对表格型数据进行重新排列的操作,被称作重塑或者透视。
使用多层索引进行重塑主要有stack和unstack操作,前面有介绍过。
In [93]: df = pd.DataFrame(np.arange(6).reshape(2,3), ...: index=pd.Index(['河南','山西'], name='省份'), ...: columns=pd.Index(['one','two','three'],name='number')) In [94]: df Out[94]: number one two three 省份 河南 0 1 2 山西 3 4 5 In [95]: result = df.stack() In [96]: result Out[96]: 省份 number 河南 one 0 two 1 three 2 山西 one 3 two 4 three 5 dtype: int32 In [97]: result.unstack() Out[97]: number one two three 省份 河南 0 1 2 山西 3 4 5
stack操作使得df的所有列都变成了分层行索引,产生了一个新的Series。
unstack默认情况下拆分最内层索引,然后将数据放入一个DataFrame中。可以传入一个层级序号或名称来拆分不同的层级。
In [98]: result.unstack(0) Out[98]: 省份 河南 山西 number one 0 3 two 1 4 three 2 5 In [99]: result.unstack('省份') Out[99]: 省份 河南 山西 number one 0 3 two 1 4 three 2 5
如果层级中的所有值并未有包含于每个子分组中,拆分可能会导致缺失值的产生:
In [100]: s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) In [101]: s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) In [102]: data2 = pd.concat([s1, s2], keys=['one', 'two']) In [103]: data2 # 注意concat的结果是一个分层索引 Out[103]: one a 0 b 1 c 2 d 3 two c 4 d 5 e 6 dtype: int64 In [104]: data2.unstack() Out[104]: a b c d e one 0.0 1.0 2.0 3.0 NaN two NaN NaN 4.0 5.0 6.0 In [105]: data2.unstack().stack() # 结果是可逆的 Out[105]: 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 In [106]: data2.unstack().stack(dropna=False) # 保留缺失值 Out[106]: 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对象拆堆时,被拆的层级会变成结果中最低的层级:
In [107]: df = pd.DataFrame({'left': result, 'right': result + 5}, ...: columns=pd.Index(['left', 'right'], name='side')) ...: In [108]: df Out[108]: side left right 省份 number 河南 one 0 5 two 1 6 three 2 7 山西 one 3 8 two 4 9 three 5 10 In [109]: df.unstack('省份') # 因为作死引入了中文,所以版式不太对齐 Out[109]: side left right 省份 河南 山西 河南 山西 number one 0 3 5 8 two 1 4 6 9 three 2 5 7 10
多层索引Series才能用unstack(单层的会报错);单层索引DataFrame用unstack和用stack作用一样,多层索引的用unstack才是拆堆操作。