Pandas 筆記
合併資料集 - 02 pandas.concat() 函式的更多細節
你必須要知道的是 pandas.concat() 函式會完完整整的複製所有的資料集,因此反覆呼叫 pandas.concat()函式連續串接資料集會嚴重的影響執行性能。倘若需要串接數個資料集,與其反覆呼叫 pandas.concat() 函式一個一個串接,不如將所有要串接的資料集放進一個串列(list)或字典(dict)中,只呼叫 pandas.concat() 函式一次。
在開始所有程式說明之前,我們先輸入 Pandas 套件。
import pandas as pd pd.__version__
'1.0.3'
而為了方便在範例中建立 pandas.DataFrame 物件,我們借用 'Python Data Science Handbook' 裡 make_df() 函式定義。
def make_df(columns, index): """ DataFrame creator """ data_dict = {c: [str(c) + '-' + str(i) for i in index] for c in columns} return pd.DataFrame(data_dict, index)
部分索引
在合併資料集的時候,資料集之間的索引並不完全重複,我們會使用 join 參數包含或排除串接軸之外另一軸的所有索引,但有時候,我們想樣的結果既不是聯集(join = 'outer')也不是交集(join = 'inner'),而是其中一個資料集的索引,這時候我們可以結合 pandas.DataFrame.reindex() 方法來達到目的。
df1 = make_df(['Albert', 'Betty', 'Cherry', 'David'], [0, 1, 2, 3]) df1
| Albert | Betty | Cherry | David | |
|---|---|---|---|---|
| 0 | Albert-0 | Betty-0 | Cherry-0 | David-0 |
| 1 | Albert-1 | Betty-1 | Cherry-1 | David-1 |
| 2 | Albert-2 | Betty-2 | Cherry-2 | David-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 | David-3 |
df2 = make_df(['Betty', 'Cherry', 'Fanny', 'Gill'], [2, 3, 4, 5]) df2
| Betty | Cherry | Fanny | Gill | |
|---|---|---|---|---|
| 2 | Betty-2 | Cherry-2 | Fanny-2 | Gill-2 |
| 3 | Betty-3 | Cherry-3 | Fanny-3 | Gill-3 |
| 4 | Betty-4 | Cherry-4 | Fanny-4 | Gill-4 |
| 5 | Betty-5 | Cherry-5 | Fanny-5 | Gill-5 |
df = pd.concat([df1, df2], axis = 1) df
| Albert | Betty | Cherry | David | Betty | Cherry | Fanny | Gill | |
|---|---|---|---|---|---|---|---|---|
| 0 | Albert-0 | Betty-0 | Cherry-0 | David-0 | NaN | NaN | NaN | NaN |
| 1 | Albert-1 | Betty-1 | Cherry-1 | David-1 | NaN | NaN | NaN | NaN |
| 2 | Albert-2 | Betty-2 | Cherry-2 | David-2 | Betty-2 | Cherry-2 | Fanny-2 | Gill-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 | David-3 | Betty-3 | Cherry-3 | Fanny-3 | Gill-3 |
| 4 | NaN | NaN | NaN | NaN | Betty-4 | Cherry-4 | Fanny-4 | Gill-4 |
| 5 | NaN | NaN | NaN | NaN | Betty-5 | Cherry-5 | Fanny-5 | Gill-5 |
df = pd.concat([df1, df2], axis = 1).reindex(df1.index) df
| Albert | Betty | Cherry | David | Betty | Cherry | Fanny | Gill | |
|---|---|---|---|---|---|---|---|---|
| 0 | Albert-0 | Betty-0 | Cherry-0 | David-0 | NaN | NaN | NaN | NaN |
| 1 | Albert-1 | Betty-1 | Cherry-1 | David-1 | NaN | NaN | NaN | NaN |
| 2 | Albert-2 | Betty-2 | Cherry-2 | David-2 | Betty-2 | Cherry-2 | Fanny-2 | Gill-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 | David-3 | Betty-3 | Cherry-3 | Fanny-3 | Gill-3 |
pandas.DataFrame.reindex() 方法會對 pandas.DataFrame 物件根據指定的參數重新設定新索引,不在新索引值內的資料集部分會被刪除,而新索引值在資料集之中沒有的索引則會被忽略。
在這個範例中,reindex(df1.index) 直接指定新索引值就是 df1 物件的索引值,因此在合併後的資料集中不在 df1 索引中的資料全部會被刪除。
另外一種有相同結果的寫法是,在執行串接之前先將樣被串接的資料集經 reindex(df1.index) 新索引過濾,再執行串接。
df = pd.concat([df1, df2.reindex(df1.index)], axis = 1) df
| Albert | Betty | Cherry | David | Betty | Cherry | Fanny | Gill | |
|---|---|---|---|---|---|---|---|---|
| 0 | Albert-0 | Betty-0 | Cherry-0 | David-0 | NaN | NaN | NaN | NaN |
| 1 | Albert-1 | Betty-1 | Cherry-1 | David-1 | NaN | NaN | NaN | NaN |
| 2 | Albert-2 | Betty-2 | Cherry-2 | David-2 | Betty-2 | Cherry-2 | Fanny-2 | Gill-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 | David-3 | Betty-3 | Cherry-3 | Fanny-3 | Gill-3 |
keys 參數的變化
pandas.concat() 函式的 keys 參數實際上有一些特別的用法,他不只是用來指定階層式索引最外層索引的名稱,他還可以用來取但欄位名稱。另外,我們也可以用字典(dict)的用法來替代 keys 參數。
取代欄位 columns 名稱
之前我們說過,keys 參數是在 pandas.concat() 函式建立階層式索引資料集指定最外層索引的名稱,但有一個特別的用法,在使用 pandas.concat() 函式串接 pandas.Series 物件時,keys 參數不是用來建立建立階層式最外層索引的名稱,而是用來指定欄位名稱。
s1 = pd.Series(['Albert', 'Betty', 'Cherry', 'David'], name = 's1') s1
0 Albert 1 Betty 2 Cherry 3 David Name: s1, dtype: object
s2 = pd.Series(['Ellen', 'Flix', 'Gill', 'Hedy'], name = 's2') s2
0 Ellen 1 Flix 2 Gill 3 Hedy Name: s2, dtype: object
s3 = pd.Series(['Ivy', 'Jeremy', 'Kent', 'Lara'], name = 's3') s3
0 Ivy 1 Jeremy 2 Kent 3 Lara Name: s3, dtype: object
df = pd.concat([s1, s2, s3], axis = 1) df
| s1 | s2 | s3 | |
|---|---|---|---|
| 0 | Albert | Ellen | Ivy |
| 1 | Betty | Flix | Jeremy |
| 2 | Cherry | Gill | Kent |
| 3 | David | Hedy | Lara |
df = pd.concat([s1, s2, s3], axis = 1, keys = ['group1', 'group2', 'group3']) df
| group1 | group2 | group3 | |
|---|---|---|---|
| 0 | Albert | Ellen | Ivy |
| 1 | Betty | Flix | Jeremy |
| 2 | Cherry | Gill | Kent |
| 3 | David | Hedy | Lara |
用字典替代 keys 參數
將要被串接的資料集以字典(dict)的方式傳入 pandas,concat() 函式時,這字典的 keys 會被當作 pandas.concat() 函式的 keys 參數來使用,建立階層式索引結構。
df1 = make_df(['Albert', 'Betty', 'Cherry'], [0, 1, 2, 3]) df1
| Albert | Betty | Cherry | |
|---|---|---|---|
| 0 | Albert-0 | Betty-0 | Cherry-0 |
| 1 | Albert-1 | Betty-1 | Cherry-1 |
| 2 | Albert-2 | Betty-2 | Cherry-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 |
df2 = make_df(['David', 'Ellen', 'Flix'], [0, 1, 2, 3]) df2
| David | Ellen | Flix | |
|---|---|---|---|
| 0 | David-0 | Ellen-0 | Flix-0 |
| 1 | David-1 | Ellen-1 | Flix-1 |
| 2 | David-2 | Ellen-2 | Flix-2 |
| 3 | David-3 | Ellen-3 | Flix-3 |
df3 = make_df(['Gill', 'Hedy', 'Ivy'], [0, 1, 2, 3]) df3
| Gill | Hedy | Ivy | |
|---|---|---|---|
| 0 | Gill-0 | Hedy-0 | Ivy-0 |
| 1 | Gill-1 | Hedy-1 | Ivy-1 |
| 2 | Gill-2 | Hedy-2 | Ivy-2 |
| 3 | Gill-3 | Hedy-3 | Ivy-3 |
df = pd.concat({'x': df1, 'y': df2, 'z': df3}, axis = 1) df
| x | y | z | |||||||
|---|---|---|---|---|---|---|---|---|---|
| Albert | Betty | Cherry | David | Ellen | Flix | Gill | Hedy | Ivy | |
| 0 | Albert-0 | Betty-0 | Cherry-0 | David-0 | Ellen-0 | Flix-0 | Gill-0 | Hedy-0 | Ivy-0 |
| 1 | Albert-1 | Betty-1 | Cherry-1 | David-1 | Ellen-1 | Flix-1 | Gill-1 | Hedy-1 | Ivy-1 |
| 2 | Albert-2 | Betty-2 | Cherry-2 | David-2 | Ellen-2 | Flix-2 | Gill-2 | Hedy-2 | Ivy-2 |
| 3 | Albert-3 | Betty-3 | Cherry-3 | David-3 | Ellen-3 | Flix-3 | Gill-3 | Hedy-3 | Ivy-3 |
不過,當使用字典方式傳入要被串接的資料集,字典的 keys 被當作 pandas.concat() 函式的 keys 參數建立階層式索引結構,但在 pandas.concat() 函式中仍然使用 keys 參數,這時,這 keys 參數和參數裡的順序會用來選擇那些欄位群要被串接起來,不在這 keys 參數裡的欄位群將不會被串接起來。
df = pd.concat({'x': df1, 'y': df2, 'z': df3}, axis = 1, keys = ['y', 'x']) df
| y | x | |||||
|---|---|---|---|---|---|---|
| David | Ellen | Flix | Albert | Betty | Cherry | |
| 0 | David-0 | Ellen-0 | Flix-0 | Albert-0 | Betty-0 | Cherry-0 |
| 1 | David-1 | Ellen-1 | Flix-1 | Albert-1 | Betty-1 | Cherry-1 |
| 2 | David-2 | Ellen-2 | Flix-2 | Albert-2 | Betty-2 | Cherry-2 |
| 3 | David-3 | Ellen-3 | Flix-3 | Albert-3 | Betty-3 | Cherry-3 |
參考資料:
1. pandas 官方網站(https://pandas.pydata.org/)
2. 'Python Data Science Handbook', Jake VanderPlas
老驥 於2020/5/11
