Pandas
的ufuncs
為什麼比apply command
還建議使用?
Pandas 有一個apply function
讓你可以針對所有在column的值執行任何functions。注意apply只是比python內建的loop還要快一點點而已!這就是為什麼pandas的內建ufuncs比較推薦使用在columns的預處理(preprocessing)。
ufuncs
是特殊functions(建構在numpy的library)裡面並由C來實行,這就是為何ufuncs
會如此之快。以下會介紹幾種ufuncs
的例子(.diff, .shift, .cumsum, .cumcount, .str commands (作用在字串), .dt commands (作用在日期))
。
這裡透過下面的數據集來演示pandas的ufuncs(同一個人可以在不同的時間軸上進行不同的活動)
這裏假設我們的任務是要基於上面的數據集去預測誰是最有趣的同學
2 1. String commands
如果我們想要對字串做切割的話,string commands (which are Ufuncs)是最推薦的:
1
|
df['name'] = df.name.str.split(" ", expand=True)
|
除此之外你可以用
pandas.Series.str.replace來更有效的清理字串。
3 2. Group by and value_counts
透過groupby
和value_counts
我們可以輕鬆數出每個人做過多少次活動:
1
|
df.groupby('name')['activity'].value_counts()
|
這稱為
multi index,它可以讓我們同時在dataframe中擁有不同的index層,在圖片中人名就是level 0而activity是level 1。
我們也可以創建每個人的活動計數特徵,透過unstack
方法,可以將行與列互換,unstack
會把最低level的index轉換成cloumns,每個人的活動計數會變成cloumns,對於沒有從事該活動的人欄位會維持缺失值NaN
,可以對其進行缺失值填補。
1
|
df.groupby('name')['activity'].value_counts().unstack().fillna(0)
|
5 4. groupby, diff, shift, and loc + A great tip for efficiency
如果能了解一個人在活動中從事的時間,必定能對我們了解誰是最有趣的人有幫助。誰在party待最久?誰在海邊待最久?
對於時間長短最有效的推算方式就是先使用groupby
歸類人名,再用diff()
算出時間差:
1
2
|
df = df.sort_values(by=['name','timestamp'])
df['time_diff'] = df.groupby('name')['timestamp'].diff()
|
如果你有大量的數據集,你可以跳過
groupby
,只做資料排序,刪除每個人的第一行(不相關的)後直接用
diff
。
1
2
3
|
df = df.sort_values(by=['name','timestamp'])
df['time_diff'] = df['timestamp'].diff()
df.loc[df.name != df.name.shift(), 'time_diff'] = None
|
順便一提 ⎯
.shift
可以將每一行向下移動ㄧ格,所以我們就可以用
df.name!=df.name.shift()
看看哪一行有改變。
然後
.loc
是最推薦用來在特定的indices的columns中set values的選擇!
接著我們把
time_diff
單位改成秒:
1
|
df['time_diff'] = df.time_diff.dt.total_seconds()
|
獲取每個row的持續時間:
1
|
df['row_duration'] = df.time_diff.shift(-1)
|
6 5. Cumcount and Cumsum
Cumcount
可以創建一個累積計數。舉個例子,我們可以單獨把每個人的第二項活動提取出來,透過groupby(‘name’)
之後apply cumcount
(關於cumcount可以見這裡)。因為
cumcount
從0開始排序,所以如果我們想知道每個人的第二個活動,我們可以==1(第三個活動==2)
1
2
|
df = df.sort_values(by=['name','timestamp'])
df2 = df[df.groupby('name').cumcount()==1]
|
1
2
|
df = df.sort_values(by=['name','timestamp'])
df2 = df[df.groupby('name').cumcount()==2]
|
cumsum
就只是對數字欄位的累加總和,我們可以把每個人在不同活動中所花的錢不斷累加。
1
2
|
df = df.sort_values(by=['name','timestamp'])
df['money_spent_so_far'] = df.groupby(‘name’)['money_spent'].cumsum()
|
在之前我們試過看看每個人在每一個活動中花了多少時間,但是我們忽略了有時候兩個活動其實是同一活動的連續!為了得知真正的活動進行時間,我們必須從連續活動的一開始測量到最後結束。這裡我們使用.shift
和.cumsum
去創建新特徵值activity_change
1
|
df['activity_change'] = (df.activity!=df.activity.shift()) | (df.name!=df.name.shift())
|
接著我們將透過
.cumsum
去計算每個人的活動數
1
|
df['activity_num'] = df.groupby('name')['activity_change'].cumsum()
|
現在我們可以利用活動持續時間透過分組每個人和活動數(還有活動名稱,雖然並不會改變分組結果但是我們需要再結果出現活動名稱)後計算每行的活動持續時間總和。
1
|
activity_duration = df.groupby(['name','activity_num','activity'])['activity_duration'].sum()
|
這樣會返回一個類似timedelta type的活動時間。你可以用
.dt.total_seconds
得知
1
|
activity_duration = activity_duration.dt.total_seconds()
|
最後你可以用中位數或平均數對每個人的活動持續時間最大/最小化
1
|
activity_duration = activity_duration.reset_index().groupby('name').max()
|
出處:參考原文