赞
踩
将自己定义的或其他库的函数应用于Pandas对象:
apply():逐行或逐列应用该函数
agg()和transform():聚合和转换
applymap():逐元素应用函数
groupby().apply():聚合之后应用于某个函数
apply函数是pandas里面所有函数中自由度最高的函数。该函数如下:
DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
该函数最有用的是第一个参数,这个参数是函数,相当于C/C++的函数指针。
这个函数需要自己实现,函数的传入参数根据axis来定,比如axis = 1,就会把一行数据作为Series的数据 结构传入给自己实现的函数中,我们在函数中实现对Series不同属性之间的计算,返回一个结果,则apply函数 会自动遍历每一行DataFrame的数据,最后将所有结果组合成一个Series数据结构并返回。
import numpy as np
import pandas as pd
if __name__ == '__main__':
f = lambda x : x.max() - x.min()
df = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['utah', 'ohio', 'texas', 'oregon']) #columns表述列标, index表述行标
print(df)
t1 = df.apply(f) #df.apply(function, axis=0),默认axis=0,表示将一列数据作为Series的数据结构传入给定的function中
print(t1)
t2 = df.apply(f, axis=1)
print(t2)
输出结果如下所示:
b d e utah 1.950737 0.318299 0.387724 ohio 1.584464 -0.082965 0.984757 texas 0.477283 -2.774454 -0.532181 oregon -0.851359 -0.654882 1.026698 b 2.802096 d 3.092753 e 1.558879 dtype: float64 utah 1.632438 ohio 1.667428 texas 3.251737 oregon 1.878057 dtype: float64
import numpy as np import pandas as pd def my_test(a, b): return a + b if __name__ == '__main__': df = pd.DataFrame({'a':np.random.randn(6), 'b':['foo', 'bar'] * 3, 'c':np.random.randn(6)}) print(df) df['value1'] = df.apply(lambda row: my_test(row['a'], row['c']), axis=1) print(df) df['vaule2'] = df['a'] + df['c'] print(df)
输出结果如下:
a b c 0 -1.745471 foo 0.723341 1 -0.378998 bar 0.229188 2 -1.468866 foo 0.788046 3 -1.323347 bar 0.323051 4 -1.894372 foo 2.216768 5 -0.649059 bar 0.858149 a b c value1 0 -1.745471 foo 0.723341 -1.022130 1 -0.378998 bar 0.229188 -0.149810 2 -1.468866 foo 0.788046 -0.680820 3 -1.323347 bar 0.323051 -1.000296 4 -1.894372 foo 2.216768 0.322396 5 -0.649059 bar 0.858149 0.209089 a b c value1 vaule2 0 -1.745471 foo 0.723341 -1.022130 -1.022130 1 -0.378998 bar 0.229188 -0.149810 -0.149810 2 -1.468866 foo 0.788046 -0.680820 -0.680820 3 -1.323347 bar 0.323051 -1.000296 -1.000296 4 -1.894372 foo 2.216768 0.322396 0.322396 5 -0.649059 bar 0.858149 0.209089 0.209089
注意:当数据量很大时,对于简单的逻辑处理建议方法2(个人处理几百M数据集时,方法1花时200s左右,方法2花时10s)
其中:设置axis = 1参数,可以逐行进行操作;默认axis=0,即逐列进行操作;
对于常见的描述性统计方法,可以直接使用一个字符串进行代替,例df.apply(‘mean’)等价于df.apply(np.mean);
>>> df = pd.read_excel('./input/class.xlsx) >>> df = df[['score_math','score_music']] >>> df score_math score_music 0 95 79 1 96 90 2 85 85 3 93 92 4 84 90 5 88 70 6 59 89 7 88 86 8 89 74 #对音乐课和数学课逐列求成绩平均分 >>> df.apply(np.mean) score_math 86.333333 score_music 83.888889 dtype: float64 >>> type(df.apply(np.mean)) <class 'pandas.core.series.Series'> >>> df['score_math'].apply('mean') 86.33333333333333 >>> type(df['score_math'].apply(np.mean)) <class 'pandas.core.series.Series'> #逐行求每个学生的平均分 >>> df.apply(np.mean,axis=1) 0 87.0 1 93.0 2 85.0 3 92.5 4 87.0 5 79.0 6 74.0 7 87.0 8 81.5 dtype: float64 >>> type(df.apply(np.mean,axis=1)) <class 'pandas.core.series.Series'>
apply()的返回结果与所用的函数是相关的:
#其中的x可以看作是每一类的Series对象
>>> df.apply(lambda x: x - 5)
score_math score_music
0 90 74
1 91 85
2 80 80
3 88 87
4 79 85
5 83 65
6 54 84
7 83 81
8 84 69
>>> type(df.apply(lambda x: x - 5))
<class 'pandas.core.frame.DataFrame'>
例:
1)对两门课逐列求平均分
>>> df.agg('mean')
score_math 86.333333
score_music 83.888889
dtype: float64
>>> df.apply('mean')
score_math 86.333333
score_music 83.888889
dtype: float64
2)应用多个函数,可将函数放于一个列表中;
例:对两门课分别求最高分与最低分
>>> df.agg(['max','min'])
score_math score_music
max 96 92
min 59 70
>>> df.apply([np.max,'min'])
score_math score_music
amax 96 92
min 59 70
3)使用字典可以对特定列应用特定及多个函数;
例:对数学成绩求均值和最小值,对音乐课求最大值
>>> df.agg({'score_math':['mean','min'],'score_music':'max'})
score_math score_music
max NaN 92.0
mean 86.333333 NaN
min 59.000000 NaN
特点:使用一个函数后,返回相同大小的Pandas对象
与数据聚合agg()的区别:
注意:df.transform(np.mean)将报错,转换是无法产生聚合结果的
#将成绩减去各课程的平均分,使用apply、agg、transfrom都可以实现
>>> df.transform(lambda x:x-x.mean())
>>> df.apply(lambda x:x-x.mean())
>>> df.agg(lambda x:x-x.mean())
score_math score_music
0 8.666667 -4.888889
1 9.666667 6.111111
2 -1.333333 1.111111
3 6.666667 8.111111
4 -2.333333 6.111111
5 1.666667 -13.888889
6 -27.333333 5.111111
7 1.666667 2.111111
8 2.666667 -9.888889
当应用多个函数时,将返回于原始DataFrame大小不同的DataFrame,返回结果中:
>>> df.transform([lambda x:x-x.mean(),lambda x:x/10])
score_math score_music
<lambda> <lambda> <lambda> <lambda>
0 8.666667 9.5 -4.888889 7.9
1 9.666667 9.6 6.111111 9.0
2 -1.333333 8.5 1.111111 8.5
3 6.666667 9.3 8.111111 9.2
4 -2.333333 8.4 6.111111 9.0
5 1.666667 8.8 -13.888889 7.0
6 -27.333333 5.9 5.111111 8.9
7 1.666667 8.8 2.111111 8.6
8 2.666667 8.9 -9.888889 7.4
applymap()对pandas对象逐元素应用某个函数,成为元素级函数应用;
与map()的区别:
例:对成绩保留小数后两位
>>> df.applymap(lambda x:'%.2f'%x) score_math score_music 0 95.00 79.00 1 96.00 90.00 2 85.00 85.00 3 93.00 92.00 4 84.00 90.00 5 88.00 70.00 6 59.00 89.00 7 88.00 86.00 8 89.00 74.00 >>> df['score_math'].map(lambda x:'%.2f'%x) 0 95.00 1 96.00 2 85.00 3 93.00 4 84.00 5 88.00 6 59.00 7 88.00 8 89.00 Name: score_math, dtype: object
从上述例子可以看出,applymap()操作实际上是对每列的Series对象进行了map()操作
通过以上分析我们可以看到,apply、agg、transform三种方法都可以对分组数据进行函数操作,但也各有特色,总结如下:
Dataframe在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,然后函数执行结果被合并到最终的结果对象中。
df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
import numpy as np import pandas as pd data = pd.DataFrame({'key1':list('aabba'), 'key2': ['one','two','one','two','one'], 'data1': np.random.randn(5), 'data2': np.random.randn(5)}) def f(group): group['sum'] = group.data1.sum() return group aa = data.groupby(['key1','key2']).apply(f) print(data) print('*'*30) print(aa) bb = data.groupby(['key1','key2'])['data1'].apply(lambda x:x) print('*'*30) print(bb) cc=data.groupby(['key1','key2']).indices print('*'*30) print(cc)
结果
key1 key2 data1 data2 0 a one -1.065003 0.775987 1 a two -0.106187 -0.024468 2 b one 1.079181 -0.499718 3 b two -0.224642 0.213094 4 a one 0.771805 1.877397 ****************************** key1 key2 data1 data2 sum 0 a one -1.065003 0.775987 -0.293198 1 a two -0.106187 -0.024468 -0.106187 2 b one 1.079181 -0.499718 1.079181 3 b two -0.224642 0.213094 -0.224642 4 a one 0.771805 1.877397 -0.293198 ****************************** 0 -1.065003 1 -0.106187 2 1.079181 3 -0.224642 4 0.771805 Name: data1, dtype: float64 ****************************** {('a', 'one'): array([0, 4], dtype=int64), ('a', 'two'): array([1], dtype=int64), ('b', 'one'): array([2], dtype=int64), ('b', 'two'): array([3], dtype=int64)}
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)}) print(df) print('------') print(df.groupby('A'), type(df.groupby('A'))) print('------') # 直接分组得到一个groupby对象,是一个中间数据,没有进行计算 a = df.groupby('A').mean() b = df.groupby(['A','B']).mean() c = df.groupby(['A'])['D'].mean() # 以A分组,算D的平均值 print("-----------------") print(a,type(a),'\n',a.columns) print() print(b,type(b),'\n',b.columns) print() print(c,type(c)) # 通过分组后的计算,得到一个新的dataframe # 默认axis = 0,以行来分组 # 可单个或多个([])列分组 #按A列分组求出A,B列的个数 grouped = df.groupby(["A"]) n = grouped.agg({"A": ["count", pd.Series.unique], "B": pd.Series.nunique}) print(n)
df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]}) print(df) print(df.groupby('X'), type(df.groupby('X'))) print('-----') print(list(df.groupby('X')), '→ 可迭代对象,直接生成list\n') print(list(df.groupby('X'))[0], '→ 以元祖形式显示\n') for n,g in df.groupby('X'): print(n) print(g) print('###') print('-----') # n是组名,g是分组后的Dataframe print(df.groupby(['X']).get_group('A'),'\n') print(df.groupby(['X']).get_group('B'),'\n') print('-----') # .get_group()提取分组后的组 grouped = df.groupby(['X']) print(grouped.groups) print(grouped.groups['A']) # 也可写:df.groupby('X').groups['A'] print('-----') # .groups:将分组后的groups转为dict # 可以字典索引方法来查看groups里的元素 sz = grouped.size() print(sz,type(sz)) print('-----') # .size():查看分组后的长度 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)}) print(df) print() print(df.groupby(['A','B'])) print() grouped = df.groupby(['A','B']).groups print(grouped) print() print(grouped[('foo', 'three')]) # 按照两个列进行分组
import pandas as pd import numpy as np df = pd.DataFrame({'data1':np.random.rand(2), 'data2':np.random.rand(2), 'key1':['a','b'], 'key2':['one','two']}) print(df) print(df.dtypes) print("-------------") print(df.groupby(df.dtypes, axis=1)) print('-----') print(list(df.groupby(df.dtypes, axis=1))) print() for n,p in df.groupby(df.dtypes, axis=1): print(n) print() print(p) print('##') # 按照值类型分列
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = ['a','b','c','d'])
print(df)
print('-----')
mapping = {'a':'one','b':'one','c':'two','d':'two','e':'three'}
by_column = df.groupby(mapping, axis = 1)
print(by_column.sum())
print('-----')
# mapping中,a、b列对应的为one,c、d列对应的为two,以字典来分组
s = pd.Series(mapping)
print(s,'\n')
print(s.groupby(s).count())
# s中,index中a、b对应的为one,c、d对应的为two,以Series来分组
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = ['a','b','c','d'],
index = ['abc','bcd','aa','b'])
print(df,'\n')
print(df.groupby(len).sum())
# 按照字母长度分组
s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3])
grouped = s.groupby(level=0) # 唯一索引用.groupby(level=0),将同一个index的分为一组
print(grouped)
print(grouped.first(),'→ first:非NaN的第一个值\n')
print(grouped.last(),'→ last:非NaN的最后一个值\n')
print(grouped.sum(),'→ sum:非NaN的和\n')
print(grouped.mean(),'→ mean:非NaN的平均值\n')
print(grouped.median(),'→ median:非NaN的算术中位数\n')
print(grouped.count(),'→ count:非NaN的值\n')
print(grouped.min(),'→ min、max:非NaN的最小值、最大值\n')
print(grouped.std(),'→ std,var:非NaN的标准差和方差\n')
print(grouped.prod(),'→ prod:非NaN的积\n')
print(grouped.size()) # 获取分组后每组的数量
df = pd.DataFrame({'a':[1,1,2,2],
'b':np.random.rand(4),
'c':np.random.rand(4),
'd':np.random.rand(4),})
print(df)
print(df.groupby('a').agg(['mean',np.sum]))
print(df.groupby('a')['b'].agg({'result1':np.mean,
'result2':np.sum}))
# 函数写法可以用str,或者np.方法
# 可以通过list,dict传入,当用dict时,key名为columns
参考:https://www.cnblogs.com/Cheryol/p/13451562.html
https://www.cnblogs.com/mliu222/p/12003794.html
https://blog.csdn.net/spiral1221/article/details/76152002
https://www.cnblogs.com/feifeifeisir/p/13792217.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。