第八篇2 資料規整:聚合、合併和重塑
在許多應⽤中,資料可能分散在許多⽂件或資料庫中,儲存的形式也不利於分析。本章關注可以聚合、合併、重塑資料的⽅法。⾸先,介紹pandas的層次化索引,它⼴泛⽤於以上操作。然後,深⼊介紹了⼀些特殊的資料操作。
一、層次化索引
層次化索引(hierarchical indexing)是pandas的⼀項重要功能,它使你能在⼀個軸上擁有多個(兩個以上)索引級別。抽象點說,它使你能以低維度形式處理⾼維度資料。我們先來看⼀個簡單的例⼦:建立⼀個Series,並⽤⼀個由列表或陣列組成的列表作為索引:
data = pd.Series(np.random.randn(9),
index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],
[1, 2, 3, 1, 3, 1, 2, 2, 3]])
data # 輸出如下:
a 1 1.007189
2 -1.296221
3 0.274992
b 1 0.228913
3 1.352917
c 1 0.886429
2 -2.001637
d 2 -0.371843
3 1.669025
dtype: float64
看到的結果是經過美化的帶有MultiIndex索引的Series的格式。索引之間的“間隔”表示“直接使⽤上⾯的標籤
data.index # 輸出如下:
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])
對於⼀個層次化索引的物件,可以使⽤所謂的部分索引,使⽤它選取資料⼦集的操作更簡單:
data['b'] # 輸出如下:
1 0.228913
3 1.352917
dtype: float64
data['b':'c'] # 輸出如下:
b 1 0.228913
3 1.352917
c 1 0.886429
2 -2.001637
dtype: float64
data.loc[['b', 'd']] # 輸出如下:
b 1 0.228913
3 1.352917
d 2 -0.371843
3 1.669025
dtype: float64
有時甚⾄還可以在“內層”
data.loc[:, 2] # 輸出如下:(選取帶2的標籤)
a -1.296221
c -2.001637
d -0.371843
dtype: float64
層次化索引在資料重塑和基於分組的操作(如透視表⽣成)中扮演著重要的⻆⾊。例如,可以通過unstack⽅法將這段資料重新安排到⼀個DataFrame中:
data.unstack() # 輸出如下:
1 2 3
a 1.007189 -1.296221 0.274992
b 0.228913 NaN 1.352917
c 0.886429 -2.001637 NaN
d NaN -0.371843 1.669025
unstack的逆運算是stack
data.unstack().stack() # 輸出如下:
a 1 1.007189
2 -1.296221
3 0.274992
b 1 0.228913
3 1.352917
c 1 0.886429
2 -2.001637
d 2 -0.371843
3 1.669025
dtype: float64
stack和unstack將在後⾯詳細講解。
對於⼀個DataFrame,每條軸都可以有分層索引:
frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=[['Ohio', 'Ohio', 'Colorado'],
['Green', 'Red', 'Green']])
frame # 輸出如下:
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
各層都可以有名字(可以是字串,也可以是別的Python物件)。如果指定了名稱,它們就會顯示在控制檯輸出中:
frame.index.names = ['key1', 'key2'] # 設定行索引屬性名稱
frame.columns.names = ['state', 'color'] # 設定列索引屬性名稱
frame # 輸出如下:
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
注意:⼩⼼區分索引名state、color與⾏標籤。
有了部分列索引,因此可以輕鬆選取列分組:
frame['Ohio'] # 輸出如下:
color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10
可以單獨建立MultiIndex然後復⽤。上⾯那個DataFrame中的(帶有分級名稱)列可以這樣建立:
MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']],
names=['state', 'color'])
1、重排與分級排序
有時,你需要重新調整某條軸上各級別的順序,或根據指定級別上的值對資料進⾏排序。swaplevel接受兩個級別編號或名稱,並返回⼀個互換了級別的新物件(但資料不會發⽣變化):
frame.swaplevel('key1', 'key2') # 輸出如下:(互換'key1'和'key2')
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11
⽽sort_index則根據單個級別中的值對資料進⾏排序。交換級別時,常常也會⽤到sort_index,這樣最終結果就是按照指定順序進⾏字⺟排序了:
frame.sort_index(level=1) # 輸出如下:(對第二個索引排序('key2'))
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
frame.swaplevel(0, 1).sort_index(level=0) # 輸出如下:(互換兩個索引,對第一個索引排序)
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11
2、根據級別彙總統計
許多對DataFrame和Series的描述和彙總統計都有⼀個level選項,它⽤於指定在某條軸上求和的級別。再以上⾯那個DataFrame為例,我們可以根據⾏或列上的級別來進⾏求和:
frame.sum(level='key2') # 輸出如下:(注意level引數後面給的是行索引或列索引的屬性名稱)
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
frame.sum(level='color', axis=1) # 輸出如下:(根據相同的顏色(Green,Red)按行求和)
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
這其實是利⽤了pandas的groupby功能,稍後將對其進⾏詳細講解。
3、使⽤DataFrame的列進⾏索引
經常要將DataFrame的⼀個或多個列當做⾏索引來⽤,或者可能希望將⾏索引變成DataFrame的列。以下⾯這個DataFrame為例:
frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),
'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
'd': [0, 1, 2, 0, 1, 2, 3]})
frame # 輸出如下:
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3
DataFrame的set_index函式會將其⼀個或多個列轉換為⾏索引,並建立⼀個新的DataFrame:
frame2 = frame.set_index(['c', 'd']) # c、d列轉換為行索引
frame2 # 輸出如下:
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1
預設情況下,那些列會從DataFrame中移除,但也可以將其保留下來:
frame.set_index(['c', 'd'], drop=False) # 輸出如下:
a b c d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
3 6 1 two 3
reset_index的功能跟set_index剛好相反,層次化索引的級別會被轉移到列⾥⾯:
frame2.reset_index() # 輸出如下:
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1
二、合併資料集
pandas物件中的資料可以通過⼀些⽅式進⾏合併:
pandas.merge可根據⼀個或多個鍵將不同DataFrame中的⾏連線起來。SQL或其他關係型資料庫的⽤戶對此應該會⽐較熟悉,因為它實現的就是資料庫的join操作。
pandas.concat可以沿著⼀條軸將多個物件堆疊到⼀起。例項⽅法combine_first可以將重複資料編接在⼀起,⽤⼀個物件中的值填充另⼀個物件中的缺失值。
接下來對它們進⾏講解,並給出⼀些例⼦。後面部分的示例中將經常⽤到它們。
1、資料庫⻛格的DataFrame合併
資料集的合併(merge)或連線(join)運算是通過⼀個或多個鍵將⾏連結起來的。這些運算是關係型資料庫(基於SQL)的核⼼。pandas的merge函式是對資料應⽤這些演算法的主要切⼊點。
以⼀個簡單的例⼦開始:
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})
df1 # 輸出如下:
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df2 # 輸出如下:
key data2
0 a 0
1 b 1
2 d 2
這是⼀種多對⼀的合併。df1中的資料有多個被標記為a和b的⾏,⽽df2中key列的每個值則僅
對應⼀⾏。對這些物件調⽤merge即可得到:
pd.merge(df1,df2) # 輸出如下:(合併具有相同的行索引,鍵的並集)
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0
注意,我並沒有指明要⽤哪個列進⾏連線。如果沒有指定,merge就會將重疊列的列名當做鍵。不過,最好明確指定⼀下:
pd.merge(df1, df2, on='key') # 輸出如下:
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0
如果兩個物件的列名不同,也可以分別進⾏指定:
df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})
df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)})
pd.merge(df3, df4, left_on='lkey', right_on='rkey') # 輸出如下:
lkey data1 rkey data2
0 b 0 b 1
1 b 1 b 1
2 b 6 b 1
3 a 2 a 0
4 a 4 a 0
5 a 5 a 0
可能你已經注意到了,結果⾥⾯c和d以及與之相關的資料消失了。預設情況下,merge做的是“內連線”;結果中的鍵是交集。其他⽅式還有"left"、"right"以及"outer"。外連線求取的是鍵的並集,組合了左連線和右連線的效果:
pd.merge(df1, df2, how='outer') # 輸出如下:(結果是鍵的並集)
key data1 data2
0 b 0.0 1.0
1 b 1.0 1.0
2 b 6.0 1.0
3 a 2.0 0.0
4 a 4.0 0.0
5 a 5.0 0.0
6 c 3.0 NaN
7 d NaN 2.0
表8-1對這些選項進⾏了總結
選項 說明
'inner' 使用兩個表都有的鍵(預設)
'left' 使用左表中所有的鍵
'right' 使用右表中所有的鍵
'outer' 使用兩個表中所有的鍵
多對多的合併有些不直觀。看下⾯的例⼦:
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6)})
df2 = pd.DataFrame({'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5)})
df1 # 輸出如下:
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 b 5
df2 # 輸出如下:
key data2
0 a 0
1 b 1
2 a 2
3 b 3
4 d 4
pd.merge(df1, df2, on='key', how='left') # 輸出如下:
key data1 data2
0 b 0 1.0
1 b 0 3.0
2 b 1 1.0
3 b 1 3.0
4 a 2 0.0
5 a 2 2.0
6 c 3 NaN
7 a 4 0.0
8 a 4 2.0
9 b 5 1.0
10 b 5 3.0
多對多連線產⽣的是⾏的笛卡爾積。由於左邊的DataFrame有3個"b"⾏,右邊的有2個,所以最終結果中就有6個"b"⾏。連線⽅式隻影響出現在結果中的不同的鍵的值:
pd.merge(df1, df2, how='inner') # 輸出如下:(等同於:pd.merge(df1, df2))
key data1 data2
0 b 0 1
1 b 0 3
2 b 1 1
3 b 1 3
4 b 5 1
5 b 5 3
6 a 2 0
7 a 2 2
8 a 4 0
9 a 4 2
要根據多個鍵進⾏合併,傳⼊⼀個由列名組成的列表即可:
left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3]})
right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7]})
pd.merge(left, right, on=['key1', 'key2'], how='outer') # 輸出如下:(根據多個鍵合併)
key1 key2 lval rval
0 foo one 1.0 4.0
1 foo one 1.0 5.0
2 foo two 2.0 NaN
3 bar one 3.0 6.0
4 bar two NaN 7.0
結果中會出現哪些鍵組合取決於所選的合併⽅式,你可以這樣來理解:多個鍵形成⼀系列元組,並將其當做單個連線鍵(當然,實際上並不是這麼回事)。
注意:在進⾏列-列連線時,DataFrame物件中的索引會被丟棄。
對於合併運算需要考慮的最後⼀個問題是對重複列名的處理。雖然你可以⼿⼯處理列名重疊的問題(檢視前⾯介紹的重新命名軸標籤),但merge有⼀個更實⽤的suffixes選項,⽤於指定附加到左右兩個DataFrame物件的重疊列名上的字串:
pd.merge(left, right, on='key1') # 輸出如下:
key1 key2_x lval key2_y rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7
pd.merge(left, right, on='key1', suffixes=('_left', '_right')) # 輸出如下(指定字尾)
key1 key2_left lval key2_right rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7
表8-2 merge函式的引數
2、索引上的合併
有時候,DataFrame中的連線鍵位於其索引中。在這種情況下,你可以傳⼊left_index=True或right_index=True(或兩個都傳)以說明索引應該被⽤作連線鍵:
left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 'value': range(6)})
right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
left1 # 輸出如下:
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
right1 # 輸出如下:
group_val
a 3.5
b 7.0
pd.merge(left1, right1, left_on='key', right_index=True) # 輸出如下:
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
由於預設的merge⽅法是求取連線鍵的交集,因此你可以通過外連線的⽅式得到它們的並集:
pd.merge(left1, right1, left_on='key', right_index=True, how='outer') # 輸出如下:
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
5 c 5 NaN
對於層次化索引的資料,事情就有點複雜了,因為索引的合併預設是多鍵合併:
lefth = pd.DataFrame({'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'key2': [2000, 2001, 2002, 2001, 2002],
'data': np.arange(5.)})
righth = pd.DataFrame(np.arange(12).reshape((6, 2)),
index=[['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'],
[2001, 2000, 2000, 2000, 2001, 2002]],
columns=['event1', 'event2'])
lefth # 輸出如下:
key1 key2 data
0 Ohio 2000 0.0
1 Ohio 2001 1.0
2 Ohio 2002 2.0
3 Nevada 2001 3.0
4 Nevada 2002 4.0
righth # 輸出如下:
event1 event2
Nevada 2001 0 1
2000 2 3
Ohio 2000 4 5
2000 6 7
2001 8 9
2002 10 11
這種情況下,必須以列表的形式指明⽤作合併鍵的多個列(注意⽤how='outer'對重複索引值的處理):
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True) # 輸出如下:
key1 key2 data event1 event2
0 Ohio 2000 0.0 4 5
0 Ohio 2000 0.0 6 7
1 Ohio 2001 1.0 8 9
2 Ohio 2002 2.0 10 11
3 Nevada 2001 3.0 0 1
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True, how='outer') # 輸出如下:
key1 key2 data event1 event2
0 Ohio 2000 0.0 4.0 5.0
0 Ohio 2000 0.0 6.0 7.0
1 Ohio 2001 1.0 8.0 9.0
2 Ohio 2002 2.0 10.0 11.0
3 Nevada 2001 3.0 0.0 1.0
4 Nevada 2002 4.0 NaN NaN
4 Nevada 2000 NaN 2.0 3.0
同時使⽤合併雙⽅的索引也沒問題:
left2 = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]],
index=['a', 'c', 'e'],
columns=['Ohio', 'Nevada'])
right2 = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]],
index=['b', 'c', 'd', 'e'],
columns=['Missouri', 'Alabama'])
left2 # 輸出如下:
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
right2 # 輸出如下:
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0
pd.merge(left2, right2, how='outer', left_index=True, right_index=True) # 輸出如下:
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
b NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0
d NaN NaN 11.0 12.0
e 5.0 6.0 13.0 14.0
DataFrame還有⼀個便捷的join例項⽅法,它能更為⽅便地實現按索引合併。它還可⽤於合併多個帶有相同或相似索引的DataFrame物件,但要求沒有重疊的列。在上⾯那個例⼦中,我們可以編寫:
left2.join(right2, how='outer') # 輸出如下:
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
b NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0
d NaN NaN 11.0 12.0
e 5.0 6.0 13.0 14.0
因為⼀些歷史版本的遺留原因,DataFrame的join⽅法預設使⽤的是左連線,保留左邊表的⾏索引。它還⽀持在調⽤的DataFrame的列上,連線傳遞的DataFrame索引:
left1.join(right1, on='key') # 輸出如下:
key value group_val
0 a 0 3.5
1 b 1 7.0
2 a 2 3.5
3 a 3 3.5
4 b 4 7.0
5 c 5 NaN
最後,對於簡單的索引合併,還可以向join傳⼊⼀組DataFrame,後面會介紹更為通⽤的concat函式,也能實現此功能:
another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],
index=['a', 'c', 'e', 'f'],
columns=['New York', 'Oregon'])
another # 輸出如下:
New York Oregon
a 7.0 8.0
c 9.0 10.0
e 11.0 12.0
f 16.0 17.0
left2.join([right2, another]) # 輸出如下:(注意引數是列表)
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0 9.0 10.0
e 5.0 6.0 13.0 14.0 11.0 12.0
left2.join([right2, another], how='outer') # 輸出如下:(行索引合併)
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
b NaN NaN 7.0 8.0 NaN NaN
c 3.0 4.0 9.0 10.0 9.0 10.0
d NaN NaN 11.0 12.0 NaN NaN
e 5.0 6.0 13.0 14.0 11.0 12.0
f NaN NaN NaN NaN 16.0 17.0
3、軸向連線
另⼀種資料合併運算也被稱作連線(concatenation)、繫結(binding)或堆疊(stacking)。
NumPy的concatenation函式可以⽤NumPy陣列來做:
arr = np.arange(12).reshape((3, 4))
arr # 輸出如下:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
np.concatenate([arr, arr], axis=1) # 輸出如下:
array([[ 0, 1, 2, 3, 0, 1, 2, 3],
[ 4, 5, 6, 7, 4, 5, 6, 7],
[ 8, 9, 10, 11, 8, 9, 10, 11]])
對於pandas物件(如Series和DataFrame),帶有標籤的軸使你能夠進⼀步推⼴陣列的連線運算。
具體點說,你還需要考慮以下這些東⻄:
如果物件在其它軸上的索引不同,我們應該合併這些軸的不
同元素還是隻使⽤交集?
連線的資料集是否需要在結果物件中可識別?
連線軸中儲存的資料是否需要保留?許多情況下,
DataFrame預設的整數標籤最好在連線時刪掉。
pandas的concat函式提供了⼀種能夠解決這些問題的可靠⽅式。
下面將給出⼀些例⼦來講解其使⽤⽅式。假設有三個沒有重疊索引的Series:
s1 = pd.Series([0, 1], index=['a', 'b'])
s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = pd.Series([5, 6], index=['f', 'g'])
對這些物件調⽤concat可以將值和索引粘合在⼀起:
pd.concat([s1, s2, s3]) # 輸出如下:
a 0
b 1
c 2
d 3
e 4
f 5
g 6
dtype: int64
預設情況下,concat是在axis=0上⼯作的,最終產⽣⼀個新的Series。如果傳⼊axis=1,則結果就會變成⼀個DataFrame(axis=1是列):
pd.concat([s1, s2, s3], axis=1) # 輸出如下:
0 1 2
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0
這種情況下,另外的軸上沒有重疊,從索引的有序並集(外連線)上就可以看出來。
傳⼊join='inner'即可得到它們的交集:
s4 = pd.concat([s1, s3])
s4 # 輸出如下:
a 0
b 1
f 5
g 6
dtype: int64
pd.concat([s1, s4], axis=1) # 輸出如下:(並集)
0 1
a 0.0 0
b 1.0 1
f NaN 5
g NaN 6
pd.concat([s1, s4], axis=1, join='inner') # 輸出如下:(交集)
0 1
a 0 0
b 1 1
在這個例⼦中,f和g標籤消失了,是因為使⽤的是join='inner'選項。
你可以通過join_axes指定要在其它軸上使⽤的索引:
pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'e']]) # 輸出如下:(指定行索引)
0 1
a 0.0 0.0
c NaN NaN
b 1.0 1.0
e NaN NaN
不過有個問題,參與連線的⽚段在結果中區分不開。假設你想要在連線軸上建立⼀個層次化索引。使⽤keys引數即可達到這個⽬的:
result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three']) # 層次化索引
result # 輸出如下:
one a 0
b 1
two a 0
b 1
three f 5
g 6
dtype: int64
result.unstack() # 輸出如下:
a b f g
one 0.0 1.0 NaN NaN
two 0.0 1.0 NaN NaN
three NaN NaN 5.0 6.0
如果沿著axis=1對Series進⾏合併,則keys就會成為DataFrame的列頭:
pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three']) # 輸出如下:
one two three
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0
同樣的邏輯也適⽤於DataFrame物件:
df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'],
columns=['one', 'two'])
df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'],
columns=['three', 'four'])
df1 # 輸出如下:
one two
a 0 1
b 2 3
c 4 5
df2 # 輸出如下:
three four
a 5 6
c 7 8
pd.concat([df1, df2], axis=1, keys=['level1', 'level2']) # 輸出如下:
level1 level2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0
如果傳⼊的不是列表⽽是⼀個字典,則字典的鍵就會被當做keys選項的值:
pd.concat({'level1': df1, 'level2': df2}, axis=1) # 輸出如下
level1 level2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0
此外還有兩個⽤於管理層次化索引建立⽅式的引數(參⻅表8-3)。舉個例⼦,我們可以⽤names引數命名建立的軸級別:
pd.concat([df1, df2], axis=1, keys=['level1', 'level2'],
names=['upper', 'lower']) # 輸出如下
upper level1 level2
lower one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0
最後⼀個關於DataFrame的問題是,DataFrame的⾏索引不包含任何相關資料:
df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
df1 # 輸出如下
a b c d
0 1.721685 -0.160918 -2.419580 -1.634277
1 -1.039395 -0.595996 0.788547 0.455259
2 0.342471 -0.118662 1.402167 0.280451
df2 # 輸出如下
b d a
0 0.236757 -0.909635 0.986049
1 -0.038411 -0.034186 -0.879236
在這種情況下,傳⼊ignore_index=True即可:
pd.concat([df1, df2], ignore_index=True) # 輸出如下:
a b c d
0 1.721685 -0.160918 -2.419580 -1.634277
1 -1.039395 -0.595996 0.788547 0.455259
2 0.342471 -0.118662 1.402167 0.280451
3 0.986049 0.236757 &nbs