將自己定義的或其他庫的函數應用於Pandas對象,有以下3種方法:
- apply():逐行或逐列應用該函數
- agg()和transform():聚合和轉換
- applymap():逐元素應用函數
一 、apply()
其中:設置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()的返回結果與所用的函數是相關的:
- 返回結果是Series對象:如上述例子應用的均值函數,就是每一行或每一列返回一個值;
- 返回大小相同的DataFrame:如下面自定的lambda函數。
#其中的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'>
二、數據聚合agg()
- 數據聚合agg()指任何能夠從數組產生標量值的過程;
- 相當於apply()的特例,可以對pandas對象進行逐行或逐列的處理;
- 能使用agg()的地方,基本上都可以使用apply()代替。
例:
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
三、數據轉換transform()
特點:使用一個函數后,返回相同大小的Pandas對象
與數據聚合agg()的區別:
- 數據聚合agg()返回的是對組內全量數據的縮減過程;
- 數據轉換transform()返回的是一個新的全量數據。
注意: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()
applymap()對pandas對象逐元素應用某個函數,成為元素級函數應用;
與map()的區別:
- applymap()是DataFrame的實例方法
- map()是Series的實例方法
例:對成績保留小數后兩位
>>> 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
三種方法都可以對分組數據進行函數操作,但也各有特色,總結如下:
apply
中自定義函數對每個分組數據單獨進行處理,再將結果合並;整個DataFrame的函數輸出可以是標量、Series或DataFrame;每個apply
語句只能傳入一個函數;agg
可以通過字典方式指定特征進行不同的函數操作,每一特征的函數輸出必須為標量;transform
不可以通過字典方式指定特征進行不同的函數操作,但函數運算單位也是DataFrame的每一特征,每一特征的函數輸出可以是標量或者Series,但標量會被廣播。