利用python进行数据分析之数据规整化

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用python进行数据分析之数据规整化相关的知识,希望对你有一定的参考价值。

数据分析和建模大部分时间都用在数据准备上,数据的准备过程包括:加载,清理,转换与重塑。

合并数据集

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

pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来,实现类似于数据库中的连接操作。

pandas.cancat表示沿着一条轴将多个对象堆叠到一起。

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

下面将进行分别讲解:

 1、数据库风格的DateFrame合并

数据集的合并运算是通过一个或者多个键将行连接起来,主要使用的merge或者join方法。

>>> import pandas as pd
>>> from pandas import DataFrame
>>> import numpy as np
>>> df1=DataFrame({key:[b,b,a,c,a,a,b],data1:range(7)})
>>> df2=DataFrame({key:[a,b,d],data2:range(3)})
>>> pd.merge(df1,df2)
   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
#未显示指定用何列拼接,默认用重叠列的作为键,最好显示指定
>>> pd.merge(df1,df2,on=key)
   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
#当两个对象列明不同可以进行分别指定
>>> df3=DataFrame({lkey:[b,b,a,c,a,a,b],data1:range(7)})
>>> df4=DataFrame({rkey:[a,b,d],data2:range(3)})
>>> pd.merge(df3,df4,left_on=lkey,right_on=rkey)
   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
#默认情况下merge函数进行的是交集操作,可以指定how参数来实现左右连接与并集(outer)

 

#根据多个键进行合并,传入一个由列名组成的列表即可
>>> left=DataFrame({key1:[foo,foo,bar],key2:[one,two,three],lval:[1,2,3]})
>>> right=DataFrame({key1:[foo,foo,bar,bar],key2:[one,two,one,two],rval:[4,5,6,7]})
>>> pd.merge(left,right,on=[key1,key2],how=outer)
  key1   key2  lval  rval
0  foo    one     1     4
1  foo    two     2     5
2  bar  three     3   NaN
3  bar    one   NaN     6
4  bar    two   NaN     7

 对于合并运算需要考虑的最后一个问题是对重复列名的处理,merge有一个suffixes选项,用于指定附加到左右两个DataFrame对象的重叠列名上的字符串:

>>> pd.merge(left,right,on=key1)
  key1 key2_x  lval key2_y  rval
0  foo    one     1    one     4
1  foo    one     1    two     5
2  foo    two     2    one     4
3  foo    two     2    two     5
4  bar  three     3    one     6
5  bar  three     3    two     7
>>> pd.merge(left,right,on=key1,suffixes=(_left,_right))
  key1 key2_left  lval key2_right  rval
0  foo       one     1        one     4
1  foo       one     1        two     5
2  foo       two     2        one     4
3  foo       two     2        two     5
4  bar     three     3        one     6
5  bar     three     3        two     7
merge函数的参数表
left 参与合并的左侧DataFrame
right 参与合并的右侧DataFrame
how 选定参与合并的方式(inner,outer,left等)
on 用于连接的列名
left_on 左侧DataFrame中用于连接的键
right_on 右侧DataFrame中用于连接的键
sort 根据连接键对合并后的数据进行排序,默认为True
suffixes

字符串元组,用于追加到重叠列名的末尾

 

 

 

 

 

 

 

 

 

2、索引上的合并

有时,DataFrame中的连接位于其索引中,在此种情况下可以传入left_index=True或者right_index=True以说明索引应该被用作连接键:

>>> left1=DataFrame({key:[a,b,a,a,b,c],value:range(6)})
>>> right1=DataFrame({group:[3.5,7]},index=[a,b])
>>> left1
  key  value
0   a      0
1   b      1
2   a      2
3   a      3
4   b      4
5   c      5
>>> right1
   group
a    3.5
b    7.0

对于层次化索引数据,相对更为复杂些,在这种情况下,必须以列表的形式指明用作合并键的多个列

>>> lenth=DataFrame({key1:[ohio,ohio,ohio,nevada,nevada],key2:[2000,2001,2002,2001,2002],data:np.arange(5)})
>>> righth=DataFrame(np.arange(12).reshape((6,2)),index=[[neveda,neveda,ohio,ohio,ohio,ohio],[2001,2000,2000,2000,2001,2002]],columns=[event1,event2])
>>> lenth
   data    key1  key2
0     0    ohio  2000
1     1    ohio  2001
2     2    ohio  2002
3     3  nevada  2001
4     4  nevada  2002
>>> righth
             event1  event2
neveda 2001       0       1
       2000       2       3
ohio   2000       4       5
       2000       6       7
       2001       8       9
       2002      10      11
>>> pd.merge(lenth,righth,left_on=[key1,key2],right_index=True)
   data  key1  key2  event1  event2
