【pandas】[5] 数据行列转置,数据透视(stack,unstack,pviot,pviot_table)

来源:互联网 发布:度小月担仔面 知乎 编辑:程序博客网 时间:2024/05/20 15:41

作者:lianghc

在逛CSDN论坛时遇到这样一个问题:

下列代码中srcdf和desdf都是Pandas的DataFrame对象,需要将srcdf转换为desdf,也就是根据列中的值拓展新的列,关系数据库报表中常见的需求,请问用DataFrame要如何实现?

[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. print(srcdf)  
  2.      姓名 性别  科目   分数  
  3. 编号                   
  4. 0   刘玄德  男  语文   98  
  5. 1   刘玄德  男  数学   60  
  6. 2   刘玄德  男  体育   50  
  7. 3   关云长  男  语文   60  
  8. 4   关云长  男  数学   60  
  9. 5   关云长  男  体育  100  
  10.    
  11. [6 rows x 4 columns]  
  12.    
  13. print(desdf)  
  14.      姓名 性别  语文  数学   体育        平均分  
  15. 编号                                  
  16. 0   刘玄德  男  98  60   50  66.666667  
  17. 1   关云长  男  60  60  100  73.333333  
  18.    
  19. [2 rows x 6 columns]  

经过分析,发现实际是将那么分组,将科目展开,即《利用pandas进行数据分析》第七章 数据转换下的将‘长格式’转换为‘宽格式’ 问题。论坛里已经有一种解决办法了:
[python] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. In [148]: from pandas import Series,DataFrame  
  2.      ...: a=[['刘玄德','男','语文',98.],['刘玄德','男','体育',60.],['关云长','男','数学',60.],['关云长','男','语文',100.]]  
  3.      ...: af=DataFrame(a,columns=['name','sex','course','score'])  
  4.   
  5. In [149]: af  
  6. Out[149]:   
  7.   name sex course  score  
  8. 0  刘玄德   男     语文     98  
  9. 1  刘玄德   男     体育     60  
  10. 2  关云长   男     数学     60  
  11. 3  关云长   男     语文    100  
  12.   
  13. In [150]: af.set_index(['name','sex','course'],inplace='TRUE')  
  14.   
  15. In [151]: af  
  16. Out[151]:   
  17.                  score  
  18. name sex course         
  19. 刘玄德  男   语文         98  
  20.          体育         60  
  21. 关云长  男   数学         60  
  22.          语文        100  
  23.   
  24. In [152]: t1=af.unstack(level=2)  
  25.   
  26. In [153]: t1  
  27. Out[153]:   
  28.          score           
  29. course      体育  数学   语文  
  30. name sex                 
  31. 关云长  男     NaN  60  100  
  32. 刘玄德  男      60 NaN   98  
  33.   
  34. In [154]: t2=t1.mean(axis=1,skipna=True)  
  35.   
  36. In [155]: t2  
  37. Out[155]:   
  38. name  sex  
  39. 关云长   男      80  
  40. 刘玄德   男      79  
  41. dtype: float64  
  42.   
  43. In [156]: t1['平均分']=t2  
  44.   
  45. In [157]: t1  
  46. Out[157]:   
  47.          score               平均分  
  48. course      体育  数学   语文      
  49. name sex                     
  50. 关云长  男     NaN  60  100    80  
  51. 刘玄德  男      60 NaN   98    79  
  52.   
  53. In [158]: t1.fillna(0)  
  54. Out[158]:   
  55.          score               平均分  
  56. course      体育  数学   语文      
  57. name sex                     
  58. 关云长  男       0  60  100    80  
  59. 刘玄德  男      60   0   98    79  

首先使用set_index 重建索引,这个函数很厉害,实际上是做了分组(groupby)和重建索引的工作。然后用unstack将行转换成列,最后算平均数,然后组合到一起。这里关键用到set_index(),unstack()。默认情况下,unstack的操作就是最内层的(这里就是level=2),除了传统分级编号,也可以用名称对其unstack。如果数据在分组中找不到的话会引入NaN。

下面我尝试用pivot和pivot_table解这个问题:

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #解法2:  
  2. In [126]: a=[['刘玄德','男','语文',98.],['刘玄德','男','体育',60.],['关云长','男','数学',60.],['关云长','男','语文',100.]]  
  3.      ...: af=DataFrame(a,columns=['name','sex','course','score'])  
  4. In [127]: af2=af.pivot('name','course','score')  #使用pviot  
  5. In [128]: af2['avg']=af2.mean(axis=1)  
  6. In [129]: af2.fillna(0)  
  7. Out[129]:   
  8. course  体育  数学   语文  avg  
  9. name                      
  10. 关云长      0  60  100   80  
  11. 刘玄德     60   0   98   79  
  12. In [130]: af2  
  13. Out[130]:   
  14. course  体育  数学   语文  avg  
  15. name                      
  16. 关云长    NaN  60  100   80  
  17. 刘玄德     60 NaN   98   79  
  18. In [131]: af2[af2.isnull()]=0  
  19. In [132]: af2  
  20. Out[132]:   
  21. course  体育  数学   语文  avg  
  22. name                      
  23. 关云长      0  60  100   80  
  24. 刘玄德     60   0   98   79  

pivot的前两个参数值分别作用于行和列索引,最后一个参数值则是用于填充DaraFrame的数据列的列名。在《利用pandas进行数据分析》第七章 数据转换下的将‘长格式’转换为‘宽格式’ 中作者一语道破了pivot和上面做法的区别:



接下来我尝试用更简单的方法去得到上面的结果,在《利用pandas进行数据分析》书中,第九章 讲了透视表和交叉表。

pivot_table 就是数据透视表,用过EXCEL数据透视表的对此肯定很熟悉。不过目前函数的参数有所更新,原来的rows变成了index,cols变成了columns。

[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #解法3:  
  2. af.pivot_table('score',index='name',columns='course',aggfunc='mean',margins=True,fill_value=0)  
  3. Out[141]:   
  4. course  体育  数学   语文   All  
  5. name                       
  6. 关云长      0  60  100  80.0  
  7. 刘玄德     60   0   98  79.0  
  8. All     60  60   99  79.5  


原创粉丝点击