分组对象的运算方法
下面以一个分组对象的方法为例,实现对指定列的数据的运算。
a = pd.DataFrame({'student':['math','chinese','english','math','english','chinese'],
'number':[89,98,78,96,65,100]})
a['teacher'] = ['java','html','python','java','python','python']
a['money'] = [10,20,30,40,50,60]
print(a.groupby('teacher')['number'].describe())
count mean std min 25% 50% 75% max
teacher
html 1.0 98.0 NaN 98.0 98.00 98.0 98.00 98.0
java 2.0 92.5 4.949747 89.0 90.75 92.5 94.25 96.0
python 3.0 81.0 17.691806 65.0 71.50 78.0 89.00 100.0
可以看出来,以上代码规定了describe()只计算a[‘number’]列的数据,可以看出来describe还是得到了很多的统计量,如果不需要这么多,或者需要的没有,比如同时显示标准差跟和,那也没有其他的方法,当然有,Pandas为此提供了一些专门的方法:aggregate(),apply(),filter(),transform(),注意他们都是分组对象的方法,都以分组对象为单位进行计算。
aggregate()
aggregate函数的作用是可以将若干个用于统计运算的函数聚合到一起:
aggregate(func, axis=0, *args, **kwargs)
print(a)
print('='*30)
print(a.groupby('teacher').aggregate(['mean','min','max']))
student number teacher money
0 math 89 java 10
1 chinese 98 html 20
2 english 78 python 30
3 math 96 java 40
4 english 65 python 50
5 chinese 100 python 60
==============================
number money
mean min max mean min max
teacher
html 98.0 98 98 20.000000 20 20
java 92.5 89 96 25.000000 10 40
python 81.0 65 100 46.666667 30 60
以上函数,将平均数,最小值,最大值三个计算函数聚合在一起,让他们分别对三个分组对象中的数据进行相应的计算。是‘number’列的最大值分别是html,java,python这三个分组中各自的最大值,不是所有数据的最大值,如果aggregate的参数是一个函数对象跟多个函数组成的列表有什么区别如下:
print(a.groupby('teacher').aggregate(np.mean))
print(a.groupby('teacher').mean())
number money
teacher
html 98.0 20.000000
java 92.5 25.000000
python 81.0 46.666667
number money
teacher
html 98.0 20.000000
java 92.5 25.000000
python 81.0 46.666667
当然如果是一个函数对象的话,用后面那个方法更简单,这里只是提一下,aggregate()也可以缩写成agg(),这个方法还可以对不同的列进行不同的运算,就是使用字典形式建立列标签和函数对象:
print(a.groupby('teacher').aggregate({'number':np.mean,'money':np.mean}))
print(a.groupby('teacher').aggregate({'number':['mean','min','max']}))
number money
teacher
html 98.0 20.000000
java 92.5 25.000000
python 81.0 46.666667
number
mean min max
teacher
html 98.0 98 98
java 92.5 89 96
python 81.0 65 100
自行领会,轴的方向也是可以改变的默认axis=0
filter()
filter()有筛选的意思,具体怎么筛选,筛选谁可以查看帮助文档:
filter(items=None, like=None, regex=None, axis=None)
下面我们就来写个filter方法:
a = pd.DataFrame({'student':['math','chinese','english','math','english','chinese'],
'number':[89,98,78,96,65,100]})
a['teacher'] = ['java','html','python','java','python','python']
a['money'] = [10,20,30,40,50,60]
print(a)
print(a.groupby('teacher').mean())
def high_money(x):
return x['money'].mean() > 30
print(a.groupby('teacher').filter(high_money))
student number teacher money
0 math 89 java 10
1 chinese 98 html 20
2 english 78 python 30
3 math 96 java 40
4 english 65 python 50
5 chinese 100 python 60
number money
teacher
html 98.0 20.000000
java 92.5 25.000000
python 81.0 46.666667
student number teacher money
2 english 78 python 30
4 english 65 python 50
5 chinese 100 python 60
可以看出def high_money()这个函数返回值是布尔值,计算money列里面数据的平均值判断是否大于30,大于的就返回True,否则就False,filter()以True为依据将teacher列内符合的数据以DataFrame的方式返回,False的则不返回,最后将返回的分组数据组合输出,filter()所筛选的对象是以分组对象为单位的,如果符合条件,则分组数据全部返回,而不是逐条筛选。
transform()
aggregate()指定针对分组对象运算的函数,得到的结果为分组对象各自运算结果的集合,此结果与原数据相比,不论是数据量还是行列标签索引都发生的变换;filter()根据分组对象设置的条件对本分组对象中的数据进行筛选,最终将得到的数据合并返回,这个返回结果一般比原数据少。相比而言,transfrom()的作用仅仅是改变了原数据的值,返回值的长度与原数据相同,这里返回值相对原数据不是原地修改,而是生成了一个新的对象。
transform(func, axis=0, *args, **kwargs)
print(a.groupby('teacher').transform(lambda x:x-x.mean()))
number money
0 -3.5 -15.000000
1 0.0 0.000000
2 -3.0 -16.666667
3 3.5 15.000000
4 -16.0 3.333333
5 19.0 13.333333
这个我们可以好好看看之前那个filter的案例,仔细做对比,可以观察到传给transform()函数对象的lambda x:x-x.mean()是对每个分组进行计算的,上面那个列子中,以math,分组为例,这个分组中“number”列的平均值为92.5,然后这种数值有两个,分别是89和96,这两个数分别减去92.5,就得到为我们上面的数据。
apply()
apply()相比前面的更加灵活,
apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)
def money_mean(x):
x['money_mean'] = x['number'] * x['money'].mean()
return x
print(a.groupby('teacher')['money'].mean())
print(a.groupby('teacher').apply(money_mean))
teacher
html 20.000000
java 25.000000
python 46.666667
Name: money, dtype: float64
student number teacher money money_mean
0 math 89 java 10 2225.000000
1 chinese 98 html 20 1960.000000
2 english 78 python 30 3640.000000
3 math 96 java 40 2400.000000
4 english 65 python 50 3033.333333
5 chinese 100 python 60 4666.666667
上面操作,目的在于增加一列,这列按照money_mean()函数进行计算,例如将java的两个money元素相加乘以它相对应的number,有两个java分别是89和96,与他们相乘得到的结果写入money_mean列里面。
最后,在所有对数值进行的计算中,数据为字符串的列自动不参与计算,比如student列或者teacher列,尽管我们没有声明,这就是Pandas的智能之处。