python之数据的合并和重塑

一、数据的合并

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

  • pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来。SQL或其他关系型数据库的用户对此应该会比较熟悉,因为它实现的就是数据库的连接操作。
  • pandas.concat可以沿着一条轴将多个对象堆叠到一起。
  • 实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值。

1.1 merge函数和join函数

python之数据的合并和重塑_第1张图片

python之数据的合并和重塑_第2张图片

相关代码

from pandas import DataFrame
import pandas as pd
#多对一:“多”指的是df1,df1中有多个被标记为a和b的行;“一"指的是df2,df2中key列每个值只对应一行
#两对象存在相同列名时:
df1=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df2=DataFrame({'key':['a','b','d'],'data2':range(3)})
#没有指定用哪一列进行连接,merge会按照重叠列的列名当键
m1=pd.merge(df1,df2)
#但,最好显式指定一下:
m2=pd.merge(df1,df2,on='key')
#利用join函数
#数据内容与m1/m2相同,但索引与data1相同,这是因为连接方式默认是'left'因此索引与data1一一对应
df1.join(df2.set_index('key'),on='key',how='inner') 
#从结果可以看出:c和d以及与之相关的数据都不见了,
#这是因为merge时,默认做的是'inner'连接,结果中的键是交集
#还有'outer','left','right'方式
m3=pd.merge(df1,df2,how='outer')
"""
df1:                       df2:                m1/m2:                       m3:
       data1 key       data2 key           data1 key  data2            data1 key  data2
0      0   b        0      0   a        0      0   b      1         0    0.0   b    1.0
1      1   b        1      1   b        1      1   b      1         1    1.0   b    1.0
2      2   a        2      2   d        2      6   b      1         2    6.0   b    1.0
3      3   c                            3      2   a      0         3    2.0   a    0.0
4      4   a                            4      4   a      0         4    4.0   a    0.0
5      5   a                            5      5   a      0         5    5.0   a    0.0
6      6   b                                                        6    3.0   c    NaN
                                                                    7    NaN   d    2.0
"""
#当两对象不存在相同列名时,可以进行分别指定:
df3=DataFrame({'lkey':['b','b','a','c','a','a','b'],'data1':range(7)})
df4=DataFrame({'rkey':['a','b','d'],'data2':range(3)})
m4=pd.merge(df3,df4,left_on='lkey',right_on='rkey')
"""
df3:                       df4:                                 m4:
       data1 lkey       data2 rkey                       data1 lkey  data2  rkey
0      0   b        0      0   a                    0      0   b      1       b
1      1   b        1      1   b                    1      1   b      1       b
2      2   a        2      2   d                    2      6   b      1       b
3      3   c                                        3      2   a      0       a
4      4   a                                        4      4   a      0       a
5      5   a                                        5      5   a      0       a
6      6   b
"""
#多对多,产生的是行的笛卡尔积,
#例:df5中data1=0,key=b的,连接后结果中,有两个,这是因为df6中key为b的有两个
df5=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df6=DataFrame({'key':['a','b','a','d','b'],'data2':range(5)})
m5=pd.merge(df5,df6,on='key',how='left')
"""
         m5:                               df5:                   df6:
    data1 key  data2                     data1 key               data2 key
0       0   b    1.0                  0      0   b            0      0   a
1       0   b    4.0                  1      1   b            1      1   b
2       1   b    1.0                  2      2   a            2      2   a
3       1   b    4.0                  3      3   c            3      3   d
4       2   a    0.0                  4      4   a            4      4   b
5       2   a    2.0                  5      5   a
6       3   c    NaN                  6      6   b
7       4   a    0.0
8       4   a    2.0
9       5   a    0.0
10      5   a    2.0
11      6   b    1.0
12      6   b    4.0
"""
#根据多个键合并,只需要传入一个由列名组成的列表
left=DataFrame({'key1':['foo','foo','bar'],'key2':['one','two','one'],'lval':[1,2,3]})
right=DataFrame({'key1':['foo','foo','bar','bar'],'key2':['one','one','one','two'],'rval':[4,5,7,8]})
m6=pd.merge(left,right,on=['key1','key2'],how='outer')
"""
left:                        right:                   m6:
  key1 key2  lval        key1 key2  rval        key1 key2   lval    rval
0  foo  one     1      0  foo  one     4     0  foo  one     1.0     4.0
1  foo  two     2      1  foo  one     5     1  foo  one     1.0     5.0
2  bar  one     3      2  bar  one     7     2  foo  two     2.0     NaN
                       3  bar  two     8     3  bar  one     3.0     7.0
                                             4  bar  two     NaN     8.0
                                             
"""
#合并运算时,对于重复列名的处理
m7=pd.merge(left,right,on='key1') #自动对重复列名添加后缀:_x,_y等
#使用merge中的suffixes选项
m8=pd.merge(left,right,on='key1',suffixes=('_left','_right'))
#使用join函数  #数据内容与m8相同,索引是[0,0,1,1,2,2]
left.join(right.set_index('key1'),on='key1',lsuffix='_left',rsuffix='_right')
"""
             m7:                                       m8:     
  key1 key2_x  lval key2_y  rval       key1 key2_left  lval key2_right  rval
0  foo    one    1    one    4       0  foo       one     1        one     4
1  foo    one    1    one    5       1  foo       one     1        one     5
2  foo    two    2    one    4       2  foo       two     2        one     4
3  foo    two    2    one    5       3  foo       two     2        one     5
4  bar    one    3    one    7       4  bar       one     3        one     7
5  bar    one    3    two    8       5  bar       one     3        two     8
"""
#索引上的合并
left1=DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
right1=DataFrame({'group_val':[3.3,6.6]},index=['a','b'])
m9=pd.merge(left1,right1,left_on='key',right_index=True)
#使用join函数
m10=left1.set_index('key').join(right1,how='inner')
"""
left1:                right1:                    m9:                       m10:
   data1 key         group_val           data1 key  group_val       data1  group_val
0      0   b      a        3.3        0      0   b        6.6    a      2        3.3
1      1   b      b        6.6        1      1   b        6.6    a      4        3.3
2      2   a                          5      5   b        6.6    b      0        6.6
3      3   c                          2      2   a        3.3    b      1        6.6
4      4   a                          4      4   a        3.3    b      5        6.6
5      5   b
"""

