close

Pandas 筆記

合併資料集 - 02 pandas.concat() 函式的更多細節

 

 

你必須要知道的是 pandas.concat() 函式會完完整整的複製所有的資料集,因此反覆呼叫 pandas.concat()函式連續串接資料集會嚴重的影響執行性能。倘若需要串接數個資料集,與其反覆呼叫 pandas.concat() 函式一個一個串接,不如將所有要串接的資料集放進一個串列(list)或字典(dict)中,只呼叫 pandas.concat() 函式一次。

在開始所有程式說明之前,我們先輸入 Pandas 套件。

In [1]:
import pandas as pd
pd.__version__
Out[1]:
'1.0.3'

而為了方便在範例中建立 pandas.DataFrame 物件,我們借用 'Python Data Science Handbook' 裡 make_df() 函式定義。 

In [2]:
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() 方法來達到目的。

In [3]:
df1 = make_df(['Albert', 'Betty', 'Cherry', 'David'],
              [0, 1, 2, 3])
df1
Out[3]:
  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
In [4]:
df2 = make_df(['Betty', 'Cherry', 'Fanny', 'Gill'],
              [2, 3, 4, 5])
df2
Out[4]:
  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
In [5]:
df = pd.concat([df1, df2], axis = 1)
df
Out[5]:
  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
In [6]:
df = pd.concat([df1, df2], axis = 1).reindex(df1.index)
df
Out[6]:
  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) 新索引過濾,再執行串接。

In [7]:
df = pd.concat([df1, df2.reindex(df1.index)],
               axis = 1)
df
Out[7]:
  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 參數不是用來建立建立階層式最外層索引的名稱,而是用來指定欄位名稱。

In [8]:
s1 = pd.Series(['Albert', 'Betty', 'Cherry', 'David'],
               name = 's1')
s1
Out[8]:
0    Albert
1     Betty
2    Cherry
3     David
Name: s1, dtype: object
In [9]:
s2 = pd.Series(['Ellen', 'Flix', 'Gill', 'Hedy'],
               name = 's2')
s2
Out[9]:
0    Ellen
1     Flix
2     Gill
3     Hedy
Name: s2, dtype: object
In [10]:
s3 = pd.Series(['Ivy', 'Jeremy', 'Kent', 'Lara'],
               name = 's3')
s3
Out[10]:
0       Ivy
1    Jeremy
2      Kent
3      Lara
Name: s3, dtype: object
In [11]:
df = pd.concat([s1, s2, s3], axis = 1)
df
Out[11]:
  s1 s2 s3
0 Albert Ellen Ivy
1 Betty Flix Jeremy
2 Cherry Gill Kent
3 David Hedy Lara
In [12]:
df = pd.concat([s1, s2, s3], axis = 1,
               keys = ['group1', 'group2', 'group3'])
df
Out[12]:
  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 參數來使用,建立階層式索引結構。

In [13]:
df1 = make_df(['Albert', 'Betty', 'Cherry'],
              [0, 1, 2, 3])
df1
Out[13]:
  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
In [14]:
df2 = make_df(['David', 'Ellen', 'Flix'],
              [0, 1, 2, 3])
df2
Out[14]:
  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
In [15]:
df3 = make_df(['Gill', 'Hedy', 'Ivy'],
              [0, 1, 2, 3])
df3
Out[15]:
  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
In [16]:
df = pd.concat({'x': df1, 'y': df2, 'z': df3},
               axis = 1)
df
Out[16]:
  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 參數裡的欄位群將不會被串接起來。

In [17]:
df = pd.concat({'x': df1, 'y': df2, 'z': df3},
               axis = 1, keys = ['y', 'x'])
df
Out[17]:
  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

 

arrow
arrow
    創作者介紹
    創作者 phd.chi 的頭像
    phd.chi

    maximaChi's blog

    phd.chi 發表在 痞客邦 留言(0) 人氣()