python3读取多行数据合并_python3 数据规整化:清理、转换、合并、重塑(一)

一.合并数据集

pandas对象中的数据可以通过一些内置的方式进行合并:

1)pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来。SQL或其他关系型数据库的用户对此应该会比较熟悉,因为它实现的就是数据库的连接操作。

2)pandas.concat可以沿着一条轴将多个对象堆叠到一起。

3)实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值。

下面分别对它们进行讲解,并给出一些例子。

1.数据库风格的DataFrame合并

数据集的合并(merge)或连接(join)运算是通过一个或多个键将行链接起来的。这些运算时关系型数据库的核心。pandas的merge函数是对数据应用这些算法的主要切入点。

下面一个简单的例子开始:

In [1]: from pandas import DataFrame

In [2]: import pandas as pd

In [3]: df1=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})

In [4]: df2=DataFrame({'key':['a','b','d'],'data2':range(3)})

In [5]: df1

Out[5]:

key data1

0   b     0

1   b     1

2   a     2

3   c     3

4   a     4

5   a     5

6   b     6

In [6]: df2

Out[6]:

key data2

0   a     0

1   b     1

2   d     2

这是一种多对一的合并。df1中的数据有多个被标记为a和b的行,而df2中key列的每个值则仅对应一行。对这些对象调用merge即可得到:

In [7]: pd.merge(df1,df2)

Out[7]:

key data1 data2

0  b       0       1

1  b       1       1

2  b       6       1

3  a       2       0

4  a       4       0

5  a       5       0

注意,这里并没有指明要用哪个列进行连接。如果没有指定,merge就会将重叠列的列名当做键。不过,最好显式指定一下:

In [8]: pd.merge(df1,df2,on='key')

Out[8]:

key data1 data2

0    b     0        1

1    b     1        1

2    b     6        1

3    a     2        0

4    a     4        0

5    a     5        0

如果两个对象的列名不同,也可以分别进行指定:

In [9]: df3=DataFrame({'lkey':['b','b','a','c','a','a','b'],'data1':range(7)})

In [10]: df4=DataFrame({'rkey':['a','b','d'],'data2':range(3)})

In [11]: pd.merge(df3,df4,left_on='lkey',right_on='rkey')

Out[11]:

lkey data1 rkey data2

0     b     0        b      1

1     b     1        b      1

2     b     6        b      1

3     a     2        a      0

4     a     4        a      0

5     a     5        a      0

可以看到,结果里面c和d以及与之相关的数据消失了。默认情况下,merge做的是"inner"连接;结果中的键是交集。其他方式还有"left"、“right”以及"outer"。外连接求取的是键的并集,组合了左连接和右连接的效果:

In [14]: pd.merge(df1,df2,how='outer')

Out[14]:

key data1 data2

0     b    0.0    1.0

1     b    1.0    1.0

2     b     6.0   1.0

3     a     2.0   0.0

4     a     4.0   0.0

5     a     5.0   0.0

6     c     3.0   NaN

7     d    NaN  2.0

多对多的合并操作非常简单,无需额外的工作。如下所示:

In [15]: df1=DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})

In [16]: df2=DataFrame({'key':['a','b','a','b','d'],'data2':range(5)})

In [17]: df1

Out[17]:

key data1

0    b    0

1    b    1

2    a    2

3    c    3

4    a    4

5    b    5

In [18]: df2

Out[18]:

key data2

0    a    0

1    b    1

2    a    2

3    b    3

4    d    4

In [19]: pd.merge(df1,df2,on='key',how='left')

Out[19]:

key data1 data2

0    b     0       1.0

1    b     0       3.0

2    b     1       1.0

3    b     1       3.0

4    a    2        0.0

5    a    2        2.0

6    c    3       NaN

7    a    4       0.0

8    a    4       2.0

9    b    5       1.0

10  b    5       3.0

多对多连接产生的是行的笛卡尔积。由于左边的DataFrame有3个"b"行,右边的有2个,所以最终结果中就有6个"b"行。连接方式只影响出现在结果中的键:

In [20]: pd.merge(df1,df2,how='inner')

Out[20]:

key data1 data2

0   b     0        1

1   b     0        3

2   b     1        1

3   b     1        3

4   b     5        1

5   b     5        3

6   a     2        0

7   a     2        2

8   a     4        0

9   a     4        2

要根据多个键进行合并,传入一个由列名组成的列表即可:

In [21]: left=DataFrame({'key1':['calvin','calvin','kobe'],'key2':['one','two',

...: 'one'],'lval':[1,2,3]})

