数据分析 第二章
数据分析 第二节 数据重构
数据的合并
层次化索引能以低维度形式处理高维度数据。
层次化索引在数据重塑和基于分组的操作(如透明表生成)中扮演着重要的角色。
例子:可以通过unstack方法将这段数据重新安排到一个DataFrame中:
In [9]: 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]]
In [10]; data
Out[10]:
a 1 -0.204708
2 0.478943
3 -0.519439
b 1 -0.555730
3 1.965781
c 1 1.393406
2 0.092908
d 2 0.281746
3 0.769023
dtype: float64
In [16]: data.unstack()
Out[16]:
1 2 3
a -0.204708 0.478943 -0.519439
b -0.555730 NaN 1.965781
c 1.393406 0.092908 NaN
d NaN 0.281746 0.769023
unstack的逆运算是stack:
In [17]: data.unstack().stack()
合并数据集
pandas对象中的数据可以通过一些方式进行合并:
1、pandas.merge可根据一个或多个键将不同DataFrame的行连接起来。
2、pandas.concat可以沿着一条轴将多个对象堆叠到一起。
3、实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值。
数据集的合并(merge)或连接(join)运算是通过一个或多个键将行连接起来的。
merge函数
In [35]: df1 = pd.DataFrame({'Key':['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7)})
In [36]: df2 = pd.DataFrame({'key': ['a', 'b', 'd'], 'data2': range(3)})
In [37]:df1
out[37];
data1 key
0 0 b
1 1 b
2 2 a
3 3 c
4 4 a
5 5 a
6 6 b
In [38]: df2
Out[38]:
data2 key
0 0 a
1 1 b
2 2 d
#多对一的合并。df1中的数据有多个被标记为a和b的行,而df2中key列的每个值仅对一行。(使用key连接到一起,有相对应的key,则横向连接到一起)
#对这些对象调用merge即可得:
In [39]: pd.merge(df1, df2)
Out[39]:
data1 key data2
0 0 b 1
1 1 b 1
2 6 b 1
3 2 a 0
4 4 a 0
5 5 a 0
如果没有指明要用哪个列进行连接,merge就会将重叠列的列名当做键。
#指明相应的列进行连接
In [40]: pd.merge(df1, df2, on='key')
Out[40]:
data1 key data2
0 0 b 1
1 1 b 1
2 6 b 1
3 2 a 0
4 4 a 0
5 5 a 0
如果两个对象的列名不同,也可以分别进行指定:
(命名的列名不同,但是对象所对应的值时相同的)
In [41]: df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'data1':range(7)]})
In [42]: df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 'data2': range(3)})
In [43]: pd.merge(df3, df4, left_on='1key', right_on='rkey')
Out[43]:
data1 lkey data2 rkey
0 0 b 1 b
1 1 b 1 b
2 6 b 1 b
3 2 a 0 a
4 4 a 0 a
5 5 a 0 a
# c和d以及与之相应的数据消失了。
默认情况下,merge做的是“内连接”;结果中的键是交集。其他方式有“left”、“right”、“outer”。
内连接:结果是键的交集。
外连接:求取的是键的并集,组合了左连接和右连接的效果。
#例子:外连接,其中一个数据索引没有相对应的值就用NaN表示
In [44]: pd.merge(df1, df2, how='outer')
Out[44]:
data1 key data2
0 0.0 b 1.0
1 1.0 b 1.0
2 6.0 b 1.0
3 2.0 a 0.0
4 4.0 a 0.0
5 5.0 a 0.0
6 3.0 c NaN
7 NaN d 2.0
merge函数选项总结:
选项 | 说明 |
---|---|
inner | 使用两个表都有的键 |
left | 使用左表中所有的键 |
right | 使用右表中所有的键 |
outer | 使用两个表中所有的键 |
多对多连接产生的是行的笛卡尔积。例如左边的DataFrame有3个“b”行,右边的有2个,所以最终结果中就有6个“b”行。连接方式只影响出现在结果中的不同的键的值。
对于重复列名的处理,使用merge的suffixes选项,用于指定附加到左右两个DataFrame对象的重复列名上的字符串:
In [55]: pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
Out[55]:
key1 key2_left lval key2_right rval
……
……
merge函数的参数
参数 | 说明 |
---|---|
left | 参与合并的左侧DataFrame |
right | 参与合并的右侧DataFrame |
how | “inner”、“outer”、“left”、“right"其中之一。 默认为"inner” |
on | 用于连接的列名。必须存在于左右两个DataFrame对象中。如未指定,则以left和right列名的交集作为连接键 |
left_on | 左侧DataFrame中用作连接键的列 |
right_on | 右侧DataFrame中用作连接键的列 |
left_index | 将左侧的行索引用作其连接键 |
right_index | 类似于left_index |
sort | 根据连接键对合并后的数据进行排序,默认为True(升序) |
suffixes | 字符串值元组,用于追加到重叠列名的末尾,默认为(’_x’, ‘_y’)。 |
copy | 设置为False,可以在某些特殊情况下避免将数据复制到结果数据结构中。默认总是复制 |
轴向连接(纵向连接)
concat函数
#假设有三个没有重复索引的Series
In [82]: s1 = pd.Series([0, 1], index=['a', 'b'])
In [83]: s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])
In [84]: s3 = pd.Series([5, 6], index=['f', 'g'])
#对这些对向调用concat可以将值和索引粘和在一起:
In [85]: pd.concat([s1, s2, s3])
Out[85]:
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是列):
#生成DataFrame的情况
In [86]: pd.concat([s1, s2, s3], axis=1)
Out[86]:
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
使用concat函数,传入join='inner’即可得到它们的交集:
In [89]: pd.concat([s1, s4], axis=1)
Out[89]:
0 1
a 0.0 0
b 1.0 1
f NaN 5
g NaN 6
In [90]: pd.concat([s1, s4], axis=1, join='inner')
Out[90]:
0 1
a 0 0
b 1 1
可以通过join_axes指定要在其它轴上使用的索引:
In [91]: pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'e']])
Out[91]:
0 1
a 0.0 0.0
c NaN NaN
b 1.0 1.0
e NaN NaN
使用keys参数可以在连续轴上创建一个层次化索引。
In [92]:result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three'])
In [93]: result
Out[93]:
one a 0
b 1
two a 0
b 1
three f 5
g 6
dtype: int64