笔记|数据分析之pandas基础----聚合与合并(二)

数据合并

索引上的合并

**比如DataFrame中连接键位于其索引中的情况,传入left_index=Trueright_index=True以说明索引应该被用作连接键:

In [62]: left1 = DataFrame({'key':['a','b','a','a','b','c'],'value':range(6)})

In [63]: right1 = DataFrame({'group_val':[3.5, 7]}, index=['a','b'])

In [64]: left1
Out[64]:
  key  value
0   a      0
1   b      1
2   a      2
3   a      3
4   b      4
5   c      5

In [65]: right1
Out[65]:
   group_val
a        3.5
b        7.0

In [71]: pd.merge(left1,right1,left_on='key',right_index=True)
Out[71]:
  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

上面例子中将left1key列与right1中的行索引进行连接。merge函数默认是求连接键的交集。可以通过修改how参数来实现并集。

In [82]: pd.merge(left1,right1,left_on='key',right_index=True,how='outer')
Out[82]:
  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

与数学中的交集与并集和合并中的交集并集还有有区别的,在笔记|数据分析之pandas基础----聚合、合并与重塑(一)中已经分析过

如果是对于层次化索引的数据

In [83]: lefth = DataFrame({'key1':['Ohio','Ohio','Ohio','Nevada','Nevada'],'key2':[2000,2001,2002,
    ...: 2001,2002],'data':np.arange(5.)})

