层次化索引
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.index
创建一个Series,通过index属性可以获取其索引。
使用索引和切片选择层次化Series的数据。
选择第一层的索引b
切片选择索引b-c
通过loc选择索引b、c
选择第一层索引的第二行数据。
通过unstack方法将两层索引的Series转为DataFrame,第二层转为列索引。
unstack的逆运算是stack,将DataFrame转为Series,列索引变成行索引的第二层。
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']])
创建一个4行3列的DataFrame,行列索引都有两层。
通过index.names可以为行索引命名,columns.names为列索引命名。
frame.index.names = ['key1','key2']
frame.columns.names = ['state','color']
通过索引选取列分组。
可以单独创建MultiIndex然后复用。
pd.MultiIndex.from_arrays([['Ohio','Ohio','Colorado'],['Green','Red','Green']],
names=['state','color'])
a = pd.MultiIndex.from_arrays([['Ohio','Ohio','Colorado'],['Green','Red','Green']],
names=['state','color'])
b = pd.Series(np.random.randn(3),index=a)
重排与分级排序
DataFrame的swaplevel方法可以将分层位置对换。
frame.swaplevel('key1','key2')
sort_index方法根据单个级别中的值对数据进行排序。
frame.sort_index(level=1)
frame.sort_index(level=0)
level=1表示按照key2列进行排序。
level=0表示按照key1列进行排序。
结合swaplevel方法和sort_index方法
frame.swaplevel(0,1).sort_index(level=0)
根据级别汇总统计
sum函数通过传入level参数可以对指定列进行汇总。
frame.sum(level='key2')
默认axis=0,即行索引,改为axis=1可以对列索引进行求和
frame.sum(level='color',axis=1) #对第二层列索引进行求和。
使用DataFrame的列进行索引
frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),^M
'c': ['one', 'one', 'one', 'two', 'two',^M
'two', 'two'],^M
'd': [0, 1, 2, 0, 1, 2, 3]})
frame2 = frame.set_index(['c','d'])
创建一个七行四列的DataFrame,通过set_index方法可以将DataFrame中的指定列设为行索引。如set_index(['c','d'])表示将c列和d列分别设置为一级行索引和二级行索引。
默认情况下会将设置为索引的原数据删除,可以设置drop=False参数保留。
frame.set_index(['c','d'],drop=False)
reset_index的功能跟set_index刚好相反,层次化索引被转回列中。
frame2.reset_index()
合并数据集
数据库风格的DataFrame合并
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
'data2': range(3)})
创建两个DataFrame。
通过merge将两个合并起来,它们有共同列key。
df1.merge(df2)
pd.merge(df1,df2)
两种形式效果一致。
如果没有指定,默认将重叠列的列名当作键,通过on参数可以指定。
pd.merge(df1,df2,on='key')
如果两个列名不同,可以分别指定。
df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],^M
'data1': range(7)})
df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'],^M
'data2': range(3)})
pd.merge(df3,df4,left_on='lkey',right_on='rkey')
可以看到c和d消失了,因为默认情况下merge做的是内连接,即取交集,外连接才是取并集。
pd.merge(df1,df2,how='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)})
pd.merge(df1,df2,on='key',how='left')
可以看到df1de key列中所有元素都出现了,而df2中的d元素并没有出现。
多对多连接产生的是笛卡尔积,如数据1有3个b,数据2有2个b,连接起来就有6个b了。
pd.merge(df1,df2,how='inner')
若要根据多个键合并,on参数中传入列名列表即可。
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')
有多个相同列的DataFrame进行合并时,如果只匹配一个列,其它列会重叠,这种情况下会在重叠列后面自动加上后缀以区分。
pd.merge(left,right,on='key1')
如之前的left和right,仅对key1列进行匹配,key2列会重叠。
也可以通过suffixes参数自行设置后缀。
pd.merge(left,right,on='key1',suffixes=('_left','_right'))
merge方法的参数
索引上的合并
如果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'])
pd.merge(left1,right1,left_on='key',right_index=True)
将right1的索引作为连接键。
默认方法是內连接,通过改how参数可以改成外连接。
pd.merge(left1,right1,left_on='key',right_index=True,how='outer')
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'])
连接键是第一个DataFrame的key1列和key2列以及righth的层次化索引。
pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True,how='outer')
第一个是內连接,第二个是外连接。
如果两个DataFrame都是层次化所以,那么可以直接设置两个连接键都是index,DataFrame有个join方法是应用于这个场景的,如果两个DataFrame中不存在重叠的列时可以使用。
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'])
pd.merge(left2,right2,how='outer',left_index=True,right_index=True)
left2.join(right2,how='outer')
上面两种方法得出的结果是相同的。
DataFrame的join方法默认使用左连接,
left1.join(right1,on='key')
可以向join中传入一组DataFrame,将多个DataFrame合并起来。
another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],
index=['a', 'c', 'e', 'f'],
columns=['New York','Oregon'])
left2.join([right2,another])
left2.join([right2,another],how='outer')
轴向连接
arr = np.arange(12).reshape((3,4)) #创建一个三行四列的数组
np.concatenate([arr,arr],axis=1) #将两个数组横向拼接起来
np.concatenate([arr,arr],axis=0) #将两个数组纵向拼接起来
利用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'])
pd.concat([s1,s2,s3])
默认axis=0,所以是纵向合并起来,若传入axis=1,则会变成一个DataFrame。
pd.concat([s1,s2,s3],axis=1)
s4 = pd.concat([s1,s3]) #将s1和s3纵向合并起来
pd.concat([s1,s4],axis=1) #将s1和s4横向合并起来,默认方式是outer
pd.concat([s1,s4],axis=1,join='inner') #改为内连接
只有两个DataFrame重叠的部分才会合并。
也可以通过join_axes参数指定合并的索引。
pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
可以在结果中建立层次化索引,来区分数据是来自那个DataFrame的。
result = pd.concat([s1,s2,s3],keys=['one','two','three'])
result.unstack()
令axis=1,对多个Series进行合并,keys参数会变成DataFrame的列名。
pd.concat([s1,s2,s3],axis=1,keys=['one','two','three'])
上面的逻辑对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'])
pd.concat([df1,df2],axis=1,keys=['level1','level2'])
创建两个DataFrame,横向合并起来,并设置列索引的一级分层。
pd.concat({'level1':df1,'level2':df2},axis=1)
得到的结果和上面的相同。
DataFrame的行索引不包括任何相关数据时,传入参数ignore_index=True。
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'])
pd.concat([df1,df2],ignore_index=True)
concat方法的参数。
合并重叠数据
a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],
index=['f', 'e', 'd', 'c', 'b', 'a'])
b = pd.Series(np.arange(len(a), dtype=np.float64),
index=['f', 'e', 'd', 'c', 'b', 'a'])
b[-1] = np.nan
创建两个Series,将b的最后一个元素设为缺失。
np.where(pd.isnull(a),b,a)
pd.isnull(a)返回了一个布尔型Series,如果元素为True,则选择b中对应位置的数据,False的话选a中对应的数据。
Series有一个combine_firse方法,实现相同的功能,还带有pandas的数据对齐。
b[:-2].combine_first(a[2:])
将b[:-2]和a[2:]合并,自动对索引进行对齐。
对DataFrame也能使用
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.]})
df1.combine_first(df2)
行列索引相同时df1中缺失而df2存在,取df2的数据。
重塑和轴向旋转
重塑层次化索引
data = pd.DataFrame(np.arange(6).reshape((2, 3)),
index=pd.Index(['Ohio','Colorado'], name='state'),
columns=pd.Index(['one', 'two', 'three'],
name='number'))
创建一个两行三列的数据,并设置好行索引和行索引列名,设置好列索引和列索引行名。
通过stack方法可以将列索引转置为行索引的二级分层。
unstack方法是逆方法。
默认情况下unstack方法将行索引列的最内层转置为列索引(stack方法也一样),可以通过传入指定索引层来转置。
result = data.stack()
result.unstack(0)
传入0表示将最外层的行索引转置为列索引。
或者传入指定索引列的列名。
result.unstack('state')
将state列转置为列索引。
二级索引的全部分类可能分散在各分组中,此时unstack操作会选取所有分类进行转置,所以会出现缺失值。
s1 = pd.Series([0,1,2,3],index=['a','b','c','d'])
s2 = pd.Series([4,5,6],index=['c','d','e'])
data2 = pd.concat([s1,s2],keys=['one','two']) #将两个Series纵向合并起来,并在行索引列前面加一层索引,one、two分别表示数据来自s1和s2
data2.unstack() #通过unstack方法将第二层索引转置称列索引
stack方法默认滤除缺失值,故逆运算可以还原成原来的Series。
设置dropna=False可以不滤除缺失值。
data2.unstack().stack(dropna=False)
df = pd.DataFrame({'left':result,'right':result+5},
columns=pd.Index(['left','right'],name='side'))
df.unstack('state')
通过unstack方法将df中的行索引列state转置为列索引的最内层。
再调用stack,也可以指定列索引行进行转置。
将长格式旋转为宽格式
data = pd.read_csv('examples/macrodata.csv') #读取文件
data.head()
periods = pd.PeriodIndex(year=data.year,quarter=data.quarter,name='date')
columns = pd.Index(['realgdp','infl','unemp'],name='item') #建立可重用索引
data = data.reindex(columns=columns) #重建data,将列索引改成columns中的内容
data.index = periods.to_timestamp('D','end')
ldata = data.stack().reset_index().rename(columns={0:'value'})
data.stack()操作是将列索引行item转置成行索引的二层索引。
data.stack().reset_index()操作是将所有行索引全部转换成列索引。
最后一步rename(columns={0:'value'},是将列0的列名改为value。
最终得到的结果。
使用DataFrame的pivot方法可以转换回来。
pivoted = ldata.pivot('date','item','value')
date列转为行索引,item列转为列索引,value转为值。
ldata['value2'] = np.random.randn(len(ldata)) #在ldata中创建一个新列
新的ldata有两列value,再次调用pivot,不传入第三个参数。
pivoted = ldata.pivot('date','item')
还有一种可以达到相同结果的操作,先将ldata中的date和item列设为行索引的一二级,再通过unstack方法将item索引列转置到列索引中。
unstacked = ldata.set_index(['date','item']).unstack('item')
将宽格式旋转为长格式
df = pd.DataFrame({'key': ['foo', 'bar', 'baz'],
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]})
melted = pd.melt(df,['key'])
pandas.melt是旋转DataFrame的逆运算,它会合并多个列产生一个长的DataFrame,需要指定某列作为分组指标。
使用pivot方法,可以转换回来
reshaped = melted.pivot('key','variable','value')
reshaped.reset_index()
可以指定列的子集,作为值的列。
pd.melt(df,id_vars=['key'],value_vars=['A','B'])
可以不用分组指标
pd.melt(df,value_vars=['A','B','C'])
pd.melt(df,value_vars=['key','A','B'])
本笔记主要内容来自:https://www.jianshu.com/p/cfc035bae567