pandas对象中的数据可以通过一些内置的方式进行合并:
1.1 merge函数和join函数
相关代码
from pandas import DataFrame
import pandas as pd
#多对一:“多”指的是df1,df1中有多个被标记为a和b的行;“一"指的是df2,df2中key列每个值只对应一行
#两对象存在相同列名时:
df1=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df2=DataFrame({'key':['a','b','d'],'data2':range(3)})
#没有指定用哪一列进行连接,merge会按照重叠列的列名当键
m1=pd.merge(df1,df2)
#但,最好显式指定一下:
m2=pd.merge(df1,df2,on='key')
#利用join函数
#数据内容与m1/m2相同,但索引与data1相同,这是因为连接方式默认是'left'因此索引与data1一一对应
df1.join(df2.set_index('key'),on='key',how='inner')
#从结果可以看出:c和d以及与之相关的数据都不见了,
#这是因为merge时,默认做的是'inner'连接,结果中的键是交集
#还有'outer','left','right'方式
m3=pd.merge(df1,df2,how='outer')
"""
df1: df2: m1/m2: m3:
data1 key data2 key data1 key data2 data1 key data2
0 0 b 0 0 a 0 0 b 1 0 0.0 b 1.0
1 1 b 1 1 b 1 1 b 1 1 1.0 b 1.0
2 2 a 2 2 d 2 6 b 1 2 6.0 b 1.0
3 3 c 3 2 a 0 3 2.0 a 0.0
4 4 a 4 4 a 0 4 4.0 a 0.0
5 5 a 5 5 a 0 5 5.0 a 0.0
6 6 b 6 3.0 c NaN
7 NaN d 2.0
"""
#当两对象不存在相同列名时,可以进行分别指定:
df3=DataFrame({'lkey':['b','b','a','c','a','a','b'],'data1':range(7)})
df4=DataFrame({'rkey':['a','b','d'],'data2':range(3)})
m4=pd.merge(df3,df4,left_on='lkey',right_on='rkey')
"""
df3: df4: m4:
data1 lkey data2 rkey data1 lkey data2 rkey
0 0 b 0 0 a 0 0 b 1 b
1 1 b 1 1 b 1 1 b 1 b
2 2 a 2 2 d 2 6 b 1 b
3 3 c 3 2 a 0 a
4 4 a 4 4 a 0 a
5 5 a 5 5 a 0 a
6 6 b
"""
#多对多,产生的是行的笛卡尔积,
#例:df5中data1=0,key=b的,连接后结果中,有两个,这是因为df6中key为b的有两个
df5=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df6=DataFrame({'key':['a','b','a','d','b'],'data2':range(5)})
m5=pd.merge(df5,df6,on='key',how='left')
"""
m5: df5: df6:
data1 key data2 data1 key data2 key
0 0 b 1.0 0 0 b 0 0 a
1 0 b 4.0 1 1 b 1 1 b
2 1 b 1.0 2 2 a 2 2 a
3 1 b 4.0 3 3 c 3 3 d
4 2 a 0.0 4 4 a 4 4 b
5 2 a 2.0 5 5 a
6 3 c NaN 6 6 b
7 4 a 0.0
8 4 a 2.0
9 5 a 0.0
10 5 a 2.0
11 6 b 1.0
12 6 b 4.0
"""
#根据多个键合并,只需要传入一个由列名组成的列表
left=DataFrame({'key1':['foo','foo','bar'],'key2':['one','two','one'],'lval':[1,2,3]})
right=DataFrame({'key1':['foo','foo','bar','bar'],'key2':['one','one','one','two'],'rval':[4,5,7,8]})
m6=pd.merge(left,right,on=['key1','key2'],how='outer')
"""
left: right: m6:
key1 key2 lval key1 key2 rval key1 key2 lval rval
0 foo one 1 0 foo one 4 0 foo one 1.0 4.0
1 foo two 2 1 foo one 5 1 foo one 1.0 5.0
2 bar one 3 2 bar one 7 2 foo two 2.0 NaN
3 bar two 8 3 bar one 3.0 7.0
4 bar two NaN 8.0
"""
#合并运算时,对于重复列名的处理
m7=pd.merge(left,right,on='key1') #自动对重复列名添加后缀:_x,_y等
#使用merge中的suffixes选项
m8=pd.merge(left,right,on='key1',suffixes=('_left','_right'))
#使用join函数 #数据内容与m8相同,索引是[0,0,1,1,2,2]
left.join(right.set_index('key1'),on='key1',lsuffix='_left',rsuffix='_right')
"""
m7: m8:
key1 key2_x lval key2_y rval key1 key2_left lval key2_right rval
0 foo one 1 one 4 0 foo one 1 one 4
1 foo one 1 one 5 1 foo one 1 one 5
2 foo two 2 one 4 2 foo two 2 one 4
3 foo two 2 one 5 3 foo two 2 one 5
4 bar one 3 one 7 4 bar one 3 one 7
5 bar one 3 two 8 5 bar one 3 two 8
"""
#索引上的合并
left1=DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
right1=DataFrame({'group_val':[3.3,6.6]},index=['a','b'])
m9=pd.merge(left1,right1,left_on='key',right_index=True)
#使用join函数
m10=left1.set_index('key').join(right1,how='inner')
"""
left1: right1: m9: m10:
data1 key group_val data1 key group_val data1 group_val
0 0 b a 3.3 0 0 b 6.6 a 2 3.3
1 1 b b 6.6 1 1 b 6.6 a 4 3.3
2 2 a 5 5 b 6.6 b 0 6.6
3 3 c 2 2 a 3.3 b 1 6.6
4 4 a 4 4 a 3.3 b 5 6.6
5 5 b
"""
1.2 concat函数------轴向连接
相关代码
#轴向连接
from pandas import DataFrame,Series
import pandas as pd
import numpy as np
s1=Series([0,1],index=['a','b'])
s2=Series([2,3,4],index=['c','d','e'])
s3=Series([5,6],index=['f','g'])
#concat默认是在axis=0上工作的,默认外连接(outter)求并集
c1=pd.concat([s1,s2,s3])
c2=pd.concat([s1,s2,s3],axis=1)
"""
c1: c2:
a 0 0 1 2
b 1 a 0.0 NaN NaN
c 2 b 1.0 NaN NaN
d 3 c NaN 2.0 NaN
e 4 d NaN 3.0 NaN
f 5 e NaN 4.0 NaN
g 6 f NaN NaN 5.0
dtype: int64 g NaN NaN 6.0
"""
s4=pd.concat([s1*5,s3])
c3=pd.concat([s1,s4],axis=1)
#设置求交集,需将join='inner'
c4=pd.concat([s1,s4],axis=1,join='inner')
#可以使用join_axes指定其他轴上使用的索引,因为此时axis=1,所以其他轴指axis=0
c5=pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
"""
s4: c3: c4: c5:
a 0 0 1 0 1 0 1
b 5 a 0.0 0 a 0 0 a 0.0 0.0
f 5 b 1.0 5 b 1 5 c NaN NaN
g 6 f NaN 5 b 1.0 5.0
dtype: int64 g NaN 6 e NaN NaN
"""
#创建层次化索引
c6=pd.concat([s1,s2,s3],keys=['s1','s2','s3'])
c7=pd.concat([s1,s2,s3],axis=1,keys=['s1','s2','s3'])
""" c7:
c6: s1 s2 s3
s1 a 0 a 0.0 NaN NaN
b 1 b 1.0 NaN NaN
s2 c 2 c NaN 2.0 NaN
d 3 d NaN 3.0 NaN
e 4 e NaN 4.0 NaN
s3 f 5 f NaN NaN 5.0
g 6 g NaN NaN 6.0
dtype: int64
"""
df1=DataFrame(np.ones((3,4)),columns=['a','b','c','d'])
df2=DataFrame(np.zeros((2,3)),columns=['b','d','a'])
#直接连接时,索引会重复
c8=pd.concat([df1,df2])
#此时,只需将ignore_index=True即可
c9=pd.concat([df1,df2],ignore_index=True)
"""
c8: c9:
a b c d a b c d
0 1.0 1.0 1.0 1.0 0 1.0 1.0 1.0 1.0
1 1.0 1.0 1.0 1.0 1 1.0 1.0 1.0 1.0
2 1.0 1.0 1.0 1.0 2 1.0 1.0 1.0 1.0
0 0.0 0.0 NaN 0.0 3 0.0 0.0 NaN 0.0
1 0.0 0.0 NaN 0.0 4 0.0 0.0 NaN 0.0
"""
1.3 对于索引全部或部分重叠的两个数据集进行合并的情况,采用combine_first方法,其效果如下:
#合并重叠数据,若索引全部或部分重叠的两个数据集进行合并时
a=Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
b=Series(np.arange(6,dtype=np.float64),index=['f','e','d','c','b','a'])
b[-1]=np.nan
#矢量化的if_else语句
np.where(pd.isnull(a),b,a) #return: array([ 0. , 2.5, 2. , 3.5, 4.5, nan])
#等效于combine_first方法,且该方法,能使数据对齐。
#用参数对象的数据为调用者对象的缺失数据“打补丁”,对于DataFrame对象也一样
a.combine_first(b)
"""
a: b: a.combine_first(b):
f NaN f 0.0 f 0.0
e 2.5 e 1.0 e 2.5
d NaN d 2.0 d 2.0
c 3.5 c 3.0 c 3.5
b 4.5 b 4.0 b 4.5
a NaN a NaN a NaN
"""
二、数据的重塑
用于重新排列表格型数据的基础运算函数,也称作重塑(reshape)或轴向旋转(pivot)运算。
2.1 重塑层次化索引
层次化索引为DataFrame数据的重排任务提供了一种良好一致性的方式:
#重塑层次化索引
#stack和unstack两者可逆。
data=DataFrame(np.arange(6).reshape((2,3)),index=pd.Index(['CN','UK'],name='state'),columns=pd.Index(['A','B','C'],name='ch'))
#stack:将数据的列“旋转”为行,且默认滤除缺失数据
result1=data.stack()
#result1.unstack()的结果和data相同
#unstack:将数据的行“旋转”为列,若找不到对应数据,则会引入缺失数据
result2=data.unstack()
"""
data: result1: result2:
ch A B C state ch ch state
state CN A 0 A CN 0
CN 0 1 2 B 1 UK 3
UK 3 4 5 C 2 B CN 1
UK A 3 UK 4
B 4 C CN 2
C 5 UK 5
"""
2.2 将“长格式”旋转为“宽格式“------pivot方法
时间序列数据通常是以所谓的”长格式“(long)或”堆叠格式“(stacked)存储在数据库和csv文件中。
pivot其实只是一个快捷方式而已,用set_index创建层次化索引,再用unstack重塑。
ldata=pd.read_csv('ldata.csv')
#pivot函数,第一个参数作为行索引的列名,第二个参数作为列索引的列名,第三个参数则是数据列列名
pivoted=ldata.pivot(index='date',columns='item',values='value')
#或pivoted=ldata.pivot('date','item','value')
#若有多个需要重塑的数据列(values),则最后一个参数忽略,将默认除行列索引的列名,其余皆为数据列
"""
ldata: pivoted:
date item value item infl realgdp unemp
0 1959-03 realgdp 270.349 date
1 1959-03 infl 0.000 1959-03 0.00 270.349 5.8
2 1959-03 unemp 5.800 1959-06 2.34 2778.801 5.1
3 1959-06 realgdp 2778.801 1959-09 2.74 2775.488 5.3
4 1959-06 infl 2.340 1959-12 NaN 2785.204 NaN
5 1959-06 unemp 5.100
6 1959-09 realgdp 2775.488
7 1959-09 infl 2.740
8 1959-09 unemp 5.300
9 1959-12 realgdp 2785.204
"""