数据规整:连接、联合与重塑

1.1分层索引

分层索引是pandas的重要特性,允许你在一个轴向上拥有多个(两个或两个以上)索引层级。笼统地说,分层索引提供了一种在更低维度的形式中处理更高维度数据的方式。先创建一个Series,以列表的列表(或数组)作为索引:

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]])
print(data)
----------------
a  1    0.211389
   2    0.974623
   3    0.009878
b  1    1.489891
   3    0.097519
c  1   -0.132779
   2   -2.556963
d  2    0.296693
   3    1.033984
dtype: float64

我们所看到的是一个以MultiIndex作为索引的Series的美化视图。索引中的“间隙”表示“直接使用上面的标签”:

print(data.index)
-----------------------------------------------------------------------------
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
           labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])

通过分层索引对象,也可以称为部分索引,允许你简洁地选择出数据的子集:

print(data['b'])
-------------
1   -0.295682
3    0.374343
dtype: float64
print(data['b':'c'])
----------------
b  1   -0.295682
   3    0.374343
c  1   -1.090632
   2   -0.035576
dtype: float64
print(data.loc[['b','d']])
----------------
b  1   -0.295682
   3    0.374343
d  2    0.829523
   3   -0.374870
dtype: float64
print(data.loc[:,2])
--------------
a    0.395417
c   -0.035576
d    0.829523
dtype: float64

分层索引在重塑数据和数组透视表等分组操作中扮演了重要角色。例如,我们可以使用unstack方法将数据在DataFrame中重新排列:

print(data.unstack())
-------------------------------
          1         2         3
a  0.248184 -1.516602  0.496004
b -0.382506       NaN -1.534670
c  1.561869  1.890850       NaN
d       NaN  1.225667  0.625659

unstack的反操作是stack:

print(data.unstack().stack())
----------------
a  1   -0.355943
   2    0.010095
   3   -0.856033
b  1    0.136396
   3   -1.474994
c  1   -0.008190
   2   -0.863610
d  2   -0.034150
   3    0.557624
dtype: float64

在DataFrame中,每个轴都可以拥有分层索引:

frame = pd.DataFrame(np.arange(12).reshape((4,3)),index=[['a','a','b','d'],[1,2,1,2]],
                     columns=[['Ohio','Ohio','Colorado'],
                              ['Green','Red','Green']])
print(frame)
----------------------
     Ohio     Colorado
    Green Red    Green
a 1     0   1        2
  2     3   4        5
b 1     6   7        8
d 2     9  10       11

分层的层级可以有名称(可以是字符串或python对象)。如果层级有名称,这些名称会在控制台输出中显示:

frame.index.names=['key1','key2']
frame.columns.names=['state','color']
print(frame)
----------------------------
state      Ohio     Colorado
color     Green Red    Green
key1 key2                   
a    1        0   1        2
     2        3   4        5
b    1        6   7        8
d    2        9  10       11

通过部分列索引,我们可以选出列中的组:

print(frame['Ohio'])
---------------------
color      Green  Red
key1 key2            
a    1         0    1
     2         3    4
b    1         6    7
d    2         9   10

1.1.1重排序和层级排序

有时,你需要重新排列轴上的层级顺序,或者按照特定层级的值对数据进行排序。swaplevel接收两个层级序号或层级名称,返回一个进行了层级变更的新对象(但是数据都是不变的):

print(frame.swaplevel('key1','key2'))
----------------------------
key2 key1                   
1    a        0   1        2
2    a        3   4        5
1    b        6   7        8
2    d        9  10       11

另一方面,sort_index只能在单一层级上对数据进行排序。在进行层级变换时,使用sort_index以使得结果按照层级进行字典排序也很常见:

print(frame.sort_index(level=1))
----------------------------
state      Ohio     Colorado
color     Green Red    Green
key1 key2                   
a    1        0   1        2
b    1        6   7        8
a    2        3   4        5
d    2        9  10       11
print(frame.swaplevel(0,1).sort_index(level=0))
----------------------------
state      Ohio     Colorado
color     Green Red    Green
key2 key1                   
1    a        0   1        2
     b        6   7        8
2    a        3   4        5
     d        9  10       11

1.1.2按层级进行汇总统计

DataFrame和Series中很多描述性和汇总性统计有一个level选项,通过level选项你可以指定你想要在某个特定的轴上进行聚合。我们可以按照层级在行或列上像下面这样进行聚合:

print(frame.sum(level='key2'))
------------------------
key2                    
1         6   8       10
2        12  14       16
print(frame.sum(level='color',axis=1))
---------------------
color      Green  Red
key1 key2            
a    1         2    1
     2         8    4
b    1        14    7
d    2        20   10

1.1.3使用DataFrame的列进行索引

frame = pd.DataFrame({'a':range(7),'b':range(7,0,-1),
                      'c':['one','one','one','two','two','two','two'],
                      'd':[0,1,2,0,1,2,3]})
print(frame)
---------------
   a  b    c  d
0  0  7  one  0
1  1  6  one  1
2  2  5  one  2
3  3  4  two  0
4  4  3  two  1
5  5  2  two  2
6  6  1  two  3

DataFrame的set_index函数会生成一个新的DataFrame,新的DataFrame使用一个或多个列作为索引:

frame2=frame.set_index(['c','d'])
print(frame2)
------------
       a  b
c   d      
one 0  0  7
    1  1  6
    2  2  5
two 0  3  4
    1  4  3
    2  5  2
    3  6  1

默认情况下这些列会从DataFrame中移除,我们也可以将它们留在DataFrame中:

print(frame.set_index(['c','d'],drop=False))
-------------------
       a  b    c  d
c   d              
one 0  0  7  one  0
    1  1  6  one  1
    2  2  5  one  2
two 0  3  4  two  0
    1  4  3  two  1
    2  5  2  two  2
    3  6  1  two  3

另一方面,reset_index是set_index的反操作,分层索引的索引层级会被移动到列中:

print(frame2.reset_index())
---------------
     c  d  a  b
0  one  0  0  7
1  one  1  1  6
2  one  2  2  5
3  two  0  3  4
4  two  1  4  3
5  two  2  5  2
6  two  3  6  1

1.2联合与合并数据集

包含在pandas对象的数据可以通过多种方式联合在一起:
pandas.merge根据一个或多个键将行进行连接。对于SQL或其他关系型数据库的用户来说,这种方式比较熟悉,它实现的是数据库的连接操作。
pandas.concat使对象在轴向上进行粘合或“堆叠”。
combine_first实例方法允许将重叠的数据拼接在一起,以使用一个对象中的值填充另一个对象中的缺失值。

1.2.1数据库风格的DataFrame连接

合并或连接操作通过一个或多个键连接行来联合数据集。这些操作是关系型数据库的核心内容(例如基于SQL的数据库)。pandas中的merge函数主要用于将各种join操作算法运用在你的数据上:

df1=pd.DataFrame({'key':['b','b','a','c','a','a','b'],
                  'data1':range(7)})
df2=pd.DataFrame({'key':['a','b','d'],'data2':range(3)})
print(pd.merge(df1,df2))
-------------------
  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会自动将重叠列名作为连接的键。但是,显示地连接键才是好的实现:

print(pd.merge(df1,df2,on='key'))
-------------------
  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

如果每个对象的列名是不同的,你可以分别为它们指定列名:

df3=pd.DataFrame({'lkey':['b','b','a','c','a','a','b'],
                  'data1':range(7)})
df4=pd.DataFrame({'rkey':['a','b','d'],
                  'data2':range(3)})
print(pd.merge(df3,df4,left_on='lkey',right_on='rkey'))
-------------------------
  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

默认情况下,merge做的是内连接(‘inner’join),结果中的键是两张表的交集。外连接(outer join)是键的并集,联合了左连接和右连接的效果:

print(pd.merge(df1,df2,how='outer'))
-------------------
  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

表1-1:how参数的不同连接类型

选项 行为
‘inner’ 只对两张表都有的键的交集进行联合
‘left’ 对所有左表的键进行联合
‘right’ 对所有右表的键进行联合
‘outer’ 对两张表都有的键的并集进行联合
df1=pd.DataFrame({'key':['b','b','a','c','a','b'],
                  'data1':range(6)})
df2=pd.DataFrame({'key':['a','b','a','b','d'],
                  'data2':range(5)})
print(df1)
------------
  key  data1
0   b      0
1   b      1
2   a      2
3   c      3
4   a      4
5   b      5
print(df2)
------------
  key  data2
0   a      0
1   b      1
2   a      2
3   b      3
4   d      4
print(pd.merge(df1,df2,on='key',how='left'))
--------------------
   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中三个‘b’行,而在右边有两行,因此在结果中有六个‘b’行。连接方法仅影响结果中显示的不同键值:

print(pd.merge(df1,df2,how='inner'))
-------------------
  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

使用多个键进行合并时,传入一个列名的列表:

left=pd.DataFrame({'key1':['foo','foo','bar'],
                   'key2':['one','two','one'],
                   'lval':[1,2,3]})
