ch8_01 数据规整:聚合、合并、重塑

Pandas进阶:数据重塑与合并
本文深入探讨Pandas库中数据重塑与合并的高级技巧,包括层次化索引的使用、数据集的合并与连接,以及按索引进行的合并操作。通过实例演示如何高效地操作和分析复杂数据结构。

Jupyter notebook】阅读模式,更好的体验!

  • 在许多应用中,数据可能分散在许多文件或数据库中,存储的形式也不利于分析。本章关注可以聚合、合并、重塑数据的方法。
import pandas as pd
import numpy as np

8.1 层次化索引

  • 层次化索引(hierarchical indexing)能在一个轴上拥有多个(两个以上)索引级别。抽象点说,它使你能以低维度形式处理高维度数据。
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.851062
   2    0.498509
   3    1.552038
b  1    0.839059
   3   -0.765026
c  1   -1.431162
   2   -1.587057
d  2   -1.012728
   3    1.318710
dtype: float64
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['a']
1    1.851062
2    0.498509
3    1.552038
dtype: float64
data['b':'c']
b  1    0.839059
   3   -0.765026
c  1   -1.431162
   2   -1.587057
dtype: float64
data.loc[['b','d']]
b  1    0.839059
   3   -0.765026
d  2   -1.012728
   3    1.318710
dtype: float64
  • 也可以进行内层选取
data[:,2]
a    0.498509
c   -1.587057
d   -1.012728
dtype: float64
data['a'][2]
0.4985087352895496
  • 层次化索引在数据重塑和基于分组的操作(如透视表生成)中扮演着重要的角色。例如,可以通过unstack方法将这段数据重新安排到一个DataFrame中:
data.unstack()
123
a1.8510620.4985091.552038
b0.839059NaN-0.765026
c-1.431162-1.587057NaN
dNaN-1.0127281.318710
  • unstack()的逆运算是stack()
data.unstack().stack()
a  1    1.851062
   2    0.498509
   3    1.552038
b  1    0.839059
   3   -0.765026
c  1   -1.431162
   2   -1.587057
d  2   -1.012728
   3    1.318710
dtype: float64
  • 对于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
OhioColorado
GreenRedGreen
a1012
2345
b1678
291011
  • 各层都可以有名字(可以是字符串,也可以是别的Python对象)。如果指定了名称,它们就会显示在控制台输出中:
frame.index.names = ['key1','key2']
frame.columns.names = ['state','color']
frame
stateOhioColorado
colorGreenRedGreen
key1key2
a1012
2345
b1678
291011
frame['Ohio']
colorGreenRed
key1key2
a101
234
b167
2910

重排与分级排序

  • 需要重新调整某条轴上各级别的顺序,或根据指定级别上的值对数据进行排序。swaplevel接受两个级别编号或名称,并返回一个互换了级别的新对象(但数据不会发生变化):
frame
stateOhioColorado
colorGreenRedGreen
key1key2
a1012
2345
b1678
291011
frame.swaplevel('key1', 'key2')
stateOhioColorado
colorGreenRedGreen
key2key1
1a012
2a345
1b678
2b91011
  • sort_index则根据单个级别中的值对数据进行排序。交换级别时,常常也会用到sort_index,这样最终结果就是按照指定顺序进行字母排序了:
frame.sort_index(level=1)
stateOhioColorado
colorGreenRedGreen
key1key2
a1012
b1678
a2345
b291011
frame.swaplevel(0,1).sort_index(level=0)
stateOhioColorado
colorGreenRedGreen
key2key1
1a012
b678
2a345
b91011

根据级别汇总统计

  • 许多对DataFrame和Series的描述和汇总统计都有一个level选项,它用于指定在某条轴上求和的级别
frame.sum(level=1)
stateOhioColorado
colorGreenRedGreen
key2
16810
2121416
frame.sum(level=0)
stateOhioColorado
colorGreenRedGreen
key1
a357
b151719
frame.sum(level=1,axis=1)
colorGreenRed
key1key2
a121
284
b1147
22010

利用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
abcd
007one0
116one1
225one2
334two0
443two1
552two2
661two3
#set_index函数会将其一个或多个列转换为行索引,并创建一个新的DataFrame:
frame2 = frame.set_index(['c','d'])
frame2
ab
cd
one007
116
225
two034
143
252
361
#默认情况下,那些列会从DataFrame中移除,但也可以将其保留下来:
frame.set_index(['c','d'],drop=False)
abcd
cd
one007one0
116one1
225one2
two034two0
143two1
252two2
361two3
  • reset_index()正好与set_index()相反,层次化的索引会被转移到列里面
frame2.reset_index()
cdab
0one007
1one116
2one225
3two034
4two143
5two252
6two361

8.2 合并数据集

pandas对象中的数据可以通过一些方式进行合并:
  • pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来。它实现的就是数据库的join操作。
  • pandas.concat可以沿着一条轴将多个对象堆叠到一起。
  • 实例方法combine_first可以将重复数据拼接在一起,用一个对象中的值填充另一个对象中的缺失值。

pandas.merge()

  • 数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的。这些运算是关系型数据库(基于SQL)的核心.
