[三] 2 数据分析工具:Pandas -- Group By: split-apply-combine

Group By
Group By功能:

  1. 根据某些条件将数据拆分成组
  2. 对每个组独立应用函数
  3. 将结果合并到一个数据结构中

一、分组 groupby()

df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)

  • by:可按单个或多个([])列分组
  • axis:默认为0,以行分组;1表示以列分组
  • level:level=0,按照索引分组;如果有多个索引,level设置为索引字符串或索引字符串数组。

直接分组得到一个groupby对象,是一个中间数据;通过分组后的计算,得到一个新的DataFrame。

df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
                   'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
                   'C': np.random.randn(8),
                   'D': np.random.randn(8)})
'''
     A      B         C         D
0  foo    one -0.740154 -0.438300
1  bar    one  1.386163 -0.271826
2  foo    two -0.558456 -1.502778
3  bar  three -0.546329 -1.928753
4  foo    two -1.145944  0.320112
5  bar    two  0.341525 -0.569331
6  foo    one -0.381080 -0.657461
7  foo  three -0.101462  1.746577
'''

df.groupby('A')
# <pandas.core.groupby.DataFrameGroupBy object at 0x000001FE6EF0F358>
# <class 'pandas.core.groupby.DataFrameGroupBy'>

a = df.groupby('A').mean()
'''
            C         D
A                      
bar  0.393786 -0.923304
foo -0.585419 -0.106370
'''
# <class 'pandas.core.frame.DataFrame'> 
# a.columns Index(['C', 'D'], dtype='object') 去除不是数字的列

b = df.groupby(['A','B']).mean()
'''
                  C         D
A   B                        
bar one    1.386163 -0.271826
    three -0.546329 -1.928753
    two    0.341525 -0.569331
foo one   -0.560617 -0.547881
    three -0.101462  1.746577
    two   -0.852200 -0.591333
'''
# <class 'pandas.core.frame.DataFrame'> 
# b.columns Index(['C', 'D'], dtype='object')

c = df.groupby(['A'])['D'].mean() # 以A分组,算D的平均值
'''
A
bar   -0.923304
foo   -0.106370
Name: D, dtype: float64
'''
# <class 'pandas.core.series.Series'>

s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3])
s.groupby(level = 0).sum()
'''
1    11
2    22
3    33
dtype: int64
'''

get_group():提取分组后的组

groups:该属性类型为dict,分组后每个组的index

list():将groupby转为元组

df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]},index=list("absc"))
'''
   X  Y
a  A  1
b  B  4
s  A  3
c  B  2
'''

df.groupby("X").get_group("A")
'''
   X  Y
a  A  1
s  A  3
'''

df.groupby("X").groups # {'B': ['b', 'c'], 'A': ['a', 's']}

list(df.groupby("X"))
'''
[('A',    X  Y
a  A  1
s  A  3), ('B',    X  Y
b  B  4
c  B  2)]
'''
list(df.groupby("X"))[0][1] # <class 'pandas.core.frame.DataFrame'>
'''
   X  Y
a  A  1
s  A  3
'''

按照值类型分组,通常按列分组。

df = pd.DataFrame({'data1': np.random.rand(2),
                   'data2': np.random.rand(2),
                   'key':['one', 'two']})
df.groupby(df.dtypes, axis = 1).groups # {dtype('O'): ['key'], dtype('float64'): ['data1', 'data2']}
for n, g in df.groupby(df.dtypes, axis = 1):
    print(n, "\n", g)
'''
float64 :
       data1     data2
0  0.495566  0.352556
1  0.837635  0.634867
object :
    key
0  one
1  two
'''

通过字典或者Series分组,通常按列分组。

df = pd.DataFrame(np.arange(16).reshape(4, 4),
                  columns = ['a', 'b', 'c', 'd'])
'''
    a   b   c   d
0   0   1   2   3
1   4   5   6   7
2   8   9  10  11
3  12  13  14  15
'''
dic = {'a': 'one', 'b': 'one', 'c': 'two', 'd': 'two', 'e': 'three'}

df.groupby(dic, axis = 1).sum()
df.groupby(pd.Series(dic), axis = 1).sum()
'''
   one  two
0    1    5
1    9   13
2   17   21
3   25   29
'''

二、遍历分组

for name, group in df.groupby("A"):
    print(name)
    print(group)
