分析數據時,我們經常需要對每一個元素(element)進行計算和轉換(Transform)。
比方說,我們想將一群學生身高的列(column)的單位從釐米轉成米時,便需要把每個元素除以 100。
我們如何妙用 pandas 內置的功能完成這個任務?
在 Series 的 map 功能
我們首先介紹在 pandas Series (即一個列 Column)的方法。
map 功能是一個可以幫我們把一個行動(operation)按元素地使用。比方說,將身高從米轉成釐米時,map 把「乘以 10」這個行動向每一個元素使用。
Series 上的 map 主要有以下 3 個用途:
- 使用 map 進行簡單算法運算(arithmetic operation)或條件運算(conditional operation)
- 使用 map 映射數據
- 使用 map 將一個 Python 功能使用在每一個元素
第 1 個用途:簡單算法或條件運算
import pandas as pd
height = pd.Series([1.67, 1.78, 1.45, 1.20])
print(height.map(lambda x: x * 100))
print(height.map(lambda x: x > 1.5))
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
這是一個最簡單的用法。如上圖,運用我們的身高米轉釐米例子,我們使用 .map(lambda x: x * 100)
便可以對每一個元素乘以 100。
除此之外,我們也可以進行條件的運算,例如上圖使用 .map(lambda x: x > 1.5)
檢查身高是否高於 1.5 米。
我們在另一篇提及過,您可以想像 lambda x
是一個把列(column)轉成每個元素(element)的語法,讓您可以直接對每一個元素演算。
當然,如果您有學習過其他編程語言,可能會知道所謂函式多載化(function overloading)。許多我們使用的算法(例如 + – * /)和條件(例如 == != > <)等都可以直接用於 pandas Series 上。
以下我們可以見到除了使用 map
之外,直接使用原來的運算(operator)反而更快。
import pandas as pd
height = pd.Series([1.67, 1.78, 1.45, 1.20])
print(height * 100)
print(height > 1.5)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
第 2 個用途:映射數據
這個用途比較貼近 map 這個字原來的意思。
譬如我們有一個我們去過的國家名稱列表(例如 ['Canada', 'Canada', 'Japan', 'Japan', 'Japan', 'Taiwan', 'Taiwan', 'United Kingdom']
),而我們希望數算有多少個國家在亞洲、美洲等,如何達至這個目的?
map 除了可以用 lambda
的型態處理每一個元素以外,我們亦可以輸入一個字典(dictionary)讓 pandas 知道每一個獨特(unique)的元素應該輸出甚麼結果(例如 Canada -> Americas,Taiwan -> Asia 等)。
import pandas as pd
countries_visited = pd.Series(['Canada', 'Canada', 'Japan', 'Japan', 'Japan', 'Taiwan', 'Taiwan', 'United Kingdom'])
countries_visited.map({'Canada': 'Americas', 'Japan': 'Asia', 'Taiwan': 'Asia', 'United Kingdom': 'Europe'})
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
以上的例子裡,我們在 countries_visited.map
的函數輸入一個字典({'Canada': 'Americas', 'Japan': 'Asia', 'Taiwan': 'Asia', 'United Kingdom': 'Europe'}
),讓 pandas 知道遇到每一個國家名稱時應該輸出甚麼。
import pandas as pd
countries_visited = pd.Series(['Canada', 'Canada', 'Japan', 'Japan', 'Japan', 'Taiwan', 'Taiwan', 'United Kingdom'])
countries_visited.map({'Canada': 'Americas', 'Japan': 'Asia', 'Taiwan': 'Asia', 'United Kingdom': 'Europe'}).value_counts()
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
以上可見,由於 countries_visited.map
也是回傳一個 pandas Series,我們在 .map()
後加入 pandas 內置功能 .value_counts()
,便可以回傳我們去了每一個洲多少次。
第 3 個用途:將 Python 功能使用在每一個元素
import pandas as pd
names = pd.Series(['Chan, Siu Wan','Lam, Tai Ming','Yung, Hong Chi'])
names.map(len)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
最後一個 map 的用途時將一個 Python 的功能使用在每一個元素上。
一個簡單的例子是計算名稱有多少個字元。如果我們想知道 ‘abcd’ 這個字有多少個字元,我們可以使用 len('abcd')
輸出 4。
而上面的例子顯示我們在 names
這個 pandas Series 裡使用 .apply(len)
的話,可以數算每一個姓名的字元,得出一條有多少字元的 pandas Series。
我們也可以把自訂功能使用在每一個元素上。 沿用我們國家名稱的例子,我們也可以自訂一個 continent()
的 Python 功能達到相同效果:
import pandas as pd
countries_visited = pd.Series(['Canada', 'Canada', 'Japan', 'Japan', 'Japan', 'Taiwan', 'Taiwan', 'United Kingdom'])
def continent(country):
if country in ['Canada']: return 'Americas'
if country in ['Japan', 'Taiwan']: return 'Asia'
if country in ['United Kingdom']: return 'Europe'
countries_visited.map(continent)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
在 DataFrame 的 applymap 功能
在 pandas DataFrame 也有 applymap 這一個功能。
本質上,DataFrame 的 applymap 跟 Series 的 map 的作用一樣,但 DataFrame 的 applymap 會將您提供的字典/功能應用在每一個 DataFrame 的元素裡。
譬如我們有一個量度 2 個箱子長闊高(單位是米)的 DataFrame,有 3 個列(column):height
, width
和 depth
。如果我們想將全部的數字變成釐米,怎麼使用 applymap 達至目的?
import pandas as pd
measures = pd.DataFrame({'height': [1.3,0.6],'width': [0.8,0.9],'depth':[2.5,1.5]})
measures.applymap(lambda x: x * 100)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
如上圖,我們可以使用 .applymap(lambda x: x * 100)
把 DataFrame 每一個數字乘以 100,並換成米。
map 與 apply 的分別
延伸閱讀:如何使用 pandas 的 apply?Dataframe 加入新 Column?Python 數據整合處理!
我們在另一篇教學介紹了 pandas 的 apply 功能,而您會發現 apply 似乎跟 map/applymap 的功能十分相似。
以下我們總括了一些何時使用 map 與 apply 的情況。留意這個分類帶一些個人喜好,但希望能給您作參考。
用於 pandas Series
功能 | 用途 |
---|---|
Series.map() | map 應該配合一個字典(dictionary)去做分類,就像我們上面的 countries_visited 例子。 |
Series.apply() | apply 應該配合 Python 功能使用(如 len 或其他自訂功能),就像我們上面的 names 例子。 |
用於 pandas DataFrame
功能 | 用途 |
---|---|
DataFrame.applymap() | applymap 適用於所有列都是同一個數據類型的 DataFrame。現實中較小機會用到。 |
DataFrame.apply() | apply 適用於需要指定某些列個別處理的情況。現實中比較常用到。 閱讀:如何使用 pandas 的 apply?Dataframe 加入新 Column?Python 數據整合處理! |
總結而言,map 是一個在比較特殊/簡單的情況下使用得宜的功能,而 apply 則比較在日常處理數據的情況時用到。當然,精明的您會因時制宜,在不同情況下選用最合適的方法。
教學完整代碼
最後送給大家這篇教學的 Google Colab 完整代碼。如果您不懂得使用免安裝又好用的 Google Colab Notebook,記得閱讀這篇教學了:新手 1/3:5 分鐘免安裝學習 Python?Google Colab Notebook 幫緊您!
結語
希望您學會了 map 以後,能懂得如何更快地處理數據吧!
其他 pandas 文章: