Python3 pandas处理长型与宽型数据

825 阅读3分钟
原文链接: zhuanlan.zhihu.com

Python处理二维的dataframe数据主要依靠pandas包。这一点与R语言不同,R中处理dataframe的包是多面开花。不过现在这些处理函数慢慢有语法大一统的趋势,如tidyverse生态链。

在处理数据常常会遇到长宽数据互转,如从Wind数据库导出的公司财务数据。在Stata和R中已经有比较便捷的处理方法。

下面列示一下pandas包的处理方法。


首先,生成一份模拟数据。

import pandas as pd
import numpy as np

df=pd.DataFrame(np.random.rand(3,6),columns=['x', 'lev2015','roa2015', 'roa2016', 'lev2016','lev2017'])
df['stkcd']=['a1','a2','a3']
df
Out[1]: 
          x   lev2015   roa2015   roa2016   lev2016   lev2017 stkcd
0  0.434583  0.352021  0.155295  0.307686  0.226555  0.718034    a1
1  0.440119  0.051882  0.667143  0.995478  0.114729  0.996174    a2
2  0.292902  0.516601  0.157647  0.066176  0.506407  0.968796    a3

然后开始从长转为宽。

df=df.melt(id_vars=['stkcd','x'],value_vars=['lev2015','roa2015', 'roa2016', 'lev2016','lev2017'],var_name='name',value_name='score')

df
Out[2]: 
   stkcd         x     name     score
0     a1  0.434583  lev2015  0.352021
1     a2  0.440119  lev2015  0.051882
2     a3  0.292902  lev2015  0.516601
3     a1  0.434583  roa2015  0.155295
4     a2  0.440119  roa2015  0.667143
5     a3  0.292902  roa2015  0.157647
6     a1  0.434583  roa2016  0.307686
7     a2  0.440119  roa2016  0.995478
8     a3  0.292902  roa2016  0.066176
9     a1  0.434583  lev2016  0.226555
10    a2  0.440119  lev2016  0.114729
11    a3  0.292902  lev2016  0.506407
12    a1  0.434583  lev2017  0.718034
13    a2  0.440119  lev2017  0.996174
14    a3  0.292902  lev2017  0.968796

但是仔细一看,还需要再转一次。把name分割为两个变量。

df['year']=df['name'].str.slice(3,7)
df['name']=df['name'].str.slice(0,3)

df
Out[3]: 
   stkcd         x name     score  year
0     a1  0.434583  lev  0.352021  2015
1     a2  0.440119  lev  0.051882  2015
2     a3  0.292902  lev  0.516601  2015
3     a1  0.434583  roa  0.155295  2015
4     a2  0.440119  roa  0.667143  2015
5     a3  0.292902  roa  0.157647  2015
6     a1  0.434583  roa  0.307686  2016
7     a2  0.440119  roa  0.995478  2016
8     a3  0.292902  roa  0.066176  2016
9     a1  0.434583  lev  0.226555  2016
10    a2  0.440119  lev  0.114729  2016
11    a3  0.292902  lev  0.506407  2016
12    a1  0.434583  lev  0.718034  2017
13    a2  0.440119  lev  0.996174  2017
14    a3  0.292902  lev  0.968796  2017

此时把name转回去即可(从变量的转成列变量的名)。这个就是我们想要的数据,不信你可以用df.to_csv('wide_long.csv')导出数据试试看。具体如下。

df=df.pivot_table(index=['stkcd','x','year'], columns='name', values='score')

df
Out[4]: 
name                      lev       roa
stkcd x        year                    
a1    0.434583 2015  0.352021  0.155295
               2016  0.226555  0.307686
               2017  0.718034       NaN
a2    0.440119 2015  0.051882  0.667143
               2016  0.114729  0.995478
               2017  0.996174       NaN
a3    0.292902 2015  0.516601  0.157647
               2016  0.506407  0.066176
               2017  0.968796       NaN

不过呢,这个数据太难看了。进一步处理如下。

df=df.reset_index()

df
Out[5]: 
name stkcd         x  year       lev       roa
0       a1  0.434583  2015  0.352021  0.155295
1       a1  0.434583  2016  0.226555  0.307686
2       a1  0.434583  2017  0.718034       NaN
3       a2  0.440119  2015  0.051882  0.667143
4       a2  0.440119  2016  0.114729  0.995478
5       a2  0.440119  2017  0.996174       NaN
6       a3  0.292902  2015  0.516601  0.157647
7       a3  0.292902  2016  0.506407  0.066176
8       a3  0.292902  2017  0.968796       NaN

最后附图(点击可以放大)。一般的长宽型都可以按照这个思路操作,只是会根据语言工具的差异略有调整。

操作过程与版本信息
示意图

:为什么模拟那么丑的df?

:有时候现实的df就很丑。

:为什么这么写?麻烦,长。

:通用,不惧df的美丑。

:有更好的操作么😝

:靠你自动手🤗