其实Pandas有pivot、pivot_table两个函数来做数据透视,作用是一样的,只是pivot_table算是pivot的增强版,pivot_table对数据格式要求不高,而且支持aggfunc、fillvalue等参数,所以这里主要介绍pivot_table。
不过这里提一下,在使用pivot函数过程中可能会经常碰到一些异常,比如下面这个:
ValueError: Index contains duplicate entries, cannot reshape
这就是刚才说的,pivot函数对数据有些要求,这时可以尝试使用pivot_table!
下面开始介绍和使用pivot_table函数
1. 先看下API
?df.pivot_table
image.png
values、index、columns参数都比较好理解,就是指定index作为纵轴索引、columns作为横轴索引来观察指定的values值,另外aggfunc指定的是均值函数(mean),下面边用边深入理解。
2. 先提前定义下数据集,以下的演示都是基于此数据集
import numpy as np
import pandas as pd
df = pd.DataFrame({'student': ['小红', '小红', '李华', '李华', '小天', '小天'],
'class': ['001','001','001','001','002','002'],
'subject': ['C', 'Java', 'Python', 'C', 'C', 'Python'],
'grades': [80, 90, 78, 90, 80, 78]})
df
image.png
3. 理解参数
index、columns参数必须传一个,否则会报以下错误:
ValueError: No group keys passed!
只传index时
df.pivot_table(index='subject')
image.png
只传columns时
df.pivot_table(columns='subject')
image.png
兄台不知道是否有疑问,原来数据中class、student这两列去哪里了???为啥只剩grades了???
我的理解是被忽略掉了,因为这两列不是数字,mean函数作用不了,为了更好理解我把默认的mean函数换成其他函数,慢慢往下看:
df.pivot_table(index='subject', aggfunc=lambda x: type(x))
image.png
可以看到其实aggfunc接受的参数是一个Pandas中的Series对象,那我们把Series转成列表看下里面是啥.
df.pivot_table(index='subject', aggfunc=lambda x: x.tolist())
image.png
搜德斯捏!!!原来就是通过指定维度后透视得到的值的列表,或者你可以理解是通过lookup来得到的一列值。所以mean函数在作用于class、student这两列是字符串元素的列表肯定是不对的,所以被过滤掉了。
4. 实例
基于上面的数据集,做些小需求来更深入理解pivot_table函数
(1)统计各个班级(class)的平均分
df.pivot_table(index='class')
image.png
(2)统计各个班级(class)的平均分以及班级学生人数
df.pivot_table(index='class', aggfunc={'grades': np.mean, 'student': lambda x: len(x.unique())})
image.png
(3)统计各个班级(class)的各个科目(subject)的平均分
df.pivot_table(index='class', columns='subject', values='grades')
image.png
(4)统计各个班级(class)的各个科目(subject)的最高分,平且将空值填充为0
df.pivot_table(index='class', columns='subject', values='grades', aggfunc=max, fill_value=0)
image.png
(5)统计各个班级(class)的各个科目(subject)的最高分,平且将空值填充为0
df.pivot_table(index='class', columns='subject', values='grades', aggfunc=max, fill_value=0)
image.png
(6)统计各个班级(class)的各个科目(subject)的人数
df.pivot_table(index='class', columns='subject', values='grades', aggfunc='count', fill_value=0)
image.png
(7)统计各个学生(student)的最高分,最低分,平均分
df.pivot_table(index='student', values='grades', aggfunc=[max, min, np.mean])
image.png
上面是多级索引,可能你想去掉grades这一级, 可以参考下面方法
stack()是行转列, 把grades从column变成了index, 再reset_index去掉grades
df.pivot_table(index='student', values='grades', aggfunc=[max, min, np.mean]).stack().reset_index(level=-1, drop=True)
image.png
(8)获取各个学生(student)的最高分的level, 其中划分方式是: "C" < 80 <= "B" < 90 <= "A"
import bisect
def get_grade_level(series):
max_grade = max(series)
return 'CBA'[bisect.bisect_right([80, 90], max_grade)]
df.pivot_table(index='student', values='grades', aggfunc=get_grade_level)
image.png
网友评论