'''
bar
     A      B         C         D
1  bar    one  1.386163 -0.271826
3  bar  three -0.546329 -1.928753
5  bar    two  0.341525 -0.569331
foo
     A      B         C         D
0  foo    one -0.740154 -0.438300
2  foo    two -0.558456 -1.502778
4  foo    two -1.145944  0.320112
6  foo    one -0.381080 -0.657461
7  foo  three -0.101462  1.746577
'''

三、多函数计算 agg()

df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
                   'B': np.random.randn(8),
                   'C': np.random.randn(8)})
df.groupby(["A"]).agg(['mean', np.sum])
'''
            B                   C          
         mean       sum      mean       sum
A                                          
bar  0.224929  0.674786 -0.734798 -2.204393
foo -0.331954 -1.659772 -0.340527 -1.702633
'''
df.groupby(["A"])["B"].agg({"res1": np.mean,
                            "res2": np.sum})
'''
         res1      res2
A                      
bar  0.224929  0.674786
foo -0.331954 -1.659772
'''

分组可用函数:

方法描述
count()统计分组中非空值、非NaN的数量
size()统计分组的大小,包括空值
sum()计算分组的和
mean()计算分组的平均值
prod()计算分组的积
first()、last()、nth(n)获取分组的第一个值、最后一个值、第n个值
min()、max()计算分组的最小值、最大值
std()、var()计算分组的标准差、方差
describe()生成描述统计学
df = pd.DataFrame({"data1": np.random.rand(5),
                   "data2": np.random.rand(5)},
                  index = list("abaab"))
'''
      data1     data2
a  0.287221  0.781097
b  0.229732  0.532843
a  0.169996  0.979437
a  0.683406  0.360751
b  0.046675  0.658154
'''
df.groupby(level = 0).describe()
'''
            data1     data2
a count  3.000000  3.000000
  mean   0.380208  0.707095
  std    0.269040  0.315911
  min    0.169996  0.360751
  25%    0.228608  0.570924
  50%    0.287221  0.781097
  75%    0.485313  0.880267
  max    0.683406  0.979437
b count  2.000000  2.000000
  mean   0.138203  0.595498
  std    0.129441  0.088608
  min    0.046675  0.532843
  25%    0.092439  0.564170
  50%    0.138203  0.595498
  75%    0.183968  0.626826
  max    0.229732  0.658154
'''

四、转换 transform()

分组后转换为与原DataFrame结构相同的DataFrame。

df = pd.DataFrame({'key': list('aabba'),
                   'data1': np.random.rand(5),
                   'data2': np.random.rand(5)})
'''
      data1     data2 key
0  0.322917  0.127519   a
1  0.169597  0.394329   a
2  0.549236  0.802236   b
3  0.015143  0.568670   b
4  0.411133  0.328612   a
'''
df.groupby(["key"]).mean()
'''
        data1     data2
key                    
a    0.301216  0.283487
b    0.282190  0.685453
'''
df.groupby(["key"]).transform(np.mean)
'''
      data1     data2
0  0.301216  0.283487
1  0.301216  0.283487
2  0.282190  0.685453
3  0.282190  0.685453
4  0.301216  0.283487
'''
pd.merge(df,df.groupby(["key"]).mean(),left_on="key",right_index=True)
'''
    data1_x   data2_x key   data1_y   data2_y
0  0.322917  0.127519   a  0.301216  0.283487
1  0.169597  0.394329   a  0.301216  0.283487
4  0.411133  0.328612   a  0.301216  0.283487
2  0.549236  0.802236   b  0.282190  0.685453
3  0.015143  0.568670   b  0.282190  0.685453
'''

五、分组后应用自定义函数 apply()

apply(自定义函数名, 参数2, 参数3, …)

  • 自定义函数(apply前面的分组???, 参数2, 参数3, …)
  • apply前面的分组:双索引或多索引的DataFrame类型,最外层索引是分组名???
df = pd.DataFrame({'key': list('aabba'),
                   'data1': np.random.rand(5),
                   'data2': np.random.rand(5)})
'''
      data1     data2 key
0  0.408519  0.153052   a
1  0.101206  0.478075   a
2  0.158971  0.394022   b
3  0.059524  0.625927   b
4  0.838733  0.963524   a
'''

df.groupby("key").apply(lambda x: x.mean())
'''
        data1     data2
key                    
a    0.449486  0.531550
b    0.109248  0.509974
'''

def f1(group, col): # 返回按照col列排序后的分组
    return group.sort_values(col)

df.groupby("key").apply(f1, "data1")
'''
          data1     data2 key
key                          
a   1  0.101206  0.478075   a
    0  0.408519  0.153052   a
    4  0.838733  0.963524   a
b   3  0.059524  0.625927   b
    2  0.158971  0.394022   b
'''