1.2  concat函数------轴向连接

python之数据的合并和重塑_第3张图片

相关代码

#轴向连接
from pandas import DataFrame,Series
import pandas as pd
import numpy as np
s1=Series([0,1],index=['a','b'])
s2=Series([2,3,4],index=['c','d','e'])
s3=Series([5,6],index=['f','g'])
#concat默认是在axis=0上工作的,默认外连接(outter)求并集
c1=pd.concat([s1,s2,s3])
c2=pd.concat([s1,s2,s3],axis=1)
"""
c1:                      c2:
a    0                0    1    2
b    1           a  0.0  NaN  NaN
c    2           b  1.0  NaN  NaN
d    3           c  NaN  2.0  NaN
e    4           d  NaN  3.0  NaN
f    5           e  NaN  4.0  NaN
g    6           f  NaN  NaN  5.0
dtype: int64     g  NaN  NaN  6.0
"""
s4=pd.concat([s1*5,s3])
c3=pd.concat([s1,s4],axis=1)
#设置求交集,需将join='inner'
c4=pd.concat([s1,s4],axis=1,join='inner')
#可以使用join_axes指定其他轴上使用的索引,因为此时axis=1,所以其他轴指axis=0
c5=pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
"""
s4:                 c3:                  c4:             c5:
a    0                0  1              0  1            0    1
b    5           a  0.0  0           a  0  0       a  0.0  0.0
f    5           b  1.0  5           b  1  5       c  NaN  NaN
g    6           f  NaN  5                         b  1.0  5.0
dtype: int64     g  NaN  6                         e  NaN  NaN
"""
#创建层次化索引
c6=pd.concat([s1,s2,s3],keys=['s1','s2','s3'])
c7=pd.concat([s1,s2,s3],axis=1,keys=['s1','s2','s3'])
"""                                   c7:
c6:                                     s1   s2   s3
s1  a    0                          a  0.0  NaN  NaN
    b    1                          b  1.0  NaN  NaN
s2  c    2                          c  NaN  2.0  NaN
    d    3                          d  NaN  3.0  NaN
    e    4                          e  NaN  4.0  NaN
s3  f    5                          f  NaN  NaN  5.0
    g    6                          g  NaN  NaN  6.0
dtype: int64
"""
df1=DataFrame(np.ones((3,4)),columns=['a','b','c','d'])
df2=DataFrame(np.zeros((2,3)),columns=['b','d','a'])
#直接连接时,索引会重复
c8=pd.concat([df1,df2])
#此时,只需将ignore_index=True即可
c9=pd.concat([df1,df2],ignore_index=True)
"""
c8:                                      c9:
     a    b    c    d               a    b    c    d
0  1.0  1.0  1.0  1.0          0  1.0  1.0  1.0  1.0
1  1.0  1.0  1.0  1.0          1  1.0  1.0  1.0  1.0
2  1.0  1.0  1.0  1.0          2  1.0  1.0  1.0  1.0
0  0.0  0.0  NaN  0.0          3  0.0  0.0  NaN  0.0
1  0.0  0.0  NaN  0.0          4  0.0  0.0  NaN  0.0
"""