In [22]: right=DataFrame({'key1':['calvin','calvin','kobe','kobe'],'key2':['one

...: ','one','one','two'],'rval':[4,5,6,7]})

In [23]: pd.merge(left,right,on=['key1','key2'],how='outer')

Out[23]:

key1 key2 lval rval

0 calvin one 1.0 4.0

1 calvin one 1.0 5.0

2 calvin two 2.0 NaN

3 kobe one 3.0 6.0

4 kobe two NaN 7.0

结果中会出现哪些键组合取决于所选的合并方式,我们可以这样来理解:多个键形成一系列元组,并将其当做单个连接键(当然,实际上并不是这么回事)。

注意:在进行列-列连接时,DataFrame对象中的索引会被丢弃。

对于合并运算需要考虑的最后一个问题是对重复列名的处理。虽然我们可以手工处理列名重叠的问题,但merge有一个更实用的suffixes选项,用于指定附加到左右两个DataFrame对象的重叠列名上的字符串:

In [8]: pd.merge(left,right,on='key1')

Out[8]:

key1 key2_x   lval key2_y rval

0 calvin   one       1       one     4

1 calvin   one       1       one     5

2 calvin   two        2       one    4

3 calvin   two        2       one    5

4 kobe    one        3       one    6

5 kobe    one        3       two     7

In [9]: pd.merge(left,right,on='key1',suffixes=('_left','_right'))

Out[9]:

key1 key2_left   lval  key2_right  rval

0 calvin      one         1        one         4

1 calvin      one         1        one         5

2 calvin      two          2       one         4

3 calvin      two          2       one         5

4 kobe       one          3       one         6

5 kobe       one          3       two          7

merge的参数见下表,索引的连接将在下一节中讲解

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')。例如,如果左右两个DataFrame对象都有"data",则结果中就会出现“data_x”和“data_y”

copy                      设置为False,可以在某些特殊情况下避免将数据复制到结果数据结构中。默认为复制

2.索引上的合并

有时候,DataFrame中的连接键位于其索引中。在这种情况下,我们可以传入left_index=True或right_index=True(或两个都传)以说明索引应该被用作连接键:

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

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

In [12]: left1

Out[12]:

key value

0    a    0

1    b    1

2    a    2

3    a    3

4    b    4

5    c    5

In [13]: right1

Out[13]:

group_val

a        3.5

b        7.0

In [14]: pd.merge(left1,right1,left_on='key',right_index=True)

Out[14]:

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

由于默认的merge方法是求取连接键的交集,因此我们可以通过外链接的方式得到它们的并集:

In [15]: pd.merge(left1,right1,left_on='key',right_index=True,how='outer')

Out[15]:

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

对于层次化索引的数据,事情就有点复杂了:

In [18]: import numpy as np

In [19]: lefth=DataFrame({'key1':['Kobe','Kobe','Kobe','Calvin','Calvin'],'key2

...: ':[2008,2009,2010,2009,2010],'data':np.arange(5)})

In [20]: righth=DataFrame(np.arange(12).reshape((6,2)),index=[['Calvin','Calvin

...: ','Kobe','Kobe','Kobe','Kobe'],[2009,2008,2008,2008,2009,2010]],column

...: s=['event1','event2'])

In [21]: lefth

Out[21]:

key1 key2  data

0  Kobe 2008    0

1  Kobe 2009    1

2  Kobe 2010    2

3 Calvin 2009   3

4 Calvin 2010   4

In [22]: righth

Out[22]:

event1 event2

Calvin 2009    0         1

2008    2         3

Kobe   2008   4          5

2008    6         7

2009    8         9

2010  10        11

这种情况下,我们必须以列表的形式指明用作合并键的多个列(注意对重复索引值的处理):

In [23]: pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)

Out[23]:

key1 key2 data event1 event2

0 Kobe 2008    0        4         5

0 Kobe 2008    0        6         7

1 Kobe 2009    1        8         9

2 Kobe 2010    2       10       11

3 Calvin 2009  3        0         1

In [24]: pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True,how='ou

...: ter')

Out[24]:

key1 key2 data event1 event2

0 Kobe 2008    0.0   4.0      5.0

0 Kobe 2008    0.0   6.0      7.0

1 Kobe 2009    1.0   8.0      9.0

2 Kobe 2010    2.0  10.0    11.0

3 Calvin 2009  3.0   0.0      1.0

4 Calvin 2010  4.0  NaN   NaN

4 Calvin 2008  NaN 2.0      3.0

同时使用合并双方的索引也没问题:

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

...: ','Nevada'])

In [28]: right2=DataFrame([[7,8],[9,10],[11,12],[13,14]],index=['b','c','d','e'

...: ],columns=['Los Angle','Miami'])

In [29]: left2

Out[29]:

Ohio Nevada

a   1          2

c   3          4

e   5          6

In [30]: right2

Out[30]:

Los Angle Miami

b        7          8

c        9         10

d       11        12

e       13        14

In [31]: pd.merge(left2,right2,how='outer',left_index=True,right_index=True)

Out[31]:

Ohio Nevada Los Angle Miami

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

DataFrame还有一个join实例方法,它能更方便地实现按索引合并。它还可用于合并多个带有相同或相似索引的DataFrame对象,而不管它们之间有没有重叠的列。在上面的那个例子中,我们可以编写:

In [33]: left2.join(right2,how='outer')

Out[33]:

Ohio Nevada Los Angle Miami

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

由于一些历史原因(早期版本的pandas),DataFrame的join方法是在连接键上做左连接。它还支持参数DataFrame的索引跟调用者DataFrame的某个列之间的连接:

In [34]: left1.join(right1,on='key')

Out[34]:

key value group_val

0     a     0        3.5

1     b     1        7.0

2     a     2        3.5

3     a     3        3.5

4     b     4        7.0

5     c     5      NaN

最后,对于简单的索引合并,我们还可以向join传入一组DataFrame(后面介绍更为通用的concat函数,它也能实现此功能):

In [41]: left2.join([right2,another],how='outer')

d:\python3.6\lib\site-packages\pandas\core\frame.py:6369: FutureWarning: Sorting

because non-concatenation axis is not aligned. A future version

of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

verify_integrity=True)

Out[41]:

Ohio Nevada Los Angle Miami NY LA

a    1.0     2.0          NaN       NaN 7.0 8.0

b     NaN NaN         7.0          8.0 NaN NaN

c     3.0    4.0           9.0        10.0 9.0 10.0

d    NaN NaN         11.0        12.0 NaN NaN

e     5.0  6.0           13.0        14.0 11.0 12.0

f     NaN NaN         NaN       NaN 16.0 17.0

3.轴向连接

另一种数据合并运算也被称作连接(concatenation)、绑定(binding)或堆叠(stacking)。NumPy有一个用于合并原始NumPy数组的concatenation函数:

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

In [43]: arr

Out[43]:

array([[ 0, 1, 2, 3],

[ 4, 5, 6, 7],

[ 8, 9, 10, 11]])

In [44]: np.concatenate([arr,arr],axis=1)

Out[44]:

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]])

对于pandas对象(如Series和DataFrame),带有标签的轴使我们能够进一步推广数组的连接运算。具体点说,我们还需要考虑一下这些东西:

1)如果各对象其他轴上的索引不同,那些轴应该是做并集还是交集?

2)结果对象中的分组需要各不相同吗?