df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],'data1': range(7)})
df2 = pd.DataFrame({'key':['a','b','c'],'data2':range(3)})
df1
keydata1
0b0
1b1
2a2
3c3
4a4
5a5
6b6
df2
keydata2
0a0
1b1
2c2
pd.merge(df1,df2)
keydata1data2
0b01
1b11
2b61
3a20
4a40
5a50
6c32
  • 上述代码并没有指明使用哪个列进行连接,这时候默认是将重叠的列名当作键。不过最好指明
pd.merge(df1,df2,on='key')
keydata1data2
0b01
1b11
2b61
3a20
4a40
5a50
6c32
  • 如果两个对象的列名不同,也可以分别进行指定:
df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})
df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'],  'data2': range(3)})
df3
lkeydata1
0b0
1b1
2a2
3c3
4a4
5a5
6b6
df4
rkeydata2
0a0
1b1
2d2
pd.merge(df3,df4,left_on = 'lkey', right_on = 'rkey')
lkeydata1rkeydata2
0b0b1
1b1b1
2b6b1
3a2a0
4a4a0
5a5a0
  • 上述代码的结果里面c和d以及与之相关的数据消失了。默认情况下,merge做的是“内连接”;结果中的键是交集。
  • 其他方式还有"left"、“right"以及"outer”。外连接求取的是键的并集,组合了左连接和右连接的效果:
pd.merge(df1, df2, how='outer')
keydata1data2
0b01
1b11
2b61
3a20
4a40
5a50
6c32

  • 要根据多个键进行合并,传入一个由列名组成的list 即可
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')
key1key2lvalrval
0fooone1.04.0
1fooone1.05.0
2footwo2.0NaN
3barone3.06.0
4bartwoNaN7.0
left
key1key2lval
0fooone1
1footwo2
2barone3
right
key1key2rval
0fooone4
1fooone5
2barone6
3bartwo7
  • 对于合并运算需要考虑的对重复列名的处理。merge有一个的suffixes选项,用于指定附加到左右两个DataFrame对象的重叠列名上的字符串:
pd.merge(left, right, on = 'key1')
key1key2_xlvalkey2_yrval
0fooone1one4
1fooone1one5
2footwo2one4
3footwo2one5
4barone3one6
5barone3two7
pd.merge(left, right,on='key1',suffixes=('_left','_right'))
key1key2_leftlvalkey2_rightrval
0fooone1one4
1fooone1one5
2footwo2one4
3footwo2one5
4barone3one6
5barone3two7
  • merge的参数如下:
    1
    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
keyvalue
0a0
1b1
2a2
3a3
4b4
5c5
right1
group_val
a3.5
b7.0
pd.merge(left1,right1,left_on='key',right_index=True)
keyvaluegroup_val
0a03.5
2a23.5
3a33.5
1b17.0
4b47.0
  • 默认的merge方法是求取连接键的交集,因此你可以通过外连接的方式得到它们的并集:
pd.merge(left1,right1,left_on='key',right_index=True,how='outer')
keyvaluegroup_val
0a03.5
2a23.5
3a33.5
1b17.0
4b47.0
5c5NaN
  • 对于层次化索引的数据,索引的合并默认是多键合并:
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
key1key2data
0Ohio20000.0
1Ohio20011.0
2Ohio20022.0
3Nevada20013.0
4Nevada20024.0
righth
event1event2
Nevada200101
200023
Ohio200045
200067
200189
20021011
  • 这种情况下,你必须以列表的形式指明用作合并键的多个列(注意用how='outer’对重复索引值的处理):
pd.merge(lefth, righth, left_on=['key1','key2'], right_index=True)
key1key2dataevent1event2
0Ohio20000.045
0Ohio20000.067
1Ohio20011.089
2Ohio20022.01011
3Nevada20013.001
pd.merge(lefth, righth, left_on=['key1','key2'], right_index=True,how='outer')
key1key2dataevent1event2
0Ohio20000.04.05.0
0Ohio20000.06.07.0
1Ohio20011.08.09.0
2Ohio20022.010.011.0
3Nevada20013.00.01.0
4Nevada20024.0NaNNaN
4Nevada2000NaN2.03.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
OhioNevada
a1.02.0
c3.04.0
e5.06.0
right2
MissouriAlabama
b7.08.0
c9.010.0
d11.012.0
e13.014.0
pd.merge(left2, right2, how='outer', left_index=True, right_index=True)
OhioNevadaMissouriAlabama
a1.02.0NaNNaN
bNaNNaN7.08.0
c3.04.09.010.0
dNaNNaN11.012.0
e5.06.013.014.0
  • DataFrame还有一个便捷的join实例方法,它能更为方便地实现按索引合并。它还可用于合并多个带有相同或相似索引的DataFrame对象,但要求没有重叠的列。在上面那个例子中,我们可以编写:
left2.join(right2,how='outer')
OhioNevadaMissouriAlabama
a1.02.0NaNNaN
bNaNNaN7.08.0
c3.04.09.010.0
dNaNNaN11.012.0
e5.06.013.014.0
right2.join(left2,how='outer')
MissouriAlabamaOhioNevada
aNaNNaN1.02.0
b7.08.0NaNNaN
c9.010.03.04.0
d11.012.0NaNNaN
e13.014.05.06.0
# 它还支持传递连接的索引
left1.join(right1, on='key')
keyvaluegroup_val
0a03.5
1b17.0
2a23.5
3a33.5
4b47.0
5c5NaN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值