right=pd.DataFrame({'key1':['foo','foo','bar','bar'],
                    'key2':['one','one','one','two'],
                    'rval':[4,5,6,7]})
print(pd.merge(left,right,on=['key1','key2'],how='outer'))
-----------------------
  key1 key2  lval  rval
0  foo  one   1.0   4.0
1  foo  one   1.0   5.0
2  foo  two   2.0   NaN
3  bar  one   3.0   6.0
4  bar  two   NaN   7.0

表1-2:merge函数参数

参数 描述
left 合并时操作中左边的DataFrame
right 合并时操作中右边的DataFrame
how ‘inner’,‘outer’,‘left’,‘right’之一,默认是’inner’
on 需要连接的列名。必须是在两边的DataFrame对象都有的列名,并以left和right中的列名的交集作为连接键
left_on left DataFrame中用作连接键的列
right_on right DataFrame中用作连接的列
left_index 使用left的行索引作为它的连接键
right_index 使用right的行索引作为它的连接键
sort 通过连接键按字母顺序对合并的数据进行排序;在默认情况下为True
suffixes 在重叠情况下,添加到列名后的字符串元祖,默认是(‘_x’,’_y’)
copy 默认是False,则在某些特殊情况下避免将数据复制到结果数据结构中

1.2.2根据索引合并

在某些情况下,DataFrame中用于合并的键是它的索引。在这种情况下,你可以传递left_index=True或right_index=True(或者都传)来表示索引需要用来作为合并的键:

left1=pd.DataFrame({'key':['a','b','a','a','b','c'],
                    'value':range(6)})
right1=pd.DataFrame({'group_val':[3.7,7]},index=['a','b'])
print(left1)
------------
  key  value
0   a      0
1   b      1
2   a      2
3   a      3
4   b      4
5   c      5
print(right1)
------------
   group_val
a        3.7
b        7.0
print(pd.merge(left1,right1,left_on='key',right_index=True))
-----------------------
  key  value  group_val
0   a      0        3.7
2   a      2        3.7
3   a      3        3.7
1   b      1        7.0
4   b      4        7.0

由于默认的合并方法是连接键相交,我们也可以使用外连接来进行合并:

print(pd.merge(left1,right1,left_on='key',right_index=True,how='outer'))
-----------------------
  key  value  group_val
0   a      0        3.7
2   a      2        3.7
3   a      3        3.7
1   b      1        7.0
4   b      4        7.0
5   c      5        NaN

在多层索引数据的情况下,事情会更复杂,在索引上连接是一个隐式的多键合并:

lefth=pd.DataFrame({'key1':['Ohio','Ohio','Ohio','Nevada','Neveda'],
                    'key2':[2000,2001,2002,2001,2002],
                    'data':np.arange(5.)})
righth=pd.DataFrame(np.arange(12).reshape((6,2)),
                    index=[['Nevada','Nevada','Ohio','Ohio','Ohio','Ohio'],
                           [2001,2000,2000,2000,2001,2002]],
                    columns=['event1','event2'])
print(lefth)
---------------------
     key1  key2  data
0    Ohio  2000   0.0
1    Ohio  2001   1.0
2    Ohio  2002   2.0
3  Nevada  2001   3.0
4  Neveda  2002   4.0
print(righth)
---------------------------
             event1  event2
Nevada 2001       0       1
       2000       2       3
Ohio   2000       4       5
       2000       6       7
       2001       8       9
       2002      10      11

这种情况下,必须以列表的方式指明合并所需多个列:

print(pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True))
---------------------------
             event1  event2
Nevada 2001       0       1
       2000       2       3
Ohio   2000       4       5
       2000       6       7
       2001       8       9
       2002      10      11

print(pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True,how='outer'))
---------------------------
             event1  event2
Nevada 2001       0       1
       2000       2       3
Ohio   2000       4       5
       2000       6       7
       2001       8       9
       2002      10      11

使用两边的索引进行合并也是可以的:

left2=pd.DataFrame([[1.,2.],[3.,4.],[5.,6.]],
                   index=['a','c','e'],
                   columns=['Ohio','Nevada'])
right2=pd.DataFrame([[7.,8.],[9.,10.],[11.,12.],[13,14]],index=['b','c','d','e'],columns=['Missouri','Alabama'])
print(left2)
---------------
   Ohio  Nevada
a   1.0     2.0
c   3.0     4.0
e   5.0     6.0
print(right2)
--------------------
   Missouri  Alabama