3)用于连接的轴重要吗?

pandas的concat函数提供了一种能够解决这些问题的可靠方式。下面给出一些例子来讲解其使用方式。假设有三个没有重叠索引的Series:

In [45]: from pandas import Series

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

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

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

对这些对象调用concat可以将值和索引粘合在一起:

In [49]: pd.concat([s1,s2,s3])

Out[49]:

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是列):

In [51]: pd.concat([s1,s2,s3],axis=1,sort=True)

Out[51]:

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

这种情况下,另外一条轴上没有重叠,从索引的有序并集(外链接)上就可以看出来。

传入join='inner'即可得到它们的交集:

In [54]: pd.concat([s1,s4],axis=1,sort=True)

Out[54]:

0 1

a 0.0 0

b 1.0 5

f NaN 5

g NaN 6

In [55]: pd.concat([s1,s4],axis=1,join='inner')

Out[55]:

0 1

a 0 0

b 1 5

In [56]: s4

Out[56]:

a 0

b 5

f 5

g 6

dtype: int64

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

In [57]: pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])

Out[57]:

0   1

a 0.0 0.0

c NaN NaN

b 1.0 5.0

e NaN NaN

不过有个问题,参与连接的片段在结果中区分不开。假设我们想要在连接轴上创建一个层次化索引。使用keys参数即可达到这个目的:

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

In [59]: result

Out[59]:

one   a 0

b 1

two   c  2

d 3

e 4

three f  5

g 6

dtype: int64

#后面将详细讲解unstack函数

