Pandas 中的聚合

2024-12-04 08:56:00
admin
原创
230
摘要:问题描述:如何使用 Pandas 进行聚合?聚合后没有 DataFrame!发生了什么?我如何才能聚合主要的字符串列(到lists,tuples,strings with separator)?我如何才能汇总计数?如何创建由聚合值填充的新列?我见过这些反复出现的问题,询问 pandas 聚合功能的各种方面。目...

问题描述:

  1. 如何使用 Pandas 进行聚合?

  2. 聚合后没有 DataFrame!发生了什么?

  3. 我如何才能聚合主要的字符串列(到lists,tuples,strings with separator)?

  4. 我如何才能汇总计数?

  5. 如何创建由聚合值填充的新列?

我见过这些反复出现的问题,询问 pandas 聚合功能的各种方面。目前,有关聚合及其各种用例的大部分信息分散在数十篇措辞不当、无法搜索的帖子中。这里的目的是整理一些更重要的要点,以供后人参考。

本问答旨在成为一系列实用用户指南的下一部分:

  • 我如何旋转数据框?

  • Pandas concat 函数中的“levels”、“keys”和“names”参数有什么用?

  • 如何对每列都有一个系列的 DataFrame 进行操作?

  • Pandas 合并 101

请注意,这篇文章并非旨在替代有关聚合和groupby 的文档,因此也请阅读该文档!


解决方案 1:

问题 1

如何使用 Pandas 进行聚合?

扩展聚合文档。

聚合函数用于减少返回对象的维度。这意味着输出 Series/DataFrame 的行数与原始行数相比更少或相同。

一些常见的聚合函数如下表所示:

功能    描述
mean() 计算组的平均值
sum() 计算组值之和
size() 计算组大小
count() 计算组的数量
std() 组的标准差
var() 计算组的方差
sem() 组平均值的标准误差
describe() 生成描述统计数据
first() 计算组内第一个值
last() 计算组内最后一个值
nth() 取第 n 个值,如果 n 是列表,则取子集
min() 计算组值的最小值
max() 计算组值的最大值
np.random.seed(123)

df = pd.DataFrame({'A' : ['foo', 'foo', 'bar', 'foo', 'bar', 'foo'],
                   'B' : ['one', 'two', 'three','two', 'two', 'one'],
                   'C' : np.random.randint(5, size=6),
                   'D' : np.random.randint(5, size=6),
                   'E' : np.random.randint(5, size=6)})
print (df)
     A      B  C  D  E
0  foo    one  2  3  0
1  foo    two  4  1  0
2  bar  three  2  1  1
3  foo    two  1  0  3
4  bar    two  3  1  4
5  foo    one  2  1  0

通过过滤列和Cython 实现的函数进行聚合:

df1 = df.groupby(['A', 'B'], as_index=False)['C'].sum()
print (df1)
     A      B  C
0  bar  three  2
1  bar    two  3
2  foo    one  4
3  foo    two  5

聚合函数用于所有未在groupby函数中指定的列,以下是A, B列:

df2 = df.groupby(['A', 'B'], as_index=False).sum()
print (df2)
     A      B  C  D  E
0  bar  three  2  1  1
1  bar    two  3  1  4
2  foo    one  4  4  0
3  foo    two  5  1  3

您还可以在函数后面的列表中仅指定一些用于聚合的列groupby

df3 = df.groupby(['A', 'B'], as_index=False)['C','D'].sum()
print (df3)
     A      B  C  D
0  bar  three  2  1
1  bar    two  3  1
2  foo    one  4  4
3  foo    two  5  1

使用函数得到相同的结果DataFrameGroupBy.agg

df1 = df.groupby(['A', 'B'], as_index=False)['C'].agg('sum')
print (df1)
     A      B  C
0  bar  three  2
1  bar    two  3
2  foo    one  4
3  foo    two  5

df2 = df.groupby(['A', 'B'], as_index=False).agg('sum')
print (df2)
     A      B  C  D  E
0  bar  three  2  1  1
1  bar    two  3  1  4
2  foo    one  4  4  0
3  foo    two  5  1  3

对于应用于一列的多个函数,请使用 s 列表tuple- 新列的名称和聚合函数:

df4 = (df.groupby(['A', 'B'])['C']
         .agg([('average','mean'),('total','sum')])
         .reset_index())
print (df4)
     A      B  average  total
0  bar  three      2.0      2
1  bar    two      3.0      3
2  foo    one      2.0      4
3  foo    two      2.5      5

如果想要传递多个函数,可以传递lists tuple

df5 = (df.groupby(['A', 'B'])
         .agg([('average','mean'),('total','sum')]))

print (df5)
                C             D             E
          average total average total average total
A   B
bar three     2.0     2     1.0     1     1.0     1
    two       3.0     3     1.0     1     4.0     4
foo one       2.0     4     2.0     4     0.0     0
    two       2.5     5     0.5     1     1.5     3

然后进入MultiIndex列:

print (df5.columns)
MultiIndex(levels=[['C', 'D', 'E'], ['average', 'total']],
           labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])

要转换为列,展平MultiIndex使用:map`join`

df5.columns = df5.columns.map('_'.join)
df5 = df5.reset_index()
print (df5)
     A      B  C_average  C_total  D_average  D_total  E_average  E_total
0  bar  three        2.0        2        1.0        1        1.0        1
1  bar    two        3.0        3        1.0        1        4.0        4
2  foo    one        2.0        4        2.0        4        0.0        0
3  foo    two        2.5        5        0.5        1        1.5        3

另一个解决方案是传递聚合函数列表,然后展平MultiIndex并对另一列名称使用str.replace

df5 = df.groupby(['A', 'B']).agg(['mean','sum'])

df5.columns = (df5.columns.map('_'.join)
                  .str.replace('sum','total')
                  .str.replace('mean','average'))
df5 = df5.reset_index()
print (df5)
     A      B  C_average  C_total  D_average  D_total  E_average  E_total
0  bar  three        2.0        2        1.0        1        1.0        1
1  bar    two        3.0        3        1.0        1        4.0        4
2  foo    one        2.0        4        2.0        4        0.0        0
3  foo    two        2.5        5        0.5        1        1.5        3

如果要使用聚合函数分别指定每一列,请执行以下操作dictionary

df6 = (df.groupby(['A', 'B'], as_index=False)
         .agg({'C':'sum','D':'mean'})
         .rename(columns={'C':'C_total', 'D':'D_average'}))
print (df6)
     A      B  C_total  D_average
0  bar  three        2        1.0
1  bar    two        3        1.0
2  foo    one        4        2.0
3  foo    two        5        0.5

您也可以传递自定义函数:

def func(x):
    return x.iat[0] + x.iat[-1]

df7 = (df.groupby(['A', 'B'], as_index=False)
         .agg({'C':'sum','D': func})
         .rename(columns={'C':'C_total', 'D':'D_sum_first_and_last'}))
print (df7)
     A      B  C_total  D_sum_first_and_last
0  bar  three        2                     2
1  bar    two        3                     2
2  foo    one        4                     4
3  foo    two        5                     1

问题 2

聚合后没有 DataFrame!发生了什么?

按两列或多列进行聚合:

df1 = df.groupby(['A', 'B'])['C'].sum()
print (df1)
A    B
bar  three    2
     two      3
foo  one      4
     two      5
Name: C, dtype: int32

首先检查Pandas 对象的Index和:type

print (df1.index)
MultiIndex(levels=[['bar', 'foo'], ['one', 'three', 'two']],
           labels=[[0, 0, 1, 1], [1, 2, 0, 2]],
           names=['A', 'B'])

print (type(df1))
<class 'pandas.core.series.Series'>

对于如何获取MultiIndex Series列,有两种解决方案:

  • 添加参数as_index=False

df1 = df.groupby(['A', 'B'], as_index=False)['C'].sum()
print (df1)
     A      B  C
0  bar  three  2
1  bar    two  3
2  foo    one  4
3  foo    two  5
  • 使用Series.reset_index

df1 = df.groupby(['A', 'B'])['C'].sum().reset_index()
print (df1)
     A      B  C
0  bar  three  2
1  bar    two  3
2  foo    one  4
3  foo    two  5

如果按一列分组:

df2 = df.groupby('A')['C'].sum()
print (df2)
A
bar    5
foo    9
Name: C, dtype: int32

...Series获得Index

print (df2.index)
Index(['bar', 'foo'], dtype='object', name='A')

print (type(df2))
<class 'pandas.core.series.Series'>

解决方案与以下相同MultiIndex Series

df2 = df.groupby('A', as_index=False)['C'].sum()
print (df2)
     A  C
0  bar  5
1  foo  9

df2 = df.groupby('A')['C'].sum().reset_index()
print (df2)
     A  C
0  bar  5
1  foo  9

问题 3

我如何才能聚合主要的字符串列(到lists,tuples,strings with separator)?

df = pd.DataFrame({'A' : ['a', 'c', 'b', 'b', 'a', 'c', 'b'],
                   'B' : ['one', 'two', 'three','two', 'two', 'one', 'three'],
                   'C' : ['three', 'one', 'two', 'two', 'three','two', 'one'],
                   'D' : [1,2,3,2,3,1,2]})
print (df)
   A      B      C  D
0  a    one  three  1
1  c    two    one  2
2  b  three    two  3
3  b    two    two  2
4  a    two  three  3
5  c    one    two  1
6  b  three    one  2

除了使用聚合函数之外,还可以传递list、来转换列tupleset

df1 = df.groupby('A')['B'].agg(list).reset_index()
print (df1)
   A                    B
0  a           [one, two]
1  b  [three, two, three]
2  c           [two, one]

另一种方法是使用GroupBy.apply

df1 = df.groupby('A')['B'].apply(list).reset_index()
print (df1)
   A                    B
0  a           [one, two]
1  b  [three, two, three]
2  c           [two, one]

要转换为带有分隔符的字符串,.join仅当它是字符串列时才使用:

df2 = df.groupby('A')['B'].agg(','.join).reset_index()
print (df2)
   A                B
0  a          one,two
1  b  three,two,three
2  c          two,one

如果它是数字列,则使用 lambda 函数astype将其转换为strings:

df3 = (df.groupby('A')['D']
         .agg(lambda x: ','.join(x.astype(str)))
         .reset_index())
print (df3)
   A      D
0  a    1,3
1  b  3,2,2
2  c    2,1

另一个解决方案是先转换为字符串groupby

df3 = (df.assign(D = df['D'].astype(str))
         .groupby('A')['D']
         .agg(','.join).reset_index())
print (df3)
   A      D
0  a    1,3
1  b  3,2,2
2  c    2,1

要转换所有列,请不要在 后传递列列表groupby。没有任何列D,因为会自动排除“干扰”列。这意味着所有数字列都被排除。

df4 = df.groupby('A').agg(','.join).reset_index()
print (df4)
   A                B            C
0  a          one,two  three,three
1  b  three,two,three  two,two,one
2  c          two,one      one,two

因此需要将所有列转换为字符串,然后获取所有列:

df5 = (df.groupby('A')
         .agg(lambda x: ','.join(x.astype(str)))
         .reset_index())
print (df5)
   A                B            C      D
0  a          one,two  three,three    1,3
1  b  three,two,three  two,two,one  3,2,2
2  c          two,one      one,two    2,1

问题 4

我如何才能汇总计数?

df = pd.DataFrame({'A' : ['a', 'c', 'b', 'b', 'a', 'c', 'b'],
                   'B' : ['one', 'two', 'three','two', 'two', 'one', 'three'],
                   'C' : ['three', np.nan, np.nan, 'two', 'three','two', 'one'],
                   'D' : [np.nan,2,3,2,3,np.nan,2]})
print (df)
   A      B      C    D
0  a    one  three  NaN
1  c    two    NaN  2.0
2  b  three    NaN  3.0
3  b    two    two  2.0
4  a    two  three  3.0
5  c    one    two  NaN
6  b  three    one  2.0

各组GroupBy.size功能:size

df1 = df.groupby('A').size().reset_index(name='COUNT')
print (df1)
   A  COUNT
0  a      2
1  b      3
2  c      2

函数GroupBy.count排除缺失值:

df2 = df.groupby('A')['C'].count().reset_index(name='COUNT')
print (df2)
   A  COUNT
0  a      2
1  b      2
2  c      1

此函数应用于计算多列非缺失值:

df3 = df.groupby('A').count().add_suffix('_COUNT').reset_index()
print (df3)
   A  B_COUNT  C_COUNT  D_COUNT
0  a        2        2        1
1  b        3        2        3
2  c        2        1        1

相关函数是Series.value_counts。它返回包含按降序排列的唯一值计数的对象的大小,因此第一个元素是最常出现的元素。它NaN默认排除 s 个值。

df4 = (df['A'].value_counts()
              .rename_axis('A')
              .reset_index(name='COUNT'))
print (df4)
   A  COUNT
0  b      3
1  a      2
2  c      2

如果想要与使用函数groupby+相同的输出size,请添加Series.sort_index

df5 = (df['A'].value_counts()
              .sort_index()
              .rename_axis('A')
              .reset_index(name='COUNT'))
print (df5)
   A  COUNT
0  a      2
1  b      3
2  c      2

问题 5

如何创建由聚合值填充的新列?

方法GroupBy.transform返回一个与被分组的对象索引相同(大小相同)的对象。

有关更多信息,请参阅Pandas 文档。

np.random.seed(123)

df = pd.DataFrame({'A' : ['foo', 'foo', 'bar', 'foo', 'bar', 'foo'],
                    'B' : ['one', 'two', 'three','two', 'two', 'one'],
                    'C' : np.random.randint(5, size=6),
                    'D' : np.random.randint(5, size=6)})
print (df)
     A      B  C  D
0  foo    one  2  3
1  foo    two  4  1
2  bar  three  2  1
3  foo    two  1  0
4  bar    two  3  1
5  foo    one  2  1


df['C1'] = df.groupby('A')['C'].transform('sum')
df['C2'] = df.groupby(['A','B'])['C'].transform('sum')