0     0  ohio  2000       4       5
0     0  ohio  2000       6       7
1     1  ohio  2001       8       9
2     2  ohio  2002      10      11

 DataFrame还有一个join实例方法,它可以更为方便的实现按索引合并,还可以合并多个带有相同或者相似索引的DataFrame对象,而不管其是否有重叠的列:

>>> left2=DataFrame([[1,2],[3,4],[5,6]],index=[a,c,e],columns=[ohio,nevada])
>>> left2
   ohio  nevada
a     1       2
c     3       4
e     5       6
>>> right2=DataFrame([[7,8],[9,10],[11,12],[13,14]],index=[b,c,d,e],columns=[missouri,alambda])
>>> right2
   missouri  alambda
b         7        8
c         9       10
d        11       12
e        13       14
>>> left2.join(right2,how=outer)
   ohio  nevada  missouri  alambda
a     1       2       NaN      NaN
b   NaN     NaN         7        8
c     3       4         9       10
d   NaN     NaN        11       12
e     5       6        13       14

3、轴向连接

 纵向上,numpy有一个用于合并原始numpy数组的concatenation函数:

>>> arr=np.arange(12).reshape((3,4))
>>> arr
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> np.concatenate([arr,arr],axis=1)
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]])
>>> np.concatenate([arr,arr],axis=0)
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
#pandas的concat函数提供了一种能够解决这些问题的可靠方式,默认情况下,concat在0轴上工作,
>>> s1=pd.Series([0,1],index=[a,b])
>>> s2=pd.Series([2,3,4],index=[c,d,e])
>>> s3=pd.Series([5,6],index=[f,g])
>>> pd.concat([s1,s2,s3])
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64
#axis=1时,得到一个DataFrame对象
>>> pd.concat([s1,s2,s3],axis=1) 0 1 2 a 0 NaN NaN b 1 NaN NaN c NaN 2 NaN d NaN 3 NaN e NaN 4 NaN f NaN NaN 5 g NaN NaN 6

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

>>> s4=pd.concat([s1*5,s3])
>>> s4
a    0
b    5
f    5
g    6
dtype: int64
>>> pd.concat([s1,s4],axis=1,join_axes=[[‘a‘,‘c‘,‘b‘,‘e‘]])
    0   1
a   0   0
c NaN NaN
b   1   5
e NaN NaN

 当你需要区分参与连接的片段时,可以在连接轴上创建一个层次化索引,使用key参数可以达到这个目的

>>> result=pd.concat([s1,s2,s3],keys=[one,two,three])
>>> result
one    a    0
       b    1
two    c    2
       d    3
       e    4
three  f    5
       g    6
dtype: int64

 

#如果沿着axis=1对Series进行合并,则keys会变成合并后DataFrame的列头
>>> pd.concat([s1,s2,s3],keys=[one,two,three],axis=1)
   one  two  three
a    0  NaN    NaN
b    1  NaN    NaN
c  NaN    2    NaN
d  NaN    3    NaN
e  NaN    4    NaN
f  NaN  NaN      5
g  NaN  NaN      6

最后一个需要考虑的问题是,跟当前分析无关的DataFrame索引,直接传入ignore_index=True即可:

>>> df1=DataFrame(np.random.randn(3,4),columns=[a,b,c,d])
>>> df2=DataFrame(np.random.randn(2,3),columns=[b,d,a])
>>> df1
          a         b         c         d
0 -1.928978 -1.202455 -0.180614  0.693538
1 -1.234482  0.664544  0.259534  0.429279
2  0.305255  0.133844  0.934637  0.243345
>>> df2
          b         d         a
0 -1.582425  0.055378  0.288906
1 -0.381170  0.731310 -0.661805
>>> pd.concat([df1,df2],ignore_index=True)
          a         b         c         d
0 -1.928978 -1.202455 -0.180614  0.693538
1 -1.234482  0.664544  0.259534  0.429279
2  0.305255  0.133844  0.934637  0.243345
3  0.288906 -1.582425       NaN  0.055378
4 -0.661805 -0.381170       NaN  0.731310
#注意区分与下面区别
>>> pd.concat([df1,df2])
          a         b         c         d
0 -1.928978 -1.202455 -0.180614  0.693538
1 -1.234482  0.664544  0.259534  0.429279
2  0.305255  0.133844  0.934637  0.243345
0  0.288906 -1.582425       NaN  0.055378
1 -0.661805 -0.381170       NaN  0.731310

 4、合并重叠数据

还有一种数据不能用简单的合并或者连接运算来处理比如你有可能索引全部或部分重叠的两个数据集:

>>> 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(len(a),dtype=np.float64),index=[f,e,d,c,b,a])
>>> a
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64
>>> b
f    0
e    1
d    2
c    3
b    4
a    5
dtype: float64
>>> np.where(pd.isnull(a),b,a)
array([ 0. ,  2.5,  2. ,  3.5,  4.5,  5. ])
#可以看作用参数对象中的数据为调用者对象的缺失数据打补丁

也可用combine_first方法

>>> df1=DataFrame({a:[1,np.nan,5,np.nan],b:[np.nan,2,np.nan,6],c:range(2,18,4)})
>>> df1
    a   b   c
0   1 NaN   2
1 NaN   2   6
2   5 NaN  10
3 NaN   6  14
>>> df2=DataFrame({a:[5,4,np.nan,3,7],b:[np.nan,3,4,6,8]})
>>> df2
    a   b
0   5 NaN
1   4   3
2 NaN   4
3   3   6
4   7   8
>>> df1.combine_first(df2)
   a   b   c
0  1 NaN   2
1  4   2   6
2  5   4  10
3  3   6  14
4  7   8 NaN

 

重塑和轴向旋转

 1、重塑层次化索引

层次化索引技术为DataFrame数据重拍运算提供了一种具有良好一致性的方式,主要功能有二:

stack,将数据的列旋转为行

unstack,将数据的行旋转为列

>>> data=DataFrame(np.arange(6).reshape((2,3)),index=[ohio,colorado],columns=[one,two,three])
>>> data
          one  two  three
ohio        0    1      2
colorado    3    4      5
>>> data.index
Index([uohio, ucolorado], dtype=object)
>>> data.index.name=state
>>> data.columns.name=number
>>> data
number    one  two  three
state                    
ohio        0    1      2
colorado    3    4      5
>>> data.stack()
state     number
ohio      one       0
          two       1
          three     2
colorado  one       3
          two       4
          three     5
dtype: int32
#将列转化为行,得到一个Series
#对于一个层次化索引的Series,可以用unstack将其重排为一个DataFrame

 默认情况下unstack操作的是最内层的,可传入分层级别的编号和名称参数,即可对其他级别进行untack操作:

>>> result=data.stack()
>>> result
state     number
ohio      one       0
          two       1
          three     2
colorado  one       3
          two       4
          three     5
dtype: int32
>>> result.unstack(0)
state   ohio  colorado
number                
one        0         3
two        1         4
three      2         5
>>> result.unstack(state)
state   ohio  colorado
number                
one        0         3
two        1         4
three      2         5

 在对DataFrame,进行unset操作时,作为旋转轴的级别将会成为结果中的最低级别(即旋转轴索引将成为最内层索引):

>>> df=DataFrame({left:result,right:result+5},columns=[left,right])
>>> df.columns.name=side
>>> df
side             left  right
state    number             
ohio     one        0      5
         two        1      6
         three      2      7
colorado one        3      8
         two        4      9
         three      5     10
>>> df.unstack(state)
side   left          right         
state  ohio colorado  ohio colorado
number                             
one       0        3     5        8
two       1        4     6        9
three     2        5     7       10
>>> df.unstack(state).stack(side)
state         ohio  colorado
number side                 
one    left      0         3
       right     5         8
two    left      1         4
       right     6         9
three  left      2         5
       right     7        10

数据转换

除了数据合并与重排之外,另一类重要的操作是过滤,清理。

1、移除重复数据

DataFrame的duplicated方法返回一个布尔型Series,表示各行是否为重复行

>>> data=DataFrame({k1:[one]*3+[two]*4,k2:[1,1,2,3,3,4,4]})
>>> data
    k1  k2
0  one   1
1  one   1
2  one   2
3  two   3
4  two   3
5  two   4
6  two   4
>>> data.duplicated()
0    False
1     True
2    False
3    False
4     True
5    False
6     True
dtype: bool
#drop_duplicates方法用于返回一个移除了重复行的DataFrame,删除那些为True的行
>>> data.drop_duplicates()
    k1  k2
0  one   1
2  one   2
3  two   3
5  two   4
#可以指定过滤重复列的项
>>> data.drop_duplicates([k1])
    k1  k2
0  one   1
3  two   3
#以上两个方法默认保留第一个出现的组合值,传入take_last=True则可以保留最后一个

 

以上是关于利用python进行数据分析之数据规整化的主要内容,如果未能解决你的问题,请参考以下文章

pandas数据规整化:清理转换合并重塑之合并数据集

利用Python进行数据分析-Pandas(第五部分-数据规整:聚合合并和重塑)

数据规整化:清理转换合并重塑

pandas小记:pandas数据规整化

pythonpython3 的CSV数据规整化1

pythonpython3 的CSV数据规整化1