数据集中性表格(数据行列转置数据透视)
在逛CSDN论坛时遇到这样一个问题:
下列代码中srcdf和desdf都是Pandas的DataFrame对象,需要将srcdf转换为desdf,也就是根据列中的值拓展新的列,关系数据库报表中常见的需求,请问用DataFrame要如何实现?
- print(srcdf)
- 姓名 性别 科目 分数
- 编号
- 0 刘玄德 男 语文 98
- 1 刘玄德 男 数学 60
- 2 刘玄德 男 体育 50
- 3 关云长 男 语文 60
- 4 关云长 男 数学 60
- 5 关云长 男 体育 100
- [6 rows x 4 columns]
- print(desdf)
- 姓名 性别 语文 数学 体育 平均分
- 编号
- 0 刘玄德 男 98 60 50 66.666667
- 1 关云长 男 60 60 100 73.333333
- [2 rows x 6 columns]
经过分析,发现实际是将那么分组,将科目展开,即《利用pandas进行数据分析》第七章 数据转换下的将‘长格式’转换为‘宽格式’ 问题。论坛里已经有一种解决办法了:
- In [148]: from pandas import Series,DataFrame
- ...: a=[['刘玄德','男','语文',98.],['刘玄德','男','体育',60.],['关云长','男','数学',60.],['关云长','男','语文',100.]]
- ...: af=DataFrame(a,columns=['name','sex','course','score'])
- In [149]: af
- Out[149]:
- name sex course score
- 0 刘玄德 男 语文 98
- 1 刘玄德 男 体育 60
- 2 关云长 男 数学 60
- 3 关云长 男 语文 100
- In [150]: af.set_index(['name','sex','course'],inplace='TRUE')
- In [151]: af
- Out[151]:
- score
- name sex course
- 刘玄德 男 语文 98
- 体育 60
- 关云长 男 数学 60
- 语文 100
- In [152]: t1=af.unstack(level=2)
- In [153]: t1
- Out[153]:
- score
- course 体育 数学 语文
- name sex
- 关云长 男 NaN 60 100
- 刘玄德 男 60 NaN 98
- In [154]: t2=t1.mean(axis=1,skipna=True)
- In [155]: t2
- Out[155]:
- name sex
- 关云长 男 80
- 刘玄德 男 79
- dtype: float64
- In [156]: t1['平均分']=t2
- In [157]: t1
- Out[157]:
- score 平均分
- course 体育 数学 语文
- name sex
- 关云长 男 NaN 60 100 80
- 刘玄德 男 60 NaN 98 79
- In [158]: t1.fillna(0)
- Out[158]:
- score 平均分
- course 体育 数学 语文
- name sex
- 关云长 男 0 60 100 80
- 刘玄德 男 60 0 98 79
首先使用set_index 重建索引,这个函数很厉害,实际上是做了分组(groupby)和重建索引的工作。然后用unstack将行转换成列,最后算平均数,然后组合到一起。这里关键用到set_index(),unstack()。默认情况下,unstack的操作就是最内层的(这里就是level=2),除了传统分级编号,也可以用名称对其unstack。如果数据在分组中找不到的话会引入NaN。
下面我尝试用pivot和pivot_table解这个问题:
- #解法2:
- In [126]: a=[['刘玄德','男','语文',98.],['刘玄德','男','体育',60.],['关云长','男','数学',60.],['关云长','男','语文',100.]]
- ...: af=DataFrame(a,columns=['name','sex','course','score'])
- In [127]: af2=af.pivot('name','course','score') #使用pviot
- In [128]: af2['avg']=af2.mean(axis=1)
- In [129]: af2.fillna(0)
- Out[129]:
- course 体育 数学 语文 avg
- name
- 关云长 0 60 100 80
- 刘玄德 60 0 98 79
- In [130]: af2
- Out[130]:
- course 体育 数学 语文 avg
- name
- 关云长 NaN 60 100 80
- 刘玄德 60 NaN 98 79
- In [131]: af2[af2.isnull()]=0
- In [132]: af2
- Out[132]:
- course 体育 数学 语文 avg
- name
- 关云长 0 60 100 80
- 刘玄德 60 0 98 79
pivot的前两个参数值分别作用于行和列索引,最后一个参数值则是用于填充DaraFrame的数据列的列名。在《利用pandas进行数据分析》第七章 数据转换下的将‘长格式’转换为‘宽格式’ 中作者一语道破了pivot和上面做法的区别:
接下来我尝试用更简单的方法去得到上面的结果,在《利用pandas进行数据分析》书中,第九章 讲了透视表和交叉表。
pivot_table 就是数据透视表,用过EXCEL数据透视表的对此肯定很熟悉。不过目前函数的参数有所更新,原来的rows变成了index,cols变成了columns。
- #解法3:
- af.pivot_table('score',index='name',columns='course',aggfunc='mean',margins=True,fill_value=0)
- Out[141]:
- course 体育 数学 语文 All
- name
- 关云长 0 60 100 80.0
- 刘玄德 60 0 98 79.0
- All 60 60 99 79.5
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com