df[['C3','D3']] = df.groupby('A')['C','D'].transform('sum')
df[['C4','D4']] = df.groupby(['A','B'])['C','D'].transform('sum')

print (df)

     A      B  C  D  C1  C2  C3  D3  C4  D4
0  foo    one  2  3   9   4   9   5   4   4
1  foo    two  4  1   9   5   9   5   5   1
2  bar  three  2  1   5   2   5   2   2   1
3  foo    two  1  0   9   5   9   5   5   1
4  bar    two  3  1   5   3   5   2   3   1
5  foo    one  2  1   9   4   9   5   4   4

解决方案 2:

如果您有 R 或 SQL 背景,这里有三个示例,它们将教您以您熟悉的方式进行聚合所需的一切:

首先创建一个 Pandas 数据框

import pandas as pd

df = pd.DataFrame({'key1' : ['a','a','a','b','a'],
                   'key2' : ['c','c','d','d','e'],
                   'value1' : [1,2,2,3,3],
                   'value2' : [9,8,7,6,5]})

df.head(5)

我们创建的表格如下所示:

键1键2值1值2
一个19
一个28
一个d27
bd36
一个35
  1. 使用类似于 SQL 的行缩减进行聚合Group By


1.1 如果 Pandas 版本>=0.25

运行检查你的 Pandas 版本print(pd.__version__)。如果你的Pandas 版本是 0.25 或更高版本,则以下代码将起作用:

df_agg = df.groupby(['key1','key2']).agg(mean_of_value_1=('value1', 'mean'),
                                         sum_of_value_2=('value2', 'sum'),
                                         count_of_value1=('value1','size')
                                         ).reset_index()


df_agg.head(5)

生成的数据表将如下所示:

键1键2平均值1值之和2值计数1
一个1.5172
一个d2.071
一个3.051
bd3.061

与此等价的SQL语句是:

SELECT
      key1
     ,key2
     ,AVG(value1) AS mean_of_value_1
     ,SUM(value2) AS sum_of_value_2
     ,COUNT(*) AS count_of_value1
FROM
    df
GROUP BY
     key1
    ,key2

1.2 如果 Pandas 版本<0.25

如果您的 Pandas 版本早于 0.25,则运行上述代码将出现以下错误:

TypeError:aggregate()缺少 1 个必需的位置参数:'arg'

value1现在,为了对和进行聚合value2,您将运行以下代码:

df_agg = df.groupby(['key1','key2'],as_index=False).agg({'value1':['mean','count'],'value2':'sum'})

df_agg.columns = ['_'.join(col).strip() for col in df_agg.columns.values]

df_agg.head(5)

结果表将如下所示:

键1键2值1_平均值值1_计数值2_总和
一个1.5217
一个d2.017
一个3.015
bd3.016

需要使用以下代码单独重命名列:

df_agg.rename(columns={"value1_mean" : "mean_of_value1",
                       "value1_count" : "count_of_value1",
                       "value2_sum" : "sum_of_value2"
                       }, inplace=True)

2. 创建不减少行数的列 ( EXCEL - SUMIF, COUNTIF)

如果您想要执行 SUMIF、COUNTIF 等操作,就像在 Excel 中行数不减少的情况一样,那么您需要执行此操作。

df['Total_of_value1_by_key1'] = df.groupby('key1')['value1'].transform('sum')

df.head(5)

生成的数据框将如下所示,其行数与原始数据框相同:

键1键2值1值2按键 1 的值总计
一个198
一个288
一个d278
bd363
一个358

3.创建 RANK 列ROW_NUMBER() OVER (PARTITION BY ORDER BY)

最后,在某些情况下您可能想要创建一个与 SQL等同排名列。ROW_NUMBER() OVER (PARTITION BY key1 ORDER BY value1 DESC, value2 ASC)

以下是具体操作方法。

 df['RN'] = df.sort_values(['value1','value2'], ascending=[False,True]) \n              .groupby(['key1']) \n              .cumcount() + 1

 df.head(5)

``注意:我们通过在每行末尾添加来使代码变为多行。

最终的数据框如下所示:

键1键2值1值2RN
一个194
一个283
一个d272
bd361
一个351

在上述所有示例中,最终的数据表将具有表结构,并且不会具有您在其他语法中可能获得的数据透视结构。

其他聚合运算符:

mean() 计算组的平均值

sum() 计算组值的总和

size() 计算组大小

count() 计算组数

std() 组别标准差

var() 计算组的方差

sem() 组平均值的标准误差

describe() 生成描述性统计数据

first() 计算组内第一个值

last() 计算组最后一个值

nth() 取第 n 个值,如果 n 是列表,则取其子集

min() 计算组值的最小值

max() 计算组值的最大值

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用