python中数据分组计算_python3数据聚合与分组运算(二)
数据聚合
对于聚合,这里指的是任何能够从数组产生标量值的数据转换过程。之前的例子中已经用过一些,比如mean、count、min以及sum等。我们可能想知道在GroupBy对象上调用mean()时究竟发生了什么。许多常见的聚合运算(如下表所示)都有就地计算数据集统计信息的优化实现。然而,并不是只能使用这些方法。我们可以使用自己发明的聚合运算,还可以调用分组对象上已经定义好的任何方法。例如,quantile可以计算Series或DataFrame列的样本分位数:
In [1]: import pandas as pd
In [2]: from pandas import Series,DataFrame
In [3]: import numpy as np
In [4]: df=DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','t
...: wo','one'],'data1':np.random.randn(5),'data2':np.random.randn(5)})
In [5]: df
Out[5]:
key1 key2 data1 data2
0 a one 0.280118 0.195369
1 a two 1.166245 0.728360
2 b one 0.701840 1.373510
3 b two 0.485219 -1.124589
4 a one -0.555356 0.899907
In [6]: grouped=df.groupby('key1')
In [7]: grouped
Out[7]:
D8>
In [8]: grouped['data1'].quantile(0.9)
Out[8]:
key1
a 0.989020
b 0.680178
Name: data1, dtype: float64
虽然quantile并没有明确地实现于GroupBy,但它是一个Series方法,所以这里是能用的。实际上,GroupBy会高效地对Series进行切片,然后对各片调用piece,quantile(0.9),最后将这些结果组装成最终结果。
如果要使用我们自己的聚合函数,只需将其传入aggregate或agg方法即可:
In [10]: def peak_to_peak(arr):
...: return arr.max()-arr.min()
...:
In [11]: grouped.agg(peak_to_peak)
Out[11]:
data1 data2
key1
a 1.721601 0.704539
b 0.216621 2.498099
注意,有些方法(如descirbe)也是可以用在这里的,即使严格来讲,它们并非聚合运算:
In [12]: grouped.describe()
Out[12]:
data1 ... data2
count mean std ... 50% 75% max
key1 ...
a 3.0 0.297002 0.860925 ... 0.72836 0.814134 0.899907
b 2.0 0.593530 0.153174 ... 0.12446 0.748985 1.373510
[2 rows x 16 columns]
在后面关于分组级运算和转换的那一节中,我们将详细说明这到底是怎么回事。
表:经过优化的GroupBy的方法
函数名 说明
count 分组中非NA值的数量
sum 非NA值的和
mean 非NA值的平均值
median 非NA值的算术中位数
std、var 无偏(分母为n-1)标准差和方差
min、max 非NA值的最小值和最大值
prod 非NA值的积
first、last 第一个和最后一个非NA值
1.面向列的多函数应用
我们已经看到,对Series或DataFrame列的聚合运算其实就是使用aggregate(使用自定义函数)或调用诸如mean、std之类的方法。然而,我们可能希望对不同的列使用不同的聚合函数,或一次应用多个函数。其实这事也好办,我们将通过一些示例来进行说明。
In [37]: tips=DataFrame({'name':['calvin','kobe','michale','kate','mary'],'scor
...: e':np.random.randn(5),'sex':['Male','Male','Male','Female','Female'],'
...: smoker':['True','False','False','False','False'],'age':[30,36,20,24,8]
...: ,'ss_pct':['0.8','0.9','0.75','0.7','0.6']})
In [38]: grouped=tips.groupby(['sex','smoker'])
注意,对于上表中的那些描述统计,可以将函数名以字符串的形式传入:
In [39]: grouped.agg('mean')
Out[39]:
score age
sex smoker
Female False -0.039857 16
Male False -0.895152 28
True -0.264493 30
如果传入一组函数或函数名,得到的DataFrame的列就会以相应的函数命名:
In [40]: grouped.agg(['mean','std',peak_to_peak])
Out[40]:
score ... age
mean std ... std peak_to_peak
sex smoker ...
Female False -0.039857 0.547300 ... 11.313708 16
Male False -0.895152 0.271034 ... 11.313708 16
True -0.264493 NaN ... NaN 0
[3 rows x 6 columns]
我们并非一定要接受GroupBy自动给出的那些列名,特别是lambda函数,它们的名称是‘’,这样的辨识度就很低了(通过函数的name属性看看就知道了)。如果传入的是一个由(name,function)元组组成的列表,则各元组的第一个元素就会被用作DataFrame的列名(可以将这种二元元组列表看做一个有序映射):
In [41]: grouped.agg([('foo','mean'),('bar',np.std)])
Out[41]:
score age
foo bar foo bar
sex smoker
Female False -0.039857 0.547300 16 11.313708
Male False -0.895152 0.271034 28 11.313708
True -0.264493 NaN 30 NaN
对于DataFrame,我们还可以定义一组应用于全部列的函数,或不同的列应用不同的函数。假设我们想要对score和age列计算三个统计信息:
In [1]: import numpy as np
In [2]: from pandas import Series,DataFrame
In [3]: tips=DataFrame({'name':['calvin','kobe','michale','kate','mary'],'score
...: ':np.random.randn(5),'sex':['Male','Male','Male','Female','Female'],'sm
...: oker':['True','False','False','False','False'],'age':[30,36,20,24,8],'s
...: s_pct':['0.8','0.9','0.75','0.7','0.6']})
In [4]: functions=['count','mean','max']
In [5]: grouped=tips.groupby(['sex','smoker'])
In [9]: result=grouped['score','age'].agg(functions)
In [10]: result
Out[10]:
score age
count mean max count mean max
sex smoker
Female False 2 0.537534 1.274737 2 16 24
Male False 2 0.095328 1.260650 2 28 36
True 1 -1.696528 -1.696528 1 30 30
如我们所见,结果DataFrame拥有层次化的列,这相当于分别对各列进行聚合,然后用concat将结果组装到一起(列名用作keys参数)。
In [11]: result['score']
Out[11]:
count mean max
sex smoker
Female False 2 0.537534 1.274737
Male False 2 0.095328 1.260650
True 1 -1.696528 -1.696528
跟前面一样,这里也可以传入带有自定义名称的元组列表:
In [12]: ftuples=[('kb24','mean'),('mj23',np.var)]
In [14]: grouped['score','age'].agg(ftuples)
Out[14]:
score age
kb24 mj23 kb24 mj23
sex smoker
Female False 0.537534 1.086937 16 128.0
Male False 0.095328 2.715952 28 128.0
True -1.696528 NaN 30 NaN
现在,假设我们想要对不同的列应用不同的函数。具体的办法是向agg传入一个从列名映射到函数的字典:
In [15]: grouped.agg({'score':np.max,'age':'sum'})
Out[15]:
score age
sex smoker
Female False 1.274737 32
Male False 1.260650 56
True -1.696528 30
In [16]: grouped.agg({'score':['min','max','mean','std'],'age':'sum'})
Out[16]:
score age
min max mean std sum
sex smoker
Female False -0.199669 1.274737 0.537534 1.042563 32
Male False -1.069995 1.260650 0.095328 1.648015 56
True -1.696528 -1.696528 -1.696528 NaN 30
只有将多个函数应用到至少一列时,DataFrame才会拥有层次化的列。
2.以“无索引”的形式返回聚合数据
到目前为止,所有示例中的聚合数据都有由唯一的分组键组成的索引(可能还是层次化的)。由于并不总是需要如此,所以我们可以向groupby传入as_index=False以禁用该功能:
In [1]: import numpy as np
In [2]: from pandas import Series,DataFrame
In [3]: tips=DataFrame({'name':['calvin','kobe','michale','kate','mary'],'score
...: ':np.random.randn(5),'sex':['Male','Male','Male','Female','Female'],'sm
...: oker':['True','False','False','False','False'],'age':[30,36,20,24,8],'s
...: s_pct':['0.8','0.9','0.75','0.7','0.6']})
In [4]: tips.groupby(['sex','smoker'],as_index=False).mean()
Out[4]:
sex smoker score age
0 Female False 0.334399 16
1 Male False 0.101183 28
2 Male True -0.092134 30
分组级运算和转换
聚合只不过是分组运算的其中一种而已。它是数据转换的一个特例,也就是说,它接受能够将一维数组简化为标量值的函数。在本节中,我们将会学到transform和apply方法,它们能够执行更多其他的分组运算。
假设我们想要为一个DataFrame添加一个用于存放各索引分组平均值的列。一个办法是先聚合再合并:
In [5]: df=DataFrame({'key1':['a','a','b','b','a'],'key2':['one','two','one','t
...: wo','one'],'data1':np.random.randn(5),'data2':np.random.randn(5)})
In [6]: df
Out[6]:
key1 key2 data1 data2
0 a one 0.366926 -0.139338
1 a two -1.224763 -0.721633
2 b one -0.130507 -0.246849
3 b two -1.282988 -1.271910
4 a one 1.228818 -0.205897
In [7]: k1_means=df.groupby('key1').mean().add_prefix('mean_')
In [8]: k1_means
Out[8]:
mean_data1 mean_data2
key1
a 0.123660 -0.355622
b -0.706748 -0.759380
In [11]: pd.merge(df,k1_means,left_on='key1',right_index=True)
Out[11]:
key1 key2 data1 data2 mean_data1 mean_data2
0 a one 0.366926 -0.139338 0.123660 -0.355622
1 a two -1.224763 -0.721633 0.123660 -0.355622
4 a one 1.228818 -0.205897 0.123660 -0.355622
2 b one -0.130507 -0.246849 -0.706748 -0.759380
3 b two -1.282988 -1.271910 -0.706748 -0.759380
虽然这样也行,但是不太灵活。我们可以将该过程看做利用np.mean函数对两个数据列进行转换。再以本章前面用过的那个people DataFrame为例,这次我们在GroupBy上使用transform方法:
In [12]: people=DataFrame(np.random.randn(5,5),columns=['a','b','c','d','e'],in
...: dex=['Kobe','Michael','Kevin','James','Wade'])
In [13]: key=['one','two','one','two','one']
In [15]: people.groupby(key).mean()
Out[15]:
a b c d e
one -0.166599 -0.230311 1.063868 -0.296599 0.073681
two -0.809523 -0.448779 -0.207218 0.518750 -0.663468
In [16]: people.groupby(key).transform(np.mean)
Out[16]:
a b c d e
Kobe -0.166599 -0.230311 1.063868 -0.296599 0.073681
Michael -0.809523 -0.448779 -0.207218 0.518750 -0.663468
Kevin -0.166599 -0.230311 1.063868 -0.296599 0.073681
James -0.809523 -0.448779 -0.207218 0.518750 -0.663468
Wade -0.166599 -0.230311 1.063868 -0.296599 0.073681
不难看出,transform会将一个函数应用到各个分组,然后将结果放置到适当的位置上。如果各分组产生的是一个标量值,则该值就会被广播出去。现在,假设我们希望从各组中减去平均值。为此,我们先创建一个距平化函数(demeaning function),然后将其传给transform:
In [17]: def deman(arr):
...: return arr-arr.mean()
...:
In [18]: demeaned=people.groupby(key).transform(demean)
In [19]: demeaned
Out[19]:
a b c d e
Kobe 0.026677 -0.544615 -0.087396 0.894772 0.465351
Michael -0.943158 -0.171742 -0.323378 0.765667 -0.386289
Kevin -0.542661 -0.411980 0.523509 -1.393987 -0.720833
James 0.943158 0.171742 0.323378 -0.765667 0.386289
Wade 0.515983 0.956595 -0.436113 0.499215 0.255483
我们可以检查一下demeaned现在的分组平均值是否为0:
In [20]: demeaned.groupby(key).mean()
Out[20]:
a b ... d e
one 0.000000e+00 7.401487e-17 ... -3.700743e-17 -1.850372e-17
two -5.551115e-17 -2.775558e-17 ... 0.000000e+00 0.000000e+00
[2 rows x 5 columns]
在下一节中我们将会看到,分组距平化操作还可以通过apply实现。
apply:一般性的“拆分-应用-合并”
跟aggregate一样,transform也是一个有着严格条件的特殊函数:传入的函数只能产生两种结果,要么产生一个可以广播的标量值(如np.mean),要么产生一个相同大小的结果数组。最一般化的GroupBy方法是apply,本节剩余部分重点学习它,apply会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各片组合到一起。
回到之前那个tips数据集,假设我们想要分组选出最高的5个ss_pct值,首先编写一个指定列找出最大值,并把这个值所在的行选取出来的函数:
In [11]: def top(df,n=5,column='ss_pct'):
...: return df.sort_values(by=column)[-n:]
In [13]: top(tips,n=4)
Out[13]:
name score sex smoker age ss_pct
3 kate 1.818554 Female False 24 0.7
2 michale 0.063468 Male False 20 0.75
0 calvin 0.300196 Male True 30 0.8
1 kobe -0.512263 Male False 36 0.9
现在,如果对smoker分组并用该函数调用apply,就会得到:
In [14]: tips.groupby('smoker').apply(top)
Out[14]:
name score sex smoker age ss_pct
smoker
False 4 mary -0.237145 Female False 8 0.6
3 kate 1.818554 Female False 24 0.7
2 michale 0.063468 Male False 20 0.75
1 kobe -0.512263 Male False 36 0.9
True 0 calvin 0.300196 Male True 30 0.8
这里发生了什么?top函数在DataFrame的各个片段上调用,然后结果由pandas.concat组装到一起,并以分组名称进行了标记。于是,最终结果就有了一个层次化索引,其内层索引值来自原DataFrame。
如果传给apply的函数能够接受其他参数或关键字,则可以将这些内容放在函数名后面一并传入:
In [15]: tips.groupby(['smoker','age']).apply(top,n=1,column='score')
Out[15]:
name score sex smoker age ss_pct
smoker age
False 8 4 mary -0.237145 Female False 8 0.6
20 2 michale 0.063468 Male False 20 0.75
24 3 kate 1.818554 Female False 24 0.7
36 1 kobe -0.512263 Male False 36 0.9
True 30 0 calvin 0.300196 Male True 30 0.8
我们之前在GroupBy对象上调用过describe:
In [21]: result=tips.groupby('smoker')['score'].describe()
In [22]: result
Out[22]:
count mean std ... 50% 75% max
smoker ...
False 4.0 0.283153 1.050256 ... -0.086839 0.502239 1.818554
True 1.0 0.300196 NaN ... 0.300196 0.300196 0.300196
[2 rows x 8 columns]
In [23]: result.unstack('smoker')
Out[23]:
smoker
count False 4.000000
True 1.000000
mean False 0.283153
True 0.300196
std False 1.050256
True NaN
min False -0.512263
True 0.300196
25% False -0.305925
True 0.300196
50% False -0.086839
True 0.300196
75% False 0.502239
True 0.300196
max False 1.818554
True 0.300196
dtype: float64
在GroupBy中,当我们调用诸如describe之类的方法时,实际上只是应用了下面两条代码的快捷方式而已:
f=lambda x:x.describe()
grouped.apply(f)
禁止分组键
从上面的例子中可以看到,分组键会跟原始对象的索引共同构成结果对象中的层次化索引。将group_keys=False传入groupby即可禁止该效果:
In [24]: tips.groupby('smoker',group_keys=False).apply(top)
Out[24]:
name score sex smoker age ss_pct
4 mary -0.237145 Female False 8 0.6
3 kate 1.818554 Female False 24 0.7
2 michale 0.063468 Male False 20 0.75
1 kobe -0.512263 Male False 36 0.9
0 calvin 0.300196 Male True 30 0.8
分位数和桶分析
pandas有一些能根据指定面元或样本分位数将数据拆分成多块的工具(比如cut和qcut)。将这些函数跟groupby结合起来,就能非常轻松地实现对数据集的桶(bucket)或分位数(quantile)分析了。以下面这个简单的随机数据集为例,我们利用cut将其装入长度相等的桶中:
In [26]: frame=DataFrame({'data1':np.random.randn(1000),'data2':np.random.randn
...: (1000)})
In [27]: factor=pd.cut(frame.data1,4)
In [29]: factor[:10]
Out[29]:
0 (-1.661, -0.0197]
1 (-1.661, -0.0197]
2 (-1.661, -0.0197]
3 (-0.0197, 1.622]
4 (-1.661, -0.0197]
5 (-3.309, -1.661]
6 (-1.661, -0.0197]
7 (-1.661, -0.0197]
8 (-0.0197, 1.622]
9 (-1.661, -0.0197]
Name: data1, dtype: category
Categories (4, interval[float64]): [(-3.309, -1.661] < (-1.661, -0.0197] < (-0.0
197, 1.622] <
(1.622, 3.263]]
由cut返回的Factor对象可直接用于groupby。因此,我们可以像下面这样对data2做一些统计计算:
In [30]: def get_stats(group):
...: return {'min':group.min(),'max':group.max(),'count':group.count(),
...: 'mean':group.mean()}
...:
In [31]: grouped=frame.data2.groupby(factor)
In [32]: grouped.apply(get_stats).unstack()
Out[32]:
count max mean min
data1
(-3.309, -1.661] 53.0 1.734561 0.103850 -1.622861
(-1.661, -0.0197] 427.0 2.702454 0.006620 -3.397039
(-0.0197, 1.622] 466.0 2.990147 -0.013584 -3.488040
(1.622, 3.263] 54.0 2.063408 0.133740 -2.509789
这些都是长度相等的桶。要根据样本分位数得到大小相等的桶,使用qcut即可。传入labels=False即可只获取分位数的编号。
#返回分位数编号
In [33]: grouping=pd.qcut(frame.data1,10,labels=False)
In [34]: grouped=frame.data2.groupby(grouping)
In [35]: grouped.apply(get_stats).unstack()
Out[35]:
count max mean min
data1
0 100.0 2.429463 0.069957 -2.255656
1 100.0 2.508677 -0.019191 -2.715692
2 100.0 2.037851 -0.077528 -2.353218
3 100.0 2.702454 0.113666 -3.397039
4 100.0 2.003158 -0.065770 -3.310005
5 100.0 2.153212 0.077802 -1.762410
6 100.0 2.325933 0.092688 -2.946146
7 100.0 2.354909 -0.091635 -3.488040
8 100.0 2.116821 -0.100465 -2.460177
9 100.0 2.990147 0.092702 -2.509789
注:
qcut与cut的主要区别:
qcut:传入参数,要将数据分成多少组,即组的个数,具体的组距是由代码计算
cut:传入参数,是分组依据。
示例:用特定于分组的值填充缺失值
对于缺失数据的清理工作,有时我们会用dropna将其滤除,而有时则可能会希望用一个固定值或有数据集本身所衍生出来的值去填充NA值。这是就得使用fillna这个工具了。在下面这个例子中,我们用平均值去填充NA值:
In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: from pandas import Series,DataFrame
In [4]: s=Series(np.random.randn(6))
In [5]: s[::2]=np.nan
In [6]: s
Out[6]:
0 NaN
1 1.134955
2 NaN
3 -0.665837
4 NaN
5 -1.250660
dtype: float64
In [7]: s.fillna(s.mean())
Out[7]:
0 -0.260514
1 1.134955
2 -0.260514
3 -0.665837
4 -0.260514
5 -1.250660
dtype: float64
假设我们需要对不同的分组填充不同的值。只需将数据分组,并使用apply和一个能够对各数据块调用fillna的函数即可。下面是一些有关美国几个州的示例数据,这些州又被分为东部和西部:
In [11]: states=['Ohio','New York','Vermont','Florida','Oregon','Nevada','Calif
...: ornia','Idaho']
In [12]: group_key=['East']*4+['West']*4
In [13]: group_key
Out[13]: ['East', 'East', 'East', 'East', 'West', 'West', 'West', 'West']
In [14]: data=Series(np.random.randn(8),index=states)
In [15]: data[['Vermont','Nevada','Idaho']]=np.nan
In [16]: data
Out[16]:
Ohio 1.412328
New York 0.720072
Vermont NaN
Florida -0.691600
Oregon 1.282029
Nevada NaN
California 0.766514
Idaho NaN
dtype: float64
In [17]: data.groupby(group_key).mean()
Out[17]:
East 0.480267
West 1.024271
dtype: float64
我们可以用分组平均值去填充NA值,如下所示:
In [18]: fill_mean=lambda g:g.fillna(g.mean())
In [19]: data.groupby(group_key).apply(fill_mean)
Out[19]:
Ohio 1.412328
New York 0.720072
Vermont 0.480267
Florida -0.691600
Oregon 1.282029
Nevada 1.024271
California 0.766514
Idaho 1.024271
dtype: float64
此外,也可以在代码中预定义各组的填充值,由于分组具有一个name属性,所以我们可以拿来用一下:
In [20]: fill_values={'East':0.5,'West':-1}
In [21]: fill_func=lambda g:g.fillna(fill_values[g.name])
In [22]: data.groupby(group_key).apply(fill_func)
Out[22]:
Ohio 1.412328
New York 0.720072
Vermont 0.500000
Florida -0.691600
Oregon 1.282029
Nevada -1.000000
California 0.766514
Idaho -1.000000
dtype: float64
示例:分组加权平均数
根据groupby的“拆分-应用-合并”范式,DataFrame的列与列之间或两个Series之间的运算(比如分组加权平均)成为一种标准作业。以下面这个数据集为例,它含有分组键、值以及一些权重值:
In [25]: df=DataFrame({'category':['a','a','a','a','b','b','b','b'],'data':np.r
...: andom.randn(8),'weights':np.random.rand(8)})
In [26]: df
Out[26]:
category data weights
0 a 1.840410 0.624775
1 a -0.612739 0.207124
2 a -0.051466 0.085688
3 a 0.786270 0.383966
4 b -1.517201 0.063853
5 b 0.692989 0.751790
6 b 0.492041 0.794091
7 b -0.137448 0.719158
然后可以利用category计算分组加权平均数:
In [27]: grouped=df.groupby('category')
In [28]: get_wavg=lambda g:np.average(g['data'],weights=g['weights'])
In [29]: grouped.apply(get_wavg)
Out[29]:
category
a 1.014496
b 0.307435
dtype: float64
透视表和交叉表
透视表(pivot table)是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行聚合,并根据行和列上的分组键将数据分配到各个矩形区域中,在Python和pandas中,可以通过本章所学习的groupby功能以及(能够利用层次化索引的)重塑运算制作透视表。DataFrame有一个pivot_table方法,此外还有一个顶级的pandas.pivot_table函数。除能为groupby提供便利之外,pivot_table还可以添加分项小计(也叫做margins)。
回到小费数据集,假设我们想要根据sex和smoker计算分组平均数(pivot_table的默认聚合类型),并将sex和smoker放到行上:
In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: from pandas import Series,DataFrame
In [4]: tips=DataFrame({'name':['calvin','kobe','michale','kate','mary'],'score
...: ':np.random.randn(5),'sex':['Male','Male','Male','Female','Female'],'sm
...: oker':['True','False','False','False','False'],'age':[30,36,20,24,8],'s
...: s_pct':['0.8','0.9','0.75','0.7','0.6']})
In [6]: tips.pivot_table(index=['sex','smoker'])
Out[6]:
age score
sex smoker
Female False 16 -0.600976
Male False 28 0.318842
True 30 -1.030795
这对groupby来说也是很简单的事情。现在,假设我们只想聚合score,而且想根据name进行分组。我将smoker放到列上,把name放到行上:
In [8]: tips.pivot_table(['score'],index=['sex','name'],columns='smoker')
Out[8]:
score
smoker False True
sex name
Female kate -2.037238 NaN
mary 0.835287 NaN
Male calvin NaN -1.030795
kobe -0.360520 NaN
michale 0.998203 NaN
还可以对这个表作进一步的处理,传入margins=True添加分项小计,这将会添加标签为ALL的行和列,其值对应于单个等级中所有数据的分组统计。在下面这个例子中,ALL值为平均数:不单独考虑烟民与非烟民(ALL列),不单独考虑行分组两个级别中的任何单项(ALL行)。
In [9]: tips.pivot_table(['score'],index=['sex','name'],columns='smoker',margin
...: s=True)
Out[9]:
score
smoker False True All
sex name
Female kate -2.037238 NaN -2.037238
mary 0.835287 NaN 0.835287
Male calvin NaN -1.030795 -1.030795
kobe -0.360520 NaN -0.360520
michale 0.998203 NaN 0.998203
All -0.141067 -1.030795 -0.319013
要使用其他的聚合函数,将其传给aggfunc即可。例如,使用count或len可以得到有关分组大小的交叉表:
In [10]: tips.pivot_table(['score'],index=['sex','name'],columns='smoker',aggfu
...: nc=len,margins=True)
Out[10]:
score
smoker False True All
sex name
Female kate 1.0 NaN 1.0
mary 1.0 NaN 1.0
Male calvin NaN 1.0 1.0
kobe 1.0 NaN 1.0
michale 1.0 NaN 1.0
All 4.0 1.0 5.0
如果存在空的组合(也就是NA),我们可能会希望设置一个fill_value:
In [11]: tips.pivot_table(['score'],index=['sex','name'],columns='smoker',aggfu
...: nc=sum,fill_value=0)
Out[11]:
score
smoker False True
sex name
Female kate -2.037238 0.000000
mary 0.835287 0.000000
Male calvin 0.000000 -1.030795
kobe -0.360520 0.000000
michale 0.998203 0.000000
pivot_table的参数说明请参见下表。
pivot_table的参数
参数名 说明
values 待聚合的列的名称。默认聚合所有数值列
index 用于分组的列名或其他分组键,出现在结果透视表的行
columns 用于分组的列名或其他分组键,出现在结果透视表的列
aggfunc 聚合函数或函数列表,默认为‘mean’。可以是任何对groupby有效的函数
fill_value 用于替换结果表中的缺失值
margins 添加行/列小计和总计,默认为False
交叉表:crosstab
交叉表(cross-tabulation,简称crosstab)是一种用于计算分组频率的特殊透视表。下面这个范例数据很典型:
In [16]: data=DataFrame({'Sample':range(1,11),'Gender':['Female','Male','Female
...: ','Male','Male','Male','Female','Female','Male','Female'],'Handedness'
...: :['Right-handed','Left-handed','Right-handed','Right-handed','Left-han
...: ded','Right-handed','Right-handed','Left-handed','Right-handed','Right
...: -handed']})
In [17]: data
Out[17]:
Sample Gender Handedness
0 1 Female Right-handed
1 2 Male Left-handed
2 3 Female Right-handed
3 4 Male Right-handed
4 5 Male Left-handed
5 6 Male Right-handed
6 7 Female Right-handed
7 8 Female Left-handed
8 9 Male Right-handed
9 10 Female Right-handed
假设我们想要根据性别和用手习惯对这段数据进行统计汇总。虽然可以用pivot_table实现该功能,但是pandas.crosstab函数会更方便:
In [18]: pd.crosstab(data.Gender,data.Handedness,margins=True)
Out[18]:
Handedness Left-handed Right-handed All
Gender
Female 1 4 5
Male 2 3 5
All 3 7 10
crosstab的前两个参数可以是数组、Series或数组列表。再比如对小费数据集:
In [19]: pd.crosstab([tips.name,tips.sex],tips.smoker,margins=True)
Out[19]:
smoker False True All
name sex
calvin Male 0 1 1
kate Female 1 0 1
kobe Male 1 0 1
mary Female 1 0 1
michale Male 1 0 1
All 4 1 5
python中数据分组计算_python3数据聚合与分组运算(二)相关推荐
- python数据科学包第三天(索引、分组计算、数据聚合、分组运算和转换、载入数据、日期范围、数据可视化)
索引 行索引 列索引 索引的分类 重复索引的处理 s = pd.Series(np.random.rand(5), index=list('abcde')) s a 0.566924 b 0.6034 ...
- 在python中使用json格式存储数据
在python中使用json格式存储数据 代码如下: import jsonlist1 = [{'A': [1, 2, 3, 4, 5, 6], 'B': [3, 4, 5, 6, 7]},{'C': ...
- python应用中调用spark_在python中使用pyspark读写Hive数据操作
1.读Hive表数据 pyspark读取hive数据非常简单,因为它有专门的接口来读取,完全不需要像hbase那样,需要做很多配置,pyspark提供的操作hive的接口,使得程序可以直接使用SQL语 ...
- Python中通过索引名称提取数据loc()函数Python中通过行和列下标提取数据iloc()函数
[小白从小学Python.C.Java] [Python全国计算机等级考试] [Python数据分析考试必会题] ● 标题与摘要 Python中通过索引名称提取数据 loc()函数 Python中通过 ...
- python读取网络端口数据_在Python中从SNMP端口获取数据
我专门尝试使用PySNMP库从python中的SNMP端口读取数据.我有兴趣仅通过此库获取数据.这是因为我正在从NetSNMP迁移到PySNMP. 这是我为NetSNMP编写的工作代码,它实际上为我提 ...
- Python中的乘方计算
[小白从小学Python.C.Java] [Python-计算机等级考试二级] [Python-数据分析] Python中的乘方计算 power()函数 选择题 以下python代码输出什么? imp ...
- R语言根据日历周期处理时间序列数据:计算时间序列数据的日对数逐次差分值、使用apply.monthly函数逐月计算日对数逐次差分值的标准差、根据调整的天数来计算年化波动率
R语言根据日历周期处理时间序列数据:计算时间序列数据的日对数逐次差分值.使用apply.monthly函数逐月计算日对数逐次差分值的标准差.根据调整的天数来计算年化波动率 目录
- python中的复数计算
python中的复数计算 在python中,有时需要对复数进行计算,比如-1开方运算,普通的math模块难以实现计算结果,此时可以使用cmath模块进行. 例如 import cmath cmath. ...
- python中的取余运算符是_python取余运算
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! python中对负数求余的计算方法和求幂运算注意点python中对负数求余的计算 ...
最新文章
- html5 graphics with svg css3,HTML5 GRAPHICS WITH SVG AND CSS3
- 免费云服务器无限流量,云服务器弄无限流量
- c语言绘制路面图形代码,道路纵断面绘图程序的开发.pdf
- ASP.NET MVC下的四种验证编程方式
- 我的AWS开发人员考试未通过。 现在怎么办?
- apt-get install php5-redis,Ubuntu14-04安装redis和php5-redis扩展
- linux下的C语言开发(线程等待)
- Bitmap缩放(二)
- R-CNN学习笔记3:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition(SPP-net)
- 前端实现用户自定义建表_Excel、SQL、Python分别实现行列转换
- NOIP2013 试做总结
- 「 Ansys 」仿真调试错误汇总
- 明翰英语教学系列之音标篇V0.2(持续更新)
- CMake工程从入门到进阶完整版,可以完成简单的工程创建(完结)
- 地图,GPS位置地图坐标系:WGS-84(GPS)、GCJ-02(Google地图)、BD-09(百度地图),OpenGIS
- 【C++】C++ 内存分配(new,operator new)详解
- JSON简介与解析方法(超级详细)
- python大众点评霸王餐_划重点:如何报名大众点评霸王餐?怎么做才能中奖?
- C语言下划线开头的函数
- CentOS网络配置文件中UUID参数释疑
热门文章
- 在Linux系统中安装和使用VNC
- 动态加载js如何保证顺序执行?
- java实现上传图片代码_Java图片上传实现代码
- JavaWeb项目表格页面
- mui开发app之多图压缩与上传(仿qq空间说说发表)
- 【ES6】数组方法--查找元素find()、findIndex()
- spark3.3.1通过hbase-connectors连接CDH6.3.2自带hbase
- 硬盘显示损坏打不开修复方法
- vim 打开文件 gb2312 (Linux下为cp936)
- JToken,JObject取值