Morris Tai
Aug 26, 2017 · 8 min read

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(同一個人可以在不同的時間軸上進行不同的活動)

這裏假設我們的任務是要基於上面的數據集去預測誰是最有趣的人

1. String commands

如果我們想要對字串做切割的話,string commands (which are Ufuncs)是最推薦的:

df[‘name’] = df.name.str.split(" ", expand=True)
作用之後的資料

除此之外你可以用連結來更有效的清理字串。

2. Group by and value_counts

透過groupbyvalue_counts我們可以輕鬆數出每個人做過多少次活動:

df.groupby('name')['activity'].value_counts()

這稱為multi index,它可以讓我們同時在dataframe中擁有不同的index層,在圖片中人名就是level 0而activity是level 1。

3. Unstack

我們也可以創建每個人的活動計數特徵,透過unstack方法,可以將行與列互換,unstack會把最低level的index轉換成cloumns,每個人的活動計數會變成cloumns,對於沒有從事該活動的人欄位會維持缺失值(NaN),可以對其進行缺失值填補。

df.groupby('name')['activity'].value_counts().unstack().fillna(0)

4. groupby, diff, shift, and loc + A great tip for efficiency

如果能了解一個人在活動中從事的時間,必定能對我們了解誰是最有趣的人有幫助。誰在party待最久?誰在海邊待最久?
對於時間長短最有效的推算方式就是先使用groupby歸類人名,再用diff()算出時間差:

df = df.sort_values(by=['name','timestamp'])
df['time_diff'] = df.groupby('name')['timestamp'].diff()
Calculating the time difference between person activities to get the duration of each activity

如果你有大量的數據集,你可以跳過groupby,只做資料排序,刪除每個人的第一行(不相關的)後直接用diff

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單位改成秒:

df['time_diff'] = df.time_diff.dt.total_seconds()

獲取每個row的持續時間:

df[‘row_duration’] = df.time_diff.shift(-1)

5. Cumcount and Cumsum

Cumcount可以創建一個累積計數。舉個例子,我們可以單獨把每個人的第二項活動提取出來,透過groupby(‘name’)之後applycumcount(關於cumcount可以見這裡)。因為
cumcount從0開始排序,所以如果我們想知道每個人的第二個活動,我們可以==1(第三個活動==2)

df = df.sort_values(by=['name','timestamp'])
df2 = df[df.groupby(‘name’).cumcount()==1]
df = df.sort_values(by=[‘name’,’timestamp’])
df2 = df[df.groupby(‘name’).cumcount()==2]

cumsum就只是對數字欄位的累加總和,我們可以把每個人在不同活動中所花的錢不斷累加。

df = df.sort_values(by=[‘name’,’timestamp’])

df['money_spent_so_far'] = df.groupby(‘name’)['money_spent'].cumsum()

6. groupby, max, min for measuring the duration of activities

在之前我們試過看看每個人在每一個活動中花了多少時間,但是我們忽略了有時候兩個活動其實是同一活動的連續!為了得知真正的活動進行時間,我們必須從連續活動的一開始測量到最後結束。這裡我們使用.shift.cumsum去創建新特徵值activity_change

df['activity_change'] = (df.activity!=df.activity.shift()) | (df.name!=df.name.shift())

接著我們將透過.cumsum去計算每個人的活動數

df['activity_num'] = df.groupby('name')['activity_change'].cumsum()

現在我們可以利用活動持續時間透過分組每個人和活動數(還有活動名稱,雖然並不會改變分組結果但是我們需要再結果出現活動名稱)後計算每行的活動持續時間總和。

activity_duration = df.groupby(['name','activity_num','activity'])['activity_duration'].sum()

這樣會返回一個類似timedelta type的活動時間。你可以用.dt.total_seconds得知

activity_duration = activity_duration.dt.total_seconds()

最後你可以用中位數或平均數對每個人的活動持續時間最大/最小化

activity_duration = activity_duration.reset_index().groupby('name').max()

出處:翻譯原文

)

Focus on Data, Data for Good.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade