【pandas】[5] 數據行列轉置,數據透視(stack,unstack,pviot,pviot_table)


作者:lianghc

在逛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



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com