1.3 对于索引全部或部分重叠的两个数据集进行合并的情况,采用combine_first方法,其效果如下:

#合并重叠数据,若索引全部或部分重叠的两个数据集进行合并时
a=Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
b=Series(np.arange(6,dtype=np.float64),index=['f','e','d','c','b','a'])
b[-1]=np.nan
#矢量化的if_else语句
np.where(pd.isnull(a),b,a)  #return: array([ 0. ,  2.5,  2. ,  3.5,  4.5,  nan])
#等效于combine_first方法,且该方法,能使数据对齐。
#用参数对象的数据为调用者对象的缺失数据“打补丁”,对于DataFrame对象也一样
a.combine_first(b)
"""
a:                   b:               a.combine_first(b):
f    NaN          f    0.0                f    0.0
e    2.5          e    1.0                e    2.5
d    NaN          d    2.0                d    2.0
c    3.5          c    3.0                c    3.5
b    4.5          b    4.0                b    4.5
a    NaN          a    NaN                a    NaN
"""

二、数据的重塑

用于重新排列表格型数据的基础运算函数,也称作重塑(reshape)或轴向旋转(pivot)运算。

2.1 重塑层次化索引

层次化索引为DataFrame数据的重排任务提供了一种良好一致性的方式:

  • stack:将数据的列“旋转”为行。
  • unstack:将数据的行“旋转”为列。
#重塑层次化索引
#stack和unstack两者可逆。
data=DataFrame(np.arange(6).reshape((2,3)),index=pd.Index(['CN','UK'],name='state'),columns=pd.Index(['A','B','C'],name='ch'))
#stack:将数据的列“旋转”为行,且默认滤除缺失数据
result1=data.stack()
#result1.unstack()的结果和data相同
#unstack:将数据的行“旋转”为列,若找不到对应数据,则会引入缺失数据
result2=data.unstack()
"""
data:                       result1:                     result2:
ch     A  B  C            state  ch                      ch state
state                     CN     A    0                  A  CN       0
CN     0  1  2                   B    1                     UK       3
UK     3  4  5                   C    2                  B  CN       1
                          UK     A    3                     UK       4
                                 B    4                  C  CN       2
                                 C    5                     UK       5
"""

2.2 将“长格式”旋转为“宽格式“------pivot方法

时间序列数据通常是以所谓的”长格式“(long)或”堆叠格式“(stacked)存储在数据库和csv文件中。

pivot其实只是一个快捷方式而已,用set_index创建层次化索引,再用unstack重塑。

ldata=pd.read_csv('ldata.csv')
#pivot函数,第一个参数作为行索引的列名,第二个参数作为列索引的列名,第三个参数则是数据列列名
pivoted=ldata.pivot(index='date',columns='item',values='value')
#或pivoted=ldata.pivot('date','item','value')
#若有多个需要重塑的数据列(values),则最后一个参数忽略,将默认除行列索引的列名,其余皆为数据列
"""
ldata:                                         pivoted:
      date     item     value           item     infl   realgdp  unemp
0  1959-03  realgdp   270.349           date                          
1  1959-03     infl     0.000           1959-03  0.00   270.349    5.8
2  1959-03    unemp     5.800           1959-06  2.34  2778.801    5.1
3  1959-06  realgdp  2778.801           1959-09  2.74  2775.488    5.3
4  1959-06     infl     2.340           1959-12   NaN  2785.204    NaN
5  1959-06    unemp     5.100
6  1959-09  realgdp  2775.488
7  1959-09     infl     2.740
8  1959-09    unemp     5.300
9  1959-12  realgdp  2785.204
"""

你可能感兴趣的:(数据分析工具)