Pandas 筆記
合併資料集 - 03 append() 物件方法
在討論完 pandas.concat() 函式之後,有一個 pandas.Series 物件和 pandas.DataFrame 物件的方法可以達到和 pandas.concat() 函式類似的功能,那就是 pandas.Series.append() 方法和 pandas.DataFrame.append()方法。這兩個 append() 方法可以看做是 pandas.concat() 函式的簡化版,只是這 append() 方法合併資料集的方向永遠是對「列」合併。
但要注意的是 pandas.Series.append() 方法和 pandas.DataFrame.append() 方法並不會添加資料集到原來的 pandas.Series 物件或 pandas.DataFrame 物件,而是另外建立新 pandas.Series 和 pandas.DataFrame 物件。
Pandas 的做法與 Python 可變序列(mutable sequence)中的串列(list)物件型態的 append() 方法不同,Python 裡的 s.append() 方法是直接將新項目添加到原來串列 s 的尾端,也就是說,原來的串列 s 被改變了。
在開始介紹 pandas.Series.append() 方法和 pandas.DataFrame.append() 方法前,我們先載入 pandas 套件。
import pandas as pd pd.__version__
'1.0.3'
pandas.Series.append() 方法
pandas.Series.append() 方法的功能是合併兩個或多個 pandas.Series 物件,它回覆的是一個合併後的 pandas.Series 物件。由於 pandas.Series.append() 方法只能「逐列」合併,因此合併後的結果無法像 pandas.concat() 函式可以選擇逐欄合併後形成 pandas.DataFrame 物件。 首先,我們先來看看 pandas.Series.append() 方法有哪些參數。
Series.append(self, to_append, ignore_index = False, verify_integrity = False)
to_append 參數
to_append 參數可以是一個 pandas.Series 物件或是由 pandas.Series 所形成的一個串列或是元祖(tuple)。
ser1 = pd.Series(['Albert', 'Bell', 'Cherry'], index = [1, 2, 3]) ser1
1 Albert 2 Bell 3 Cherry dtype: object
ser2 = pd.Series(['David', 'Ellen', 'Flora'], index = [4, 5, 6]) ser2
4 David 5 Ellen 6 Flora dtype: object
ser3 = pd.Series(['Glen', 'Hedy', 'Ian'], index = [5, 6, 7]) ser3
5 Glen 6 Hedy 7 Ian dtype: object
ser1.append(ser2)
1 Albert 2 Bell 3 Cherry 4 David 5 Ellen 6 Flora dtype: object
ser1
1 Albert 2 Bell 3 Cherry dtype: object
我們可以看到,在合併之後 ser1 仍然保持不變,也就是 ser2 並沒有添加到 ser1 之後,而是另建 pandas.Series 物件。
ser1.append([ser2, ser3])
1 Albert 2 Bell 3 Cherry 4 David 5 Ellen 6 Flora 5 Glen 6 Hedy 7 Ian dtype: object
在這個例子中,一次合併兩個資料集(ser2 和 ser3)到 ser1 資料集中,而 ser2 與 ser3 資料集以串列的方式先組合在一起。
另外,可以在這個例子中發現重複的索引,ser2 和 ser3 資料集都有索引 5 和 6,因此,合併後的資料集 pandas.Series 物件索引 5 和 6 個出現了兩次,這是因為 pandas.Series.append() 方法在預設上是會保留原先 pandas.Series 物件的索引。
to_append 參數以元祖(tuple)的方式列出要被合併的資料集和以串列(list)的方式列出要被合併的資料集,結果是一樣的。
ser1.append((ser2, ser3))
1 Albert 2 Bell 3 Cherry 4 David 5 Ellen 6 Flora 5 Glen 6 Hedy 7 Ian dtype: object
verify_integrity 參數
verify_integrity 參數是一個布林值,預設是 False。
verify_integrity 參數決定是否檢查合併後的新索引(index)有無重複的索引值。當 verify_integrity = False 時,pandas.Series.append() 方法允許合併後的 pandas.Series 物件可以有重複的索引值。而當 verify_integrity = True 時,pandas.Series.append() 方法發現合併後的 pandas.Series 物件有重複的索引值時,會發出 ValueError 告警。
在實際應用時,資料集來源可能來自不同地方,因此索引值是有重複的可能。
try: ser1.append([ser2, ser3], verify_integrity = True) except ValueError as err: print(f"Exception: {err}")
Exception: Indexes have overlapping values: Int64Index([5, 6], dtype='int64')
ignore_index 參數
ignore_index 參數是一個布林值,預設是 False。當設定為 True 時,合併後資料集將不使用合併前資料集的索引(index),取而代之的是數字 0、1、2、...。
在某些資料集的應用中,資料集原先的索引並不重要,資料集之間的索引是否有重複也不在意,這時候可以使用 ignore_index 參數,忽略原先的索引值,合併後的新資料集會重新指定索引值。
ser1.append((ser2, ser3), ignore_index = True)
0 Albert 1 Bell 2 Cherry 3 David 4 Ellen 5 Flora 6 Glen 7 Hedy 8 Ian dtype: object
pandas.DataFrame.append() 方法
pandas.DataFrame.append() 方法的功能是逐列合併兩個或以上的 pandas.DataFrame 物件或 pandas.Series 物件形成一個新的 pandas.DataFrame 物件。
在說明 pandas.DataFrame.append() 方法前,我們先看看它有哪些參數。
DataFrame.append(self, other, ignore_index = False, verify_integrity = False, sort = False)
這裡,我們依舊借用 'Python Data Science Handbook' 裡 make_df() 函式定義,方便建立不同的 pandas.DataFrame 物件。
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)
other 參數
other 參數是一個 pandas.DataFrame 物件、pandas.Series 物件、字典型態的物件、或是這些物件所形成的串列。
df1 = make_df(['Albert', 'Bell', 'Cherry'], [1, 2, 3]) df1
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
df2 = make_df(['Albert', 'Bell', 'Cherry'], [4, 5, 6]) df2
| Albert | Bell | Cherry | |
|---|---|---|---|
| 4 | Albert-4 | Bell-4 | Cherry-4 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
df3 = make_df(['Albert', 'Bell', 'Cherry'], [5, 6, 7]) df3
| Albert | Bell | Cherry | |
|---|---|---|---|
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
| 7 | Albert-7 | Bell-7 | Cherry-7 |
df1.append(df2)
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
| 4 | Albert-4 | Bell-4 | Cherry-4 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
df1
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
從這個例子我們發現 df1 資料集在合併前後並沒有不同,也就是說 df2 並沒有添加到 df1 之後,而是另外建立新的 pandas.DataFrame 物件。
df1.append([df2, df3])
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
| 4 | Albert-4 | Bell-4 | Cherry-4 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
| 7 | Albert-7 | Bell-7 | Cherry-7 |
df1.append((df2, df3))
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
| 4 | Albert-4 | Bell-4 | Cherry-4 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
| 5 | Albert-5 | Bell-5 | Cherry-5 |
| 6 | Albert-6 | Bell-6 | Cherry-6 |
| 7 | Albert-7 | Bell-7 | Cherry-7 |
pandas.DataFrame.append() 方法可以一次合併兩個以上的 pandas.DataFrame 物件到原 pandas.DataFrame 物件後,這時添加的 pandas.DataFrame 物件以串列(list)或元祖(tuple)方式組成 other 參數。
當 other 參數是 pandas.Series 物件時,要特別注意它必須有名稱、或是 ignore_index = True 才能夠合併,否則會出現 TypeError 的錯誤訊息。
ser1 = pd.Series(['Albert', 'Bell', 'Cherry'], index = [1, 2, 3]) ser1
1 Albert 2 Bell 3 Cherry dtype: object
try: df1.append(ser1) except TypeError as err: print(f"Exception: {err}")
Exception: Can only append a Series if ignore_index=True or if the Series has a name
ser1 = pd.Series(['Albert', 'Bell', 'Cherry'], index = [1, 2, 3], name = 'ser1') ser1
1 Albert 2 Bell 3 Cherry Name: ser1, dtype: object
df1.append(ser1)
| Albert | Bell | Cherry | 1 | 2 | 3 | |
|---|---|---|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 | NaN | NaN | NaN |
| 2 | Albert-2 | Bell-2 | Cherry-2 | NaN | NaN | NaN |
| 3 | Albert-3 | Bell-3 | Cherry-3 | NaN | NaN | NaN |
| ser1 | NaN | NaN | NaN | Albert | Bell | Cherry |
這個範例和 pandas.concat() 函式設定 join 參數為 'outer' 的結果一樣。對於 ser1 物件,它的索引值 1、2、3 會成為合併後 pandas.DataFrame 物件的新欄名稱(columns),而 ser1 的名稱(name)會成為合併後 pandas.DataFrame 物件的新索引值(index)。
ser1 = pd.Series(['Albert', 'Bell', 'Cherry'], index = [1, 2, 3]) ser1
1 Albert 2 Bell 3 Cherry dtype: object
df1.append(ser1, ignore_index = True)
| Albert | Bell | Cherry | 1 | 2 | 3 | |
|---|---|---|---|---|---|---|
| 0 | Albert-1 | Bell-1 | Cherry-1 | NaN | NaN | NaN |
| 1 | Albert-2 | Bell-2 | Cherry-2 | NaN | NaN | NaN |
| 2 | Albert-3 | Bell-3 | Cherry-3 | NaN | NaN | NaN |
| 3 | NaN | NaN | NaN | Albert | Bell | Cherry |
當 ser1 沒有設定名稱(name)時,合併時設定 ignore_index 參數為 True,同樣能達到相同的效果。
當 other 參數是字典型態(dict-like)時,這字典型態在使用上卻有點類似 pandas.Series 物件,以一個字典一列的方式添加。
dict4 = {'Albert': 'Albert-4', 'Bell': 'Bell-4', 'Cherry': 'Cherry-4' } dict4
{'Albert': 'Albert-4', 'Bell': 'Bell-4', 'Cherry': 'Cherry-4'}
dict5 = {'Albert': 'Albert-5', 'Bell': 'Bell-5', 'Cherry': 'Cherry-5' } dict5
{'Albert': 'Albert-5', 'Bell': 'Bell-5', 'Cherry': 'Cherry-5'}
df1.append([dict4, dict5])
| Albert | Bell | Cherry | |
|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 |
| 2 | Albert-2 | Bell-2 | Cherry-2 |
| 3 | Albert-3 | Bell-3 | Cherry-3 |
| 0 | Albert-4 | Bell-4 | Cherry-4 |
| 1 | Albert-5 | Bell-5 | Cherry-5 |
verify_integrity
verify_integrity 參數是一個布林值,預設是 False。
verify_integrity 參數決定是否檢查合併後的新索引(index)有無重複的索引值。當 verify_integrity = False 時,pandas.DataFrame.append() 方法允許合併後的 pandas.DataFrame 物件可以有重複的索引值。而當 verify_integrity = True 時,pandas.DataFrame.append() 方法發現合併後的 pandas.DataFrame 物件有重複的索引值時,會發出 ValueError 告警。
try: df1.append([df2, df3], verify_integrity = True) except ValueError as err: print(f"Exception: {err}")
Exception: Indexes have overlapping values: Int64Index([5, 6], dtype='int64')
ignore_index 參數
ignore_index 參數是一個布林值,預設是 False。當設定為 True 時,合併後資料集將不使用合併前資料集的索引(index),取而代之的是數字 0、1、2、...。
在某些資料集的應用中,資料集原先的索引並不重要,資料集之間的索引是否有重複也不在意,這時候可以使用 ignore_index 參數,忽略原先的索引值,合併後的新資料集會重新指定索引值。
df1.append((df2, df3), ignore_index = True)
| Albert | Bell | Cherry | |
|---|---|---|---|
| 0 | Albert-1 | Bell-1 | Cherry-1 |
| 1 | Albert-2 | Bell-2 | Cherry-2 |
| 2 | Albert-3 | Bell-3 | Cherry-3 |
| 3 | Albert-4 | Bell-4 | Cherry-4 |
| 4 | Albert-5 | Bell-5 | Cherry-5 |
| 5 | Albert-6 | Bell-6 | Cherry-6 |
| 6 | Albert-5 | Bell-5 | Cherry-5 |
| 7 | Albert-6 | Bell-6 | Cherry-6 |
| 8 | Albert-7 | Bell-7 | Cherry-7 |
sort 參數
sort 參數式一個布林值,是在 0.23.0 版新增的參數,預設值是 None,在 1.0.0 版時變更預設值為 False。
在合併資料集時,如果這些資料集的欄名並未完全對其的話,sort 參數設為 True 會對欄排序。
df4 = make_df(['Albert', 'Cherry', 'David', 'Bell'], [1, 2, 3, 4]) df4
| Albert | Cherry | David | Bell | |
|---|---|---|---|---|
| 1 | Albert-1 | Cherry-1 | David-1 | Bell-1 |
| 2 | Albert-2 | Cherry-2 | David-2 | Bell-2 |
| 3 | Albert-3 | Cherry-3 | David-3 | Bell-3 |
| 4 | Albert-4 | Cherry-4 | David-4 | Bell-4 |
df5 = make_df(['Bell', 'Flora', 'Ellen', 'David'], [2, 3, 5, 6]) df5
| Bell | Flora | Ellen | David | |
|---|---|---|---|---|
| 2 | Bell-2 | Flora-2 | Ellen-2 | David-2 |
| 3 | Bell-3 | Flora-3 | Ellen-3 | David-3 |
| 5 | Bell-5 | Flora-5 | Ellen-5 | David-5 |
| 6 | Bell-6 | Flora-6 | Ellen-6 | David-6 |
df4.append(df5, sort = False)
| Albert | Cherry | David | Bell | Flora | Ellen | |
|---|---|---|---|---|---|---|
| 1 | Albert-1 | Cherry-1 | David-1 | Bell-1 | NaN | NaN |
| 2 | Albert-2 | Cherry-2 | David-2 | Bell-2 | NaN | NaN |
| 3 | Albert-3 | Cherry-3 | David-3 | Bell-3 | NaN | NaN |
| 4 | Albert-4 | Cherry-4 | David-4 | Bell-4 | NaN | NaN |
| 2 | NaN | NaN | David-2 | Bell-2 | Flora-2 | Ellen-2 |
| 3 | NaN | NaN | David-3 | Bell-3 | Flora-3 | Ellen-3 |
| 5 | NaN | NaN | David-5 | Bell-5 | Flora-5 | Ellen-5 |
| 6 | NaN | NaN | David-6 | Bell-6 | Flora-6 | Ellen-6 |
在上面這個範例中,因為 sort = False ,因此並不會對欄這個方向排序。
而下面這個範例中,sort = True ,因此資料集合併之後會再對欄排序。
df4.append(df5, sort = True)
| Albert | Bell | Cherry | David | Ellen | Flora | |
|---|---|---|---|---|---|---|
| 1 | Albert-1 | Bell-1 | Cherry-1 | David-1 | NaN | NaN |
| 2 | Albert-2 | Bell-2 | Cherry-2 | David-2 | NaN | NaN |
| 3 | Albert-3 | Bell-3 | Cherry-3 | David-3 | NaN | NaN |
| 4 | Albert-4 | Bell-4 | Cherry-4 | David-4 | NaN | NaN |
| 2 | NaN | Bell-2 | NaN | David-2 | Ellen-2 | Flora-2 |
| 3 | NaN | Bell-3 | NaN | David-3 | Ellen-3 | Flora-3 |
| 5 | NaN | Bell-5 | NaN | David-5 | Ellen-5 | Flora-5 |
| 6 | NaN | Bell-6 | NaN | David-6 | Ellen-6 | Flora-6 |
參考資料:
- Pandas 官方網站(https://pandas.pydata.org/)
- 'Python Data Science Handbook', Jake VanderPlas
- Python 官方網站(https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range )
老驥 於 2020/5/14
