ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 Pandas 进行聚合?聚合后没有DataFrame!发生了什么?如何主要聚合字符串列(到列表、元组、带分隔符的字符串)?如何汇总计数?如何创建一个由聚合值填充的新列?

我已经看到这些反复出现的问题询问熊猫聚合功能的各个方面。今天,关于聚合及其各种用例的大部分信息都分散在数十个措辞不当、无法搜索的帖子中。这里的目的是为后代整理一些更重要的观点。

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

如何旋转数据框,

熊猫连接

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

熊猫合并101

请注意,这篇文章并不是要替代 documentation about aggregation 和关于 groupby,所以也请阅读!

请尽量不要关闭规范帖子(您无法解决规范问答帖子中的 1 个问题)

P
Peter Mortensen

问题 1

如何使用 Pandas 进行聚合?

展开aggregation documentation

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

下表列出了一些常见的聚合函数:

Function    Description
mean()         Compute mean of groups
sum()         Compute sum of group values
size()         Compute group sizes
count()     Compute count of group
std()         Standard deviation of groups
var()         Compute variance of groups
sem()         Standard error of the mean of groups
describe()     Generates descriptive statistics
first()     Compute first of group values
last()         Compute last of group values
nth()         Take nth value, or a subset if n is a list
min()         Compute min of group values
max()         Compute max of group values
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 implemented functions 聚合:

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

对于应用于一列的多个函数,请使用 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

如果要传递多个函数,可以传递 tuplelist

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 展平,使用 mapjoin

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 对象的 Indextype

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

... 用 Index 获得 Series

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

如何主要聚合字符串列(到列表、元组、带分隔符的字符串)?

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

可以传递 listtupleset 来代替聚合函数来转换列:

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

如果它是数字列,请使用带有 astype 的 lambda 函数来转换为 string

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,因为 automatic exclusion of 'nuisance' columns。这意味着所有数字列都被排除在外。

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

每个组的 size 的函数 GroupBy.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 的值。

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 返回一个对象,该对象的索引与被分组的对象相同(相同大小)。

有关详细信息,请参阅 the Pandas documentation

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

@AbhishekDujari - 我尝试用一些关于聚合的相关问题来扩展文档,所以它更像是文档中的更多信息。
谢谢你。虽然我建议为项目本身做出贡献。这些很好的例子将使很多学生受益
可用聚合函数的列表......你在哪里找到的?我似乎在官方文档的任何地方都找不到它!谢谢!
@QACollective - 你可以检查 this
P
Peter Mortensen

如果您来自 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 ac 1 9 ac 2 8 ad 2 7 bd 3 6 ae 3 5

1. 与 SQL Group By 类似的行缩减聚合

1.1 如果 Pandas 版本 >=0.25

通过运行 print(pd.__version__) 检查您的 Pandas 版本。如果您的 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)

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

key1 key2 mean_of_value1 sum_of_value2 count_of_value1 ac 1.5 17 2 ad 2.0 7 1 ae 3.0 5 1 bd 3.0 6 1

与此等效的 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,则运行上述代码会给您以下错误:

类型错误:聚合()缺少 1 个必需的位置参数:'arg'

现在要对 value1value2 进行聚合,您将运行以下代码:

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)

结果表将如下所示:

key1 key2 value1_mean value1_count value2_sum ac 1.5 2 17 ad 2.0 1 7 ae 3.0 1 5 bd 3.0 1 6

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

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)

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

key1 key2 value1 value2 Total_of_value1_by_key1 ac 1 9 8 ac 2 8 8 ad 2 7 8 bd 3 6 3 ae 3 5 8

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

最后,在某些情况下,您可能想要创建一个 rank 列,它是 ROW_NUMBER() OVER (PARTITION BY key1 ORDER BY value1 DESC, value2 ASC) 的 SQL 等效

这是你如何做到的。

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

 df.head(5)

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

以下是生成的数据框的样子:

键 1 键 2 值 1 值 2 RN ac 1 9 4 ac 2 8 3 ad 2 7 2 bd 3 6 1 ae 3 5 1

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

其他聚合运算符:

mean() 计算组的平均值

sum() 计算组值的总和

size() 计算组大小

count() 计算组数

std() 组的标准差

var() 计算组的方差

sem() 组均值的标准误

describe() 生成描述性统计信息

first() 计算组值中的第一个

last() 计算最后一个组值

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

min() 计算组值的最小值

max() 计算组值的最大值


df 有一些 nan 时,这是否成立?