b       7.0      8.0
c       9.0     10.0
d      11.0     12.0
e      13.0     14.0
print(pd.merge(left2,right2,how='outer',left_index=True,right_index=True))
----------------------------------
   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

DataFrame有一个方便的join实例方法,用于按照索引合并。该方法也可以用于合并多个索引相同或相似但没有重叠列的DataFrame对象。在之前的例子中,我们可以这样写:

print(left2.join(right2,how='outer'))
----------------------------------
   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列表:

another=pd.DataFrame([[7.,8.],[9.,10.],[11.,12.],[16.,17.]],
                     index=['a','c','e','f'],
                     columns=['New York','Oregon'])
print(another)
-------------------
   New York  Oregon
a       7.0     8.0
c       9.0    10.0
e      11.0    12.0
f      16.0    17.0
print(left2.join([right2,another]))
----------------------------------------------------
   Ohio  Nevada  Missouri  Alabama  New York  Oregon
a   1.0     2.0       NaN      NaN       7.0     8.0
c   3.0     4.0       9.0     10.0       9.0    10.0
e   5.0     6.0      13.0     14.0      11.0    12.0
print(left2.join([right2,another],how='outer'))
----------------------------------------------------
   Ohio  Nevada  Missouri  Alabama  New York  Oregon
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

1.2.3沿轴向连接

另一种数据组合操作可互换地称为拼接、绑定或堆叠。NumPy的concatenate函数可以在NumPy数组上实现该功能:

arr=np.arange(12).reshape((3,4))
print(arr)
--------------
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
print(np.concatenate([arr,arr],axis=1))
--------------------------
[[ 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的concat函数:

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'])
print(pd.concat([s1,s2,s3]))
------------
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

也可以传递一个参数axis=1,返回的结果则是一个DataFrame:

print(pd.concat([s1,s2,s3],axis=1))
----------------
     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
s4=pd.concat([s1,s3])
print(s4)
------------
a    0
b    1
f    5
g    6
dtype: int64
print(pd.concat([s1,s4],axis=1))
---------
     0  1
a  0.0  0
b  1.0  1
f  NaN  5
g  NaN  6
print(pd.concat([s1,s4],axis=1,join='inner'))
-------
   0  1
a  0  0
b  1  1

在这里也可以使用join_axes来指定用于连接其他轴向的轴:

print(pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']]))
-----------
     0    1
a  0.0  0.0
c  NaN  NaN
b  1.0  1.0
e  NaN  NaN

我们可以用keys参数在连接轴上创建一个多层索引:

result=pd.concat([s1,s1,s3],keys=['one','two','three'])
print(result)
-------------
one    a    0
       b    1
two    a    0
       b    1
three  f    5
       g    6
dtype: int64
print(result.unstack())
-------------------------
         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的列头:

print(pd.concat([s1,s2,s3],axis=1,keys=['one','two','three']))
------------------
   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对象:

df1=pd.DataFrame(np.arange(6).reshape(3,2),index=['a','b','c'],columns=['one','two'])
df2=pd.DataFrame(5+np.arange(4).reshape(2,2),index=['a','c'],columns=['three','four'])
print(df1)
-----------
   one  two
a    0    1
b    2    3
c    4    5
print(df2)
--------------
   three  four
a      5     6
c      7     8
print(pd.concat([df1,df2],axis=1,keys=['level1','level2']))
------------------------
  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选项:

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

我们可以用names参数命名生成的轴层级:

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

表1-3:concat函数的参数

参数 描述
objs 需要连接的pandas对象列表或字典;这是必选参数
axis 连接的轴向;默认是1
join 可以是’inner’或’outer’;用于指定连接方式是内连接还是外连接
keys 与要连接的对象关联的值,沿着连接轴形成分层索引;可以是任意值的列表或数组,也可以是元祖的数组,也可以是数组的列表(如果向levels参数传入多层数组)
names 如果传入了keys或levels参数,该参数用于多层索引的层级名称
ignore_index 不沿着连接轴保留索引,而产生一段新的索引

1.2.4联合重叠数据

还有另一个数据联合场景,既不是合并操作,也不是连接操作。你可能有两个数据集,这两个数据集的索引全部或部分重叠。作为一个示例,考虑NumPy的where函数,这个函数可以进行面向数组的if-else等价操作:

a=pd.Series([np.nan,2.5,0.0,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
b=pd.Series([0.,np.nan,2.,np.nan,np.nan,5.])
print(a)
--------------
f    NaN
e    2.5
d    0.0
c    3.5
b    4.5
a    NaN
dtype: float64
print(b)
--------------
0    0.0
1    NaN
2    2.0
3    NaN
4    NaN
5    5.0
dtype: float64
print(np.where(pd.isnull(a),b,a))
-------------------------
[0.  2.5 0.  3.5 4.5 5. ]

在DataFrame中,combine_first逐列做相同的操作,因此我们可以认为它是根据传入的对象来“修补”调用对象的缺失值:

df1=pd.DataFrame({'a':[1.,np.nan,5.,np.nan],
                  'b':[np.nan,2.,np.nan,6.],
                  'c':range(2,18,4)})
df2=pd.DataFrame({'a':[5.,4.,np.nan,3.,7.],
                  'b':[np.nan,3.,4.,6.,8.]})
print(df1)
---------------
     a    b   c
0  1.0  NaN   2
1  NaN  2.0   6
2  5.0  NaN  10
3  NaN  6.0  14
print(df2)
-----------
     a    b
0  5.0  NaN
1  4.0  3.0
2  NaN  4.0
3  3.0  6.0
4  7.0  8.0
print(df1.combine_first(df2))
-----------------
     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

1.3重塑和透视

重排列表格型数据有多种基础操作。这些操作被称为重塑或透视。

1.3.1使用多层索引进行重塑

多层索引在DataFrame中提供了一种一致性方式用于重排列数据。以下是基础操作:
stack(堆叠)
该操作会“旋转”或将列中的数据透视到行。
unstack(拆堆)
该操作会将行中的数据透视到列。
下面考虑一个带有字符串数组作为行或列索引的小型DataFrame:

data=pd.DataFrame(np.arange(6).reshape((2,3)),index=pd.Index(['Ohio','Colorado'],name='state'),columns=pd.Index(['one','two','three'],name='number'))
print(data)
-------------------------
number    one  two  three
state                    
Ohio        0    1      2
Colorado    3    4      5

在这份数据上使用stack方法会将列透视到行,产生一个新的Series:

result=data.stack()
print(result)
---------------------
state     number
Ohio      one       0
          two       1
          three     2
Colorado  one       3
          two       4
          three     5
dtype: int32

从一个多层索引序列中,我们可以使用unstack方法将数据重排列后放入一个DataFrame中:

print(result.unstack())
-------------------------
number    one  two  three
state                    
Ohio        0    1      2
Colorado    3    4      5

默认情况下,最内层是已拆堆的(与stack方法一样)。你可以传入一个层级序号或名称来拆分一个不同的层级:

print(result.unstack(0))
----------------------
state   Ohio  Colorado
number                
one        0         3
two        1         4
three      2         5
print(result.unstack('state'))
----------------------
state   Ohio  Colorado
number                
one        0         3
two        1         4
three      2         5

如果层级中的所有值并未包含于每个子分组中时,拆分可能会引入缺失值:

s1=pd.Series([0,1,2,3],index=['a','b','c','d'])
s2=pd.Series([4,5,6],index=['c','d','e'])
data2=pd.concat([s1,s2],keys=['one','two'])
print(data2)
------------
one  a    0
     b    1
     c    2
     d    3
two  c    4
     d    5
     e    6
dtype: int64
print(data2.unstack())
----------------------------
       a    b    c    d    e
one  0.0  1.0  2.0  3.0  NaN
two  NaN  NaN  4.0  5.0  6.0

默认情况下,堆叠会过滤出缺失值,因此堆叠拆堆的操作是可逆的:

print(data2.unstack())
----------------------------
       a    b    c    d    e
one  0.0  1.0  2.0  3.0  NaN
two  NaN  NaN  4.0  5.0  6.0
print(data2.unstack().stack())
--------------
one  a    0.0
     b    1.0
     c    2.0
     d    3.0
two  c    4.0
     d    5.0
     e    6.0
dtype: float64
print(data2.unstack().stack(dropna=False))
--------------
one  a    0.0
     b    1.0
     c    2.0
     d    3.0
     e    NaN
two  a    NaN
     b    NaN
     c    4.0
     d    5.0
     e    6.0
dtype: float64

当你在DataFrame中拆堆时,被拆堆的层级会变为结果中最低的层级:

df=pd.DataFrame({'left':result,'right':result+5},
                columns=pd.Index(['left','right'],name='side'))
print(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
print(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

在调用stack方法时,我们可以指明需要堆叠的轴向名称:

print(df.unstack('state').stack('side'))
----------------------------
state         Colorado  Ohio
number side                 
one    left          3     0
       right         8     5
two    left          4     1
       right         9     6
three  left          5     2
       right        10     7

猜你喜欢

转载自blog.csdn.net/weixin_43303087/article/details/86319668
今日推荐