In [84]: righth = DataFrame(np.arange(12).reshape((6,2)),index=[['Nevada','Nevada','Ohio','Ohio','O
    ...: hio','Ohio'],[2001,2000,2000,2000,2001,2002]],columns=['event1','event2'])

In [85]: lefth
Out[85]:
     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

In [86]: righth
Out[86]:
             event1  event2
Nevada 2001       0       1
       2000       2       3
Ohio   2000       4       5
       2000       6       7
       2001       8       9
       2002      10      11

这种情况下,你必须以列表的形式指明用作合并键的多个列:

In [89]: pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
Out[89]:
     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

**要将rightf的层次化索引合并进来需要2列数据,lefth中的key1,key2正好可以对其进行合并,所以left_on = ['key1', 'key2']

也可以同时合并双方的索引

In [90]: left2 = DataFrame([[1,2],[3,4],[5,6]],index=['a','c','e'], columns=['Ohio','Nevada'])

In [91]: right2 = DataFrame([[7,8],[9,10],[11,12],[13,14]],index=['b','c','d','e'],columns=['Missou
    ...: ri','Alabama'])

In [92]: left2
Out[92]:
   Ohio  Nevada
a     1       2
c     3       4
e     5       6

In [93]: right2
Out[93]:
   Missouri  Alabama
b         7        8
c         9       10
d        11       12
e        13       14

In [94]: pd.merge(left2,right2, how='outer',left_index=True,right_index=True)
Out[94]:
   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

通过join方法进行合并

join函数可用于合并多个带有相同或相似索引的DataFrame对象而不管它们之间有没有重叠的列

In [95]: left2.join(right2,how='outer')
Out[95]:
   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

还可以向join函数传入一组DataFrame对象

In [96]: another = DataFrame([[7,8],[9,10],[11,12],[16,17]],index=['a','c','e','f'],columns=['New Y
    ...: ork','Oregon'])

In [97]: left2.join([right2,another])
Out[97]:
   Ohio  Nevada  Missouri  Alabama  New York  Oregon
a     1       2       NaN      NaN         7       8
c     3       4       9.0     10.0         9      10
e     5       6      13.0     14.0        11      12

默认是交集,所以a,b,c,d,ea,c,e,f合并后,索引就变成a,c,e

轴向连接

pandas还有另一种合并运算:Numpy的```concatenation````函数:

In [98]: arr = np.arange(12).reshape(3,4)

In [99]: arr
Out[99]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [100]: np.concatenate([arr,arr],axis=1)
Out[100]:
array([[ 0,  1,  2,  3,  0,  1,  2,  3],
       [ 4,  5,  6,  7,  4,  5,  6,  7],
       [ 8,  9, 10, 11,  8,  9, 10, 11]])

这个很好理解,axis=1合并列。

而对于pandas对象,带有标签的轴使你能够进一步推广数组的连接运算。教材中给出了三个需要思考的点:

  • 如果各对象其他轴上的索引不同,那些轴应该做并集还是交集?
  • 结果对象中的分组需要各不相同吗?
  • 用于连接的轴重要吗?

pandas的concat函数为这些问题提供了可靠的解决方案。
如下例,假设有三个没有重叠索引的Series:

In [102]: s1 = Series([0,1],index=['a','b'])

In [103]: s2 = Series([2,3,4], index=['c','d','e'])

In [104]: s3 = Series([5,6], index=['f','g'])

我们可以通过concat函数将三个对象粘合在一起:

In [108]: pd.concat([s1,s2,s3])
Out[108]:
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

concat函数默认axis=0,所以会合并行。
从结果中可以看到没有出现重叠的情况,再看下面的例子:

In [115]: pd.concat([s1,s4], axis=1, sort=False)
Out[115]:
     0  1
a  0.0  0
b  1.0  5
f  NaN  5
g  NaN  6
In [117]: pd.concat([s1,s4], axis=1, sort=False, join='inner')
Out[117]:
   0  1
a  0  0
b  1  5

因为设置了join=inner交集,所以f、g标签消失了。

你可以通过join_axes指定要在其他轴上使用的索引:

In [118]: pd.concat([s1,s4], axis=1, join_axes=[['a','c','b','e']])
Out[118]:
     0    1
a  0.0  0.0
c  NaN  NaN
b  1.0  5.0
e  NaN  NaN

如果需要知道合并后的数据来源,我们可以创建一个层次化索引,使用keys参数可以做到:

In [119]: result = pd.concat([s1, s1, s3], keys = ['one','two','three'])

In [120]: result
Out[120]:
one    a    0
       b    1
two    a    0
       b    1
three  f    5
       g    6
dtype: int64

result转为DataFrame

In [121]: result.unstack()
Out[121]:
         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的列头:

In [129]: pd.concat([s1, s2, s3], keys = ['one','two','three'], axis=1, sort=False)
Out[129]:
   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

这里axis=1行向合并,keys也受到了它的影响变成了DataFrame的列头。

同样DataFrame也是如此:

In [130]: df1 = DataFrame(np.arange(6).reshape(3,2), index=['a','b','c'], columns=['one','two'])

In [131]: df2 = DataFrame(5 + np.arange(4).reshape(2, 2), index=['a','c'], columns=['three','four'])

In [133]: pd.concat([df1, df2], axis=1, keys=['level1','level2'], sort=False)
Out[133]:
  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选项的值:

In [138]: pd.concat({'level1':df1, 'level2':df2}, axis=1, sort=False)
Out[138]:
  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

此外还有两个用于管理层次化索引创建方式的参数:

In [139]: pd.concat([df1,df2], axis=1,sort=False, keys=['level1','level2'],names=['upper','lower'])
     ...:
Out[139]:
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

concat函数的参数


WechatIMG34.png

合并重叠数据

如果遇到比较复杂的两个数据集需要合并,里面会遇到很多重叠的情况,那么用NumPy的where函数是最佳选择:

In [140]: a = Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan],index=['f','e','d','c','b','a'])

In [141]: b = Series(np.arange(len(a), dtype=np.float64), index=['f','e','d','c','b','a'])

In [142]: b[-1] = np.nan

In [143]: a
Out[143]:
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64

In [144]: b
Out[144]:
f    0.0
e    1.0
d    2.0
c    3.0
b    4.0
a    NaN
dtype: float64

比方说遇到这种索引全都重叠的两组数据集,并且merge函数不能对Series对象进行合并的情况下:

In [155]: np.where(pd.isnull(a),b,a)
Out[155]: array([0. , 2.5, 2. , 3.5, 4.5, nan])

where函数本来是返回一个数组,判断a中元素是否为NaN,是返回b否则返回a。正好对两组数据进行了合并,这种情况比较少不过还是要了解下。奇怪的是这里和教材不同,返回了一个ndarray

Series有一个combine_first方法,也可以实现一样的功能,而且会对数据对齐:

In [162]: b[:-2].combine_first(a[2:])
Out[162]:
a    NaN
b    4.5
c    3.0
d    2.0
e    1.0
f    0.0
Name: b, dtype: float64

同样combine_first也可以用在DataFrame上:

In [164]: df1 = DataFrame({'a':[1, np.nan, 5, np.nan],'b':[np.nan, 2, np.nan, 6],'c':range(2, 18, 4
     ...: )})

In [165]: df2 = DataFrame({'a':[5, 4, np.nan, 3, 7],'b':[np.nan, 3, 4, 6, 8]})

In [166]: df1.combine_first(df2)
Out[166]:
     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

在两组数据正好可以互相填补的情况下很适合用combine_first

总结

今天学习了merge函数的后半部分功能:

  • DataFrame对象行索引的合并
  • 也可以对层次化索引进行合并,因为有层次化索引的关系会有两列索引,所以相对应的要提供2列数据来对它合并。

通过join方法进行合并,它可以对多个相同或者相似索引的DataFrame进行合并。

学习了concat函数对Series对象的一些合并操作,它能控制Series横向或者纵向合并。可以对合并后的数据添加层次化索引,同样对DataFrame也可以进行这样的合并。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352