In [60]: result.unstack()

Out[60]:

a     b     c       d     e     f       g

one 0.0 1.0 NaN NaN NaN NaN NaN

two NaN NaN 2.0 3.0 4.0 NaN NaN

three NaN NaN NaN NaN NaN 5.0 6.0

如果沿着axis=1对Series进行合并,则keys就会成为DataFrame的列头:

In [62]: pd.concat([s1,s2,s3],axis=1,keys=['one','two','three'],sort=True)

Out[62]:

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

同样的逻辑对DataFrame对象也是一样:

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

...: one','two'])

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

...: ree','four'])

In [65]: pd.concat([df1,df2],axis=1,keys=['level1','level2'],sort=True)

Out[65]:

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

Out[67]:

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 [70]: pd.concat([df1,df2],axis=1,keys=['level1','level2'],names=['upper','lo

...: wer'],sort=True)

Out[70]:

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

最后一个需要考虑的问题是,跟当前分析工作无关的DataFrame行索引:

In [71]: df1=DataFrame(np.random.randn(3,4),columns=['a','b','c','d'])

In [72]: df2=DataFrame(np.random.randn(2,3),columns=['b','d','a'])

In [73]: df1

Out[73]:

a               b             c            d

0 1.063786 0.119253 0.143501 0.169069

1 -1.825730 -0.406440 -0.505858 0.181967

2 0.023236 0.829552 0.401033 -0.365971

In [74]: df2

Out[74]:

b               d           a

0 -0.101389 -1.745123 1.739812

1 0.866487 1.324343 0.695858

在这种情况下,传入ignore_index=True即可:

In [77]: pd.concat([df1,df2],ignore_index=True,sort=True)

Out[77]:

a              b              c             d

0 1.063786 0.119253 0.143501 0.169069

1 -1.825730 -0.406440 -0.505858 0.181967

2 0.023236 0.829552 0.401033 -0.365971

3 1.739812 -0.101389 NaN -1.745123

4 0.695858 0.866487 NaN 1.324343

concat函数的参数

参数                       说明

objs                 参与连接的pandas对象的列表或字典。唯一必须的参数

axis                  指明连接的轴向,默认为0

join                   "inner"、“outer”其中之一,默认为“outer”.指明其他轴向上的索引是按交集(inner)还是并集(outer)进行合并

join_axes          指明用于其他n-1条轴的索引,不执行并集/交集运算

keys                   与连接对象有关的值,用于形成连接轴向上的层次化索引。可以是任意值得列表或数组、元组数组、数组列表(如果levels设置成多级数组的话)

levels                指定用作层次化索引各级别上的索引,如果设置了keys的话,用于创建分层级别的名称,如果设置了keys和(或)levels的话

verify_integrity    检查结果对象新轴上的重复情况,如果发现则引发异常。默认(False)允许重复

ignore_index   不保留连接轴上的索引,产生一组新索引range(total_length)

4.合并重叠数据

还有一种数据组合问题不能用简单的合并(merge)或连接(concatenation)运算来处理。比如说,我们可能有索引全部或部分重叠的数据集。给这个例子增加一点启发性,我们使用NumPy的where函数,它用于表达一种矢量化的if-else:

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: from pandas import DataFrame

In [4]: from pandas import Series

In [5]: a=Series([np.nan,6.6,np.nan,7.7,8.8,np.nan],index=['f','e','d','c','b',

...: 'a'])

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

...: 'a'])

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

In [9]: a

Out[9]:

f NaN

e 6.6

d NaN

c 7.7

b 8.8

a NaN

dtype: float64

In [10]: b

Out[10]:

f 0.0

e 1.0

d 2.0

c 3.0

b 4.0

a NaN

dtype: float64

In [11]: np.where(pd.isnull(a),b,a)

Out[11]: array([0. , 6.6, 2. , 7.7, 8.8, nan])

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

In [17]: b[:-2].combine_first(a[2:])

Out[17]:

a NaN

b 8.8

c 3.0

d 2.0

e 1.0

f 0.0

dtype: float64

对于DataFrame,combine_first自然也会在列上做同样的事情,因此我们可以将其看做:用参数对象中的数据为调用者对象的缺失数据“打补丁”:

In [18]: df1=DataFrame({'a':[1,np.nan,5,np.nan],'b':[np.nan,2,np.nan,6],'c':ran

...: ge(2,18,4)})

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

In [20]: df1.combine_first(df2)  #df2填充df1对应的NaN值

Out[20]:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值