def f2(group, col): # 选取col列前两行的数据
    return group[col][:2]

df.groupby("key").apply(f2, "data1")
'''
key   
a    0    0.408519
     1    0.101206
b    2    0.158971
     3    0.059524
Name: data1, dtype: float64
'''

六、透视表 pivot_table()

pd.pivot_table(data, values=None, index=None, columns=None, aggfunc=‘mean’,
fill_value=None, margins=False, dropna=True, margins_name=‘All’)

  • data:DataFrame对象
  • values:要聚合的列或多列(列表)
  • index:数据透视表的index,从原数据的列中筛选
  • columns:数据透视表的columns,从原数据的列中筛选
  • aggfunc:用于聚合的函数,默认为numpy.mean,支持numpy计算方法
df = pd.DataFrame({'date': pd.to_datetime(['2017-5-1', '2017-5-2', '2017-5-3'] * 3),
                   'key': list('abcdabcda'),
                   'val1': np.random.rand(9) * 10,
                   'val2': np.random.rand(9) * 10})
'''
        date key      val1      val2
0 2017-05-01   a  1.292234  3.649055
1 2017-05-02   b  1.836119  5.295825
2 2017-05-03   c  9.986584  7.534052
3 2017-05-01   d  9.333207  1.853681
4 2017-05-02   a  6.754704  1.831979
5 2017-05-03   b  2.824246  7.208884
6 2017-05-01   c  6.142462  8.362095
7 2017-05-02   d  4.500458  6.771704
8 2017-05-03   a  8.408800  9.921002
'''
pd.pivot_table(df, values = 'val1', index = 'date', columns = 'key', aggfunc = np.sum)
'''
key                a         b         c         d
date                                              
2017-05-01  1.292234       NaN  6.142462  9.333207
2017-05-02  6.754704  1.836119       NaN  4.500458
2017-05-03  8.408800  2.824246  9.986584       NaN
'''
pd.pivot_table(df, values = ['val1', 'val2'], index = ['date', 'key'], aggfunc = 'sum')
'''
                    val1      val2
date       key                    
2017-05-01 a    1.292234  3.649055
           c    6.142462  8.362095
           d    9.333207  1.853681
2017-05-02 a    6.754704  1.831979
           b    1.836119  5.295825
           d    4.500458  6.771704
2017-05-03 a    8.408800  9.921002
           b    2.824246  7.208884
           c    9.986584  7.534052
'''

七、交叉表 crosstab()

默认情况下,crosstab()计算因子的频率表,比如用于str的数据透视分析。

pd.crosstab(index, columns, rownames=None, colnames=None,
values=None, aggfunc=None, margins=False, dropna=True, normalize=False)

  • index:行中用于分组的值,可以为Series类型
  • columns: 列中用于分组的值

如果没有values和aggfunc,将计算频率表

  • values:根据因子聚合的值数组,可选
  • aggfunc:聚合函数,可选
  • margins:是否添加行/列边距(小计),默认为False
  • normalize:将所有值除以值的总和进行归一化,默认为False,为True时候显示百分比

如果crosstab只接收两个Series(数组),它将提供一个频率表。用index的唯一值,统计columns唯一值的出现次数。

df = pd.DataFrame({'A': [1, 2, 2, 2, 2],
                   'B': [3, 3, 4, 4, 4],
                   'C': [1, 1, np.nan, 1, 1]})
'''
   A  B    C
0  1  3  1.0
1  2  3  1.0
2  2  4  NaN
3  2  4  1.0
4  2  4  1.0
'''

pd.crosstab(df['A'], [df['B'], df['C']])
'''
B   3   4
C 1.0 1.0
A        
1   1   0
2   1   2
'''
pd.crosstab([df['A'], df['B']], df['C'])
'''
C    1.0
A B     
1 3    1
2 3    1
  4    2
'''
pd.crosstab(df['A'], df['B'])
'''
B  3  4
A      
1  1  0
2  1  3
'''

相当于以A和B界定分组,计算出每组中第三个系列C的值

pd.crosstab(df['A'], df['B'], values = df['C'], aggfunc = np.sum)
'''
B    3    4
A          
1  6.0  NaN
2  1.0  5.0
'''
pd.crosstab(df.A, df.B, margins = True)
'''
B    3  4  All
A             
1    1  0    1
2    1  3    4
All  2  3    5
'''
pd.crosstab(df.A, df.B, normalize = True)
'''
B    3    4
A          
1  0.2  0.0
2  0.2  0.6
'''
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值