在很多应用中,数据可能分布在多个文件或数据库中,抑或以某种不易于分析的格式进行排列。本章关注于对数据联合、连接以及重排列有用的工具。
首先,将pandas中的分层索引的概念,这个概念在这些操作中被广泛使用。然后深入介绍特定的数据操作。
分层索引允许你在一个轴向上拥有多个(两个或两个以上)索引层级。笼统地说,分层索引提供了一种在更低维度的形式中处理更高维度数据的方式。下面让我们从一个简单的例子开始,先创建一个Series,以列表的列表(或数组)作为索引:
import pandas as pd
import numpy as np
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]])
print(data)
---------------------------------------------------------
a 1 0.954823
2 -0.275865
3 0.028851
b 1 -0.653380
3 2.047604
c 1 0.674058
2 1.843968
d 2 -0.219208
3 -0.438914
dtype: float64
索引中的"间隙"表示“直接使用上面的标签”:
a = data.index
print(a)
---------------------------------------------------------
MultiIndex([('a', 1),
('a', 2),
('a', 3),
('b', 1),
('b', 3),
('c', 1),
('c', 2),
('d', 2),
('d', 3)],
)
通过分层索引对象,也可以称为部分索引,允许你简洁地选择出数据的子集:
a = data['b']
print(a)
a = data['b':'c']
print(a)
a = data.loc[['b','d']]
print(a)
---------------------------------------------------------
1 -0.653380
3 2.047604
dtype: float64
b 1 -0.653380
3 2.047604
c 1 0.674058
2 1.843968
dtype: float64
b 1 -0.653380
3 2.047604
d 2 -0.219208
3 -0.438914
dtype: float64
在“内部”层级中进行选择也是可以的:
a = data.loc[:,2]
print(a)
---------------------------------------------------------
a -0.275865
c 1.843968
d -0.219208
dtype: float64
分层索引在重塑数据和数组透视表等分组操作中扮演了重要角色。例如,你可以使用unstack方法将数据在DataFrame中重新排列:
a = data.unstack()
print(a)
---------------------------------------------------------
1 2 3
a 0.954823 -0.275865 0.028851
b -0.653380 NaN 2.047604
c 0.674058 1.843968 NaN
d NaN -0.219208 -0.438914
unstack的反操作是stack:
b = a.stack()
print(b)
---------------------------------------------------------
a 1 0.954823
2 -0.275865
3 0.028851
b 1 -0.653380
3 2.047604
c 1 0.674058
2 1.843968
d 2 -0.219208
3 -0.438914
dtype: float64
在DataFrame中,每个轴都可以拥有分层索引:
data = pd.DataFrame(np.arange(12).reshape((4, 3)),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']])
print(data)
---------------------------------------------------------
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
分层的层级可以有名称(可以是字符串或Python对象)。如果层级有名称,这些名称会在控制台输出中显示:
data.index.names=['key1','key2']
data.columns.names = ['state','color']
print(data)
---------------------------------------------------------
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
通过部分列索引,你可以选出列中的组:
a = data['Ohio']
print(a)
---------------------------------------------------------
color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10
有时,你需要重新排列轴上的层级顺序,或者按照特定层级的值对数据进行排序。swaplevel接收两个层级序号或层级名称,返回一个进行了层级变更的新对象(但是数据是不变的):
a = data.swaplevel('key1','key2')
print(a)
---------------------------------------------------------
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以使得结果按照层级进行字典排序也很常见:
a = data.sort_index(level=1)
print(a)
a = data.swaplevel(0,1).sort_index(level=0)
print(a)
---------------------------------------------------------
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
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
如果索引按照字典顺序从最外层开始排序,那么数据选择性能会更好——调用sort_index(level=0)或 sort_index可以得到这样的结果。
DataFrame和Series中很多描述性和汇总性统计有一个level选项,通过level选项你可以指定你想要在某个特定的轴上进行聚合。考虑上述示例中的DataFrame,我们可以按照层级在行或列上像下面这样进行聚合:
print(data)
a = data.sum(level= 'key2')
print(a)
a = data.sum(level= 'color',axis=1)
print(a)
---------------------------------------------------------
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 Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10
例如a = data.sum(level= ‘key2’),在多层级的数值相加时,先是对应外层“key2”,在对应内层索引“1”和“2”分别求和。**a = data.sum(level= ‘color’,axis=1)**同理,他是先根据外层“color”找到对应的列“Green”和“Red”,而axis=1是列对应列相加。第一列的“Green”找到第二列的“Green”对应相加,而”Red“只有一列,因此保持原样。
通常,我们不会使用DataFrame中一个或多个列作为行索引;反而你可能想要将行索引移动到DataFrame的列中。
data = 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]})
print(data)
---------------------------------------------------------
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,新的DataFrame使用一个或多个列作为索引:
a = data.set_index(['c','d'])
print(a)
---------------------------------------------------------
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中被删除,但你也可以通过传递参数drop= False 保留它们。
a1 = data.set_index(['c','d'],drop=False)
print(a1)
---------------------------------------------------------
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的反操作,分层索引的索引层级会被移动到列中:
b = a.reset_index()
print(b)
---------------------------------------------------------
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函数主要用于将各种join操作算法运用在你的数据上:
data = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
data1 = pd.DataFrame({'key': ['a', 'b', 'd'],
'data2': range(3)})
print(data)
print(data1)
---------------------------------------------------------
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
key data2
0 a 0
1 b 1
2 d 2
这是一个多对一连接的例子;data的数据有多个行的标签为a和b,而data1在key列中每个值仅有一行。调用merge处理我们获得的对象:
a = pd.merge(data,data1)
print(a)
---------------------------------------------------------
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会自动将重叠列名作为连接的键。但是,显示地指定连接键才是好的实现:
a = pd.merge(data,data1,on='key')
print(a)
---------------------------------------------------------
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
如果每个对象的列名是不同的,你可以分别为它们指定列名:
data2 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
data3 = pd.DataFrame({'rkey': ['a', 'b', 'd'],
'data2': range(3)})
a = pd.merge(data2,data3,left_on='lkey',right_on='rkey')
print(a)
---------------------------------------------------------
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做的是内连接(‘inner’ join),结果中的键是两张表的交集。其他可选的选项有’left’、‘right’和’outer’。外连接(outer join)是键的并集,联合了左连接和右连接的效果:
a = pd.merge(data,data1,how='outer')
print(a)
---------------------------------------------------------
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
下表是对how选项的总结:
选项 | 行为 |
---|---|
inner | 只对两张表都有的键的交集进行联合 |
left | 对所有左表的键进行联合 |
right | 对所有右表的键进行联合 |
outer | 对两张表都有的键的并集进行联合 |
尽管不是很直观,但多对多的合并有明确的行为。
data = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],
'data1': range(6)})
data1 = pd.DataFrame({'key': ['a', 'b', 'a', 'b', 'd'],
'data2': range(5)})
print(data)
print(data1)
a = pd.merge(data,data1,on='key',how='left')
print(a)
---------------------------------------------------------
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 b 5
key data2
0 a 0
1 b 1
2 a 2
3 b 3
4 d 4
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中有三个’b’行,而在右边有两个行,因此在结果中有六个’b’行。连接方式仅影响结果中显示的不同键:
a = pd.merge(data,data1,how='inner')
print(a)
---------------------------------------------------------
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]})
print(left)
print(right)
a = pd.merge(left,right,on=['key1','key2'],how='outer
print(a)
---------------------------------------------------------
key1 key2 lval
0 foo one 1
1 foo two 2
2 bar one 3
key1 key2 lval
0 foo one 4
1 foo one 5
2 bar one 6
3 bar two 7
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
要决定哪些键联合出现在结果中,取决于合并方法的选择,把多个键看作一个元组数据来作为单个连接键使用。
合并操作中最后一个要考虑的问题是如何处理重叠的列名。虽然你可以手动解决重叠问题,但是merge有一个suffixes后缀选项,用于在左右两边DataFrame对象重叠列名后指定需要添加的字符串:
a1 = pd.merge(left, right, on='key1')
print(a1)
a2 = pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
print(a2)
--------------------------------------------------------------------------
key1 key2_x rval key2_y lval
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
key1 key2_left rval key2_right lval
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
下表是merge方法的参数参考。使用DataFrame的行索引进行连接是下一节的内容。
参数 | 描述 |
---|---|
left | 合并时操作中左边的DataFrame |
right | 合并时操作中右边的DataFrame |
how | ‘inner’,‘outer’,‘left’,‘right’之一;默认是‘inner’ |
on | 需要连接的列名。必须是在两边的DataFrame对象都有的列名,并以left和right中的列名的交集作为连接键的列 |
left_on | left DataFrame中用作连接键的列 |
right_on | right DataFrame中用作连接键的列 |
sort | 通过连接键按字母顺序对合并的数据进行排序;默认情况下为True |
suffixes | 在重叠情况下,添加到列名后的字符串元组;默认是(‘_x’,‘_y’) |
copy | 如果为False,则在某些特殊情况下避免将数据复制到结果数据结构中,默认情况下总是复制 |
indicator | 添加一个特殊的列_merge,指示每一行的来源;值将根据每行中连接数据的来源分别为’left_only’,'right_only’或’both‘ |
left_index | 使用left的行索引作为他的连接键(如果是MultiIndex,则是多个键) |
right_index | 使用left的行索引作为他的连接键(如果是MultiIndex,则是多个键) |
在某些情况下,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'])
print(left1)
print(right1)
a = pd.merge(left1,right1,left_on='key',right_index=True)
print(a)
---------------------------------------------------------
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
group_val
a 3.5
b 7.0
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
由于默认的合并方法是连接键相交,你可以使用外连接来进行合并:
a1 = pd.merge(left1,right1,left_on='key',right_index=True,how='outer')
print(a1)
---------------------------------------------------------
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'])
print(lefth)
print(righth)
---------------------------------------------------------
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
event1 event2
Nevada 2001 0 1
2000 2 3
Ohio 2000 4 5
2000 6 7
2001 8 9
2002 10 11
这种情况下,你必须以列表的方式指明合并所需多个列(请注意使用how='outer’处理两个表的并集):
a = pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
print(a)
a = pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True,how='outer')
print(a)
---------------------------------------------------------
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
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'])
print(left2)
print(right2)
a = pd.merge(left2,right2,how='outer',left_index=True,right_index=True)
print(a)
---------------------------------------------------------
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0
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对象。在上一个例子中我们可以这样写:
a = left2.join(right2,how='outer')
print(a)
---------------------------------------------------------
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的某一列上连接传递的DataFrame的索引:
left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
'value': range(6)})
right1 = pd.DataFrame({'group_val': [3.5, 7]},
index=['a', 'b'])
print(left1)
print(right1)
a = left1.join(right1,on='key')
print(a)
---------------------------------------------------------
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
group_val
a 3.5
b 7.0
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'])
print(another)
a = left2.join([right2,another])
print(a)
a = left2.join([right2,another],how='outer')
print(a)
---------------------------------------------------------
New York Oregon
a 7.0 8.0
c 9.0 10.0
e 11.0 12.0
f 16.0 17.0
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
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
b NaN NaN 7.0 8.0 NaN NaN
d NaN NaN 11.0 12.0 NaN NaN
f NaN NaN NaN NaN 16.0 17.0
另一种数据组合操作可以互换地称为拼接、绑定或堆叠。NumPy的concatenate函数可以在NumPy数组上实现该功能:
import numpy as np
arr = np.arange(12).reshape((3,4))
print(arr)
a = np.concatenate([arr,arr],axis=1)
print(a)
---------------------------------------------------------
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[ 0 1 2 3 0 1 2 3]
[ 4 5 6 7 4 5 6 7]
[ 8 9 10 11 8 9 10 11]]
而在Seires和DataFrame等pandas对象的上下文中,使用标记的轴可以进一步泛化数组连接。尤其是你还有许多需要考虑的事情:
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'])
a = pd.concat([s1,s2,s3])
print(a)
---------------------------------------------------------
a 0
b 1
c 2
d 3
e 4
f 5
g 6
dtype: int64
默认情况下,concat方法是沿着axis=0的轴向生效的,生成另一个Series。如果你传递axis=1,返回的结果则是一个DataFrame:
a = pd.concat([s1,s2,s3],axis=1)
print(a)
---------------------------------------------------------
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])
print(s4)
a = pd.concat([s1,s4],axis=1)
print(a)
a = pd.concat([s1,s4],axis=1,join='inner')
print(a)
---------------------------------------------------------
a 0
b 1
f 5
g 6
dtype: int64
0 1
a 0.0 0
b 1.0 1
f NaN 5
g NaN 6
0 1
a 0 0
b 1 1
拼接在一起的各部分无法在结果中区分是一个潜在的问题,假设你想在连接轴向上创建一个多层索引,可以使用keys参数来实现:
result = pd.concat([s1,s1,s3],keys=['one','two','three'])
print(result)
a = result.unstack()
print(a)
---------------------------------------------------------
one a 0
b 1
two a 0
b 1
three f 5
g 6
dtype: int64
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的列头:
a = pd.concat([s1,s2,s3],axis=1,keys=['one','two','three'])
print(a)
---------------------------------------------------------
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'])
print(df1)
print(df2)
a = pd.concat([df1,df2],axis=1,keys=['level1','level2'])
print(a)
---------------------------------------------------------
one two
a 0 1
b 2 3
c 4 5
three four
a 5 6
c 7 8
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选项:
a = pd.concat({'level1':df1,'level2':df2},axis=1)
print(a)
---------------------------------------------------------
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
我们还能使用names参数命名生成的轴层级:
a = pd.concat([df1,df2],axis=1,keys=['level1','level2'],names=['upper','lower'])
print(a)
---------------------------------------------------------
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:
df11 = pd.DataFrame(np.random.rand(3,4),columns=['a','b','c','d'])
df22 = pd.DataFrame(np.random.rand(2,3),columns=['b','d','a'])
print(df11)
print(df22)
---------------------------------------------------------
a b c d
0 0.003492 0.525904 0.312933 0.633035
1 0.462266 0.738024 0.946863 0.276046
2 0.059198 0.818812 0.585546 0.776541
b d a
0 0.181717 0.350863 0.587233
1 0.028107 0.294537 0.287630
当我们传入ignore_index= True时,会产生新的索引,而不是连接索引:
a = pd.concat([df11,df22],ignore_index=True)
print(a)
---------------------------------------------------------
a b c d
0 0.003492 0.525904 0.312933 0.633035
1 0.462266 0.738024 0.946863 0.276046
2 0.059198 0.818812 0.585546 0.776541
3 0.587233 0.181717 NaN 0.350863
4 0.287630 0.028107 NaN 0.294537
下表将介绍关于concat函数的参数:
参数 | 描述 |
---|---|
objs | 需要连接的pandas对象列表或字典;这是必选参数 |
axis | 连接的轴向;默认是0(沿着行方向) |
join | 可以是’inner‘或’outer‘;用于指定连接方式是内连接还是外连接,默认是’outer‘ |
keys | 与要连接的对象关联的值,沿着连接轴形成分层索引;可以是任意值的列表或数组,也可以是数组的列表(如果向levels参数传入多层数组) |
levels | 在键值传递时,该参数用于指定多层索引的层级 |
names | 如果传入了keys和或levels参数,该参数用于多层索引的层级名称 |
verify_integrity | 检查连接对象中的新轴是否重复,如果是,则引发异常;默认(False)允许重复 |
ignore_index | 不沿着连接轴保留索引,而产生一段新的索引(长度为total_length) |
还有另一个数据联合场景,既不是合并操作,也不是连接操作。你可能有两个数据集,这两个数据集的索引全部或部分重叠。作为一个示例,考虑NumPy的where函数,这个函数可以进行面向数组的if-else等价操作:
a = pd.Series([np.nan,2.5,0.0,3.5,4.5,np.nan],
index=['f','e','d','c','b','a'])
b = pd.Series([0.,np.nan,2.,np.nan,np.nan,5.],
index=['a','b','c','d','e','f'])
print(a)
print(b)
a1 = np.where(pd.isnull(a),b,a)
print(a1)
---------------------------------------------------------
f NaN
e 2.5
d 0.0
c 3.5
b 4.5
a NaN
dtype: float64
a 0.0
b NaN
c 2.0
d NaN
e NaN
f 5.0
dtype: float64
[0. 2.5 0. 3.5 4.5 5. ]
Series有一个combine_first方法,该方法可以等价于下面这种使用pandas常见数据对齐逻辑的轴向操作:
c = b.combine_first(a)
print(c)
---------------------------------------------------------
a 0.0
b 4.5
c 2.0
d 0.0
e 2.5
f 5.0
dtype: float64
在DataFrame中,combie_first逐列做相同的操作,因此你可以认为它是根据你传入的对象来”修补“调用对象的缺失值:
df1 = pd.DataFrame({'a':[1.,np.nan,5.,np.nan],
'b':[np.nan,2.,np.nan,6.],
'c':range(2,18,4)})
df2 = pd.DataFrame({'a':[5.,4.,np.nan,3.,7.],
'b':[np.nan,3.,4.,6.,8.]})
print(df1)
print(df2)
d = df1.combine_first(df2)
print(d)
---------------------------------------------------------
a b c
0 1.0 NaN 2
1 NaN 2.0 6
2 5.0 NaN 10
3 NaN 6.0 14
a b
0 5.0 NaN
1 4.0 3.0
2 NaN 4.0
3 3.0 6.0
4 7.0 8.0
a b c
0 1.0 NaN 2.0
1 4.0 2.0 6.0
2 5.0 4.0 10.0
3 3.0 6.0 14.0
4 7.0 8.0 NaN
以上就是今天要讲的内容,本文简单介绍了分层索引的创建是以列表的列表作为索引,而我们学习到一个unstack方法可以对分层索引的数据在DataFrame进行重新排列,而unstack的反操作则是stack方法。而当你想改变层级排序是我们有swaplevel方法,对层级进行汇总统计时,level选项可以指定你想要在某个特定的轴上进行聚合。接下来就是包含pandas对象的数据进行联合与合并处理,这个时候我们就会用到merge方法,灵活调用该方法内部参数可以做到很多方式合并,DataFrame还有join方法以及concat来完成这些操作。而联合我们可以用到combine_first方法,就介绍到这些,下一篇即将介绍数据重塑和透视。