数据分析之Pandas学习笔记(六)(层次化索引、重塑、轴向旋转、行列变换、合并表数据)
level层次化索引
用于数组重塑
以低维度处理高维度数据
基于分组的操作
透视表的生成
pandas的层次化索引示例
unstack()与stack()进行重塑,即:行列索引变换
以DataFrame为例:
df.stack()
降维
将 列索引最上侧
的那一排索引 加到 行索引的最右侧
df.unstack()
升维
将 行索引最右侧
的那一竖索引 加到 列索引的最上侧
swaplevel()交换两个索引位置
df.swaplevel(0,1)
可以为name,也可以为level索引
sort_index()排序与 sum(level= )求和排序
df.sort_index(level=0)
对相应维度的那列索引排序
df.sum(level=0)
对行索引求和并自动排序
set_index()和reset_index()索引和列之间相互变换
df.set_index(['c','d'])
将c,d两列 --> 变成 --> 行索引
通过添加drop=False
字段,会创建出一个新的DataFrame,保留住原来cd这两列的数据。
df.reset_index()
reset_index的功能跟set_index刚好相反,层次化索引的级别会被转移到列里面
轴向旋转
重塑(轴向旋转的一种)stack()和unstack()
上面提到了重塑,它其实是轴向旋转的一种
.stack()
和.unstack()
操作的都是最内层,在进行轴向旋转的时候,轴级别也会成为结果中的最低级别。
(可以结合上面stack()和unstack()部分的例子。。。体会一下)
轴向旋转pivot()长变宽
df.pivot(index='',columns='',values='')
pandas.DataFrame.pivot()官方文档
将某列作为行索引,某列作为列索引,某(若干)列作为值。
本质有点类似于,先set_index创建层次化索引,然后unstack重塑。
例如下面这样:
相当于合并同类项(每个value对应的行列索引是唯一的,)
什么意思?看下面这个例子:
但是你用df.pivot_table() 这个方法,就可以避免上述唯一性的问题。
轴向旋转melt()宽变长
pandas.melt()官方文档
官方文档的例子看了几个之后,应该有个大致了解了。但是我看了还是有点不懂,到底有什么实际意义。
它和pivot()的区别只是,在不限定填入值参数的时候,pivot把长的数据变成了宽的数据,melt是把宽数据变成了长数据。
pivot和melt的区别和理解
再仔细考究一下,它们之间的区别,我们来实际体会一下有什么区别。
pivot()
我们限定了value值区域只填‘baz’
原来的foo列 --> 行索引
原来的bar列 --> 列索引
原来了baz列 --> 值区域
下面我们不限定值区域:
可以看到它自动默认把其余列充当值区域显示了。
也就实现了长数据变成了宽数据。
melt()
感觉看的有点难理解,我们可以大致这样来理解上面生成的结果:
id_vars相当于pivot中的index
value_vars相当于pivot中的columns
当然结果表中并没有把foo和bar这两列变成了行列索引。
而是把foo列作为了一个分组指标,结果中的foo列显示了它的列数据作为分组指标
而bar列,结果中显示了两列,一列纯显示了bar这个列索引名字 一列显示了bar列的具体数据
所以看的时候你可以大致这么看,一行一行对过去看,相当于原表中,one行bar列对应的数据是A,two行bar列对应的数据是B
这样就实现了宽数据变成了长数据
当然你想将baz和zoo列也一起放进来,那么value_var参数字段中添加即可,这样显示的结果表会变得更长
当然melt()过后的表格想恢复成原来的样子,可以直接在melt()后的df对象直接用pivot()即可
就像下面这样:
大致可以恢复成原来的数据表样式
因为我melt的时候拿了原数据表的2列数据,所以pivot的时候也只恢复了2列,看去没有恢复成原表所有数据,但是样式做到了和原表差不多的样式。
如果你一定要恢复成原表的样式的话,可以这样做:
1,将pivot后的df对象(这里我叫做b好了),先b.columns.name=None
2, 再用reset_index即可。
(可能排好之后的顺序不是你期望的那样,如果你原表是有序的你可以再sort_values(by=[…])对(若干)列里的值,排序一下)
pivot_table()数据透视表
pandas.pivot_table()官方文档
参数详解,这一篇写的很详细很好~
pd.pivot_table(df,index=[..],
columns=[..],
values=[..],
aggfunc=[..], -->np.sum,np.mean或字典(实现不同values执行不同函数)
fill_value=0,
margins=True, -->总和数据
)
pivot_table()高级用法
table = pd.pivot_table(df,index=["Manager","Status"],columns=["Product"],values=["Quantity","Price"],
aggfunc={"Quantity":len,"Price":[np.sum,np.mean]},fill_value=0)
table
类似SQL查询一样
groupby()分组
df.groupby([..],
axis=,
level=,
sort=,
)
对哪一列进行分组,就把那一列作为行索引:
有多层次的索引的话,也可以直接对分组出所需要的分组。
pivot和melt和pivot_table和groupby小结
pivot
还行
melt
不常用
pivot_table
数据透视表,功能强大
groupby
分组
合并表数据
join()
join的方法要求:
1,索引相似或相同
2,无重叠的列
3,默认左连接
df_left.join(df_right,
on='',
how='' 可填inner,left,right,outer
)
merge()
df01.merge(df02)
pd.merge(df01,df02) 默认将重叠的列当做键(有点类似于SQL中的外键),默认内连接inner(用how参数申明)
df01.merge(df02,
on='', 最好加这个字段申明一下要连接的列是哪(几)个
how='inner', 默认是内连接inner,此外还有left左外连接,right右外连接,outer外连接
suffixes=('_left','_right') 可实现重复列名的重命名
left_index=True 将行索引用于连接键
right_index=True 将行索引用于连接键
sort=True 排序字段,默认为True
)
当出现多对多的情况时,由于多对多结果产生的是行笛卡尔积,所以on参数需要传入多个连接键进行连接。
concat()
combine_first()
pandas.Series.combine_first官方文档
pandas.DataFrame.combine_first官方文档
pandas中concatenate和combine_first的用法
实践应用
场景一
将如下表,改成学号id,学生,各门学科,各门学科中的排名。
改成这样
首先,它肯定进行了rank排名操作,肯定进行了行列变换,或许会用到表合并,列与列的位置调换等相关操作。
下面一起来动手操作吧~
原始数据
df = pd.DataFrame({
# 'id':[001,002,003,001,002,003], 这样写会报错,理由是:数字前不能有多个0
# 'score':[90,96,93,87,82,80],
# 'subjectCode':[01,01,01,02,02,02], 这样写会报错,理由是:数字前不能有多个0
'id': ['001', '002', '003', '001', '002', '003'],
'score': [90, 96, 93, 87, 82, 80],
'subjectCode': ['01','01', '01', '02', '02', '02'],
'subjectName':['语文','语文','语文','数学','数学','数学'],
'userName':['张三','李四','王五','张三','李四','王五']
})
步骤一
利用povit(),截取userName和subjectName列作为行和列,score作为值。
df01 = df.pivot(index='userName',columns='subjectName',values='score')
步骤二
去掉列索引的name -->即:去除上面subjectName字段
# df01.index.name=None
df01.columns.name=None
步骤三
在df01表新建一列数学排名列
method=first(如果排名相同,取前一个排名进一位,当然你可以不填这个字段,那么排名不是取整,而有0·5·产生,不过这样也没事,看你个人需求,)
astype(‘int64’)是因为,排名出的结果是float64形式展示的,看着很别扭,我要排名全取整。
在df01表新建一列语文排名列
df01['数学rank'] = df01['数学'].rank(method='first').astype('int64')
df01['语文rank'] = df01['语文'].rank(method='first').astype('int64')
步骤四
我这里其实做了两步:
1,通过reindex(…),重新调整了一下,列与列之间的位置
2,通过reset_index(),把userName这一列行索引,重整到列里面
df01 = df01.reindex(['数学','数学rank','语文','语文rank'],axis=1).reset_index()
步骤五
我这里其实做了两步:
1,合并表数据
合并的方法有很多(merge、join、concat、combine_first
)如果是直接拼到最右边,那直接join(要拼的列)
但是我这里要拼到最左侧,join方法行不通,不能达到我们想要的效果
我这里通过merge()
函数来实现,因为要DataFrame对象
才有merge方法,所以df[‘id’].merge()是会报错的!
2,去重
因为df01表的数据,只有3行,但拼上去的id列有6行数据,这样在进行左连接还是右连接时肯定会多出来3行重复数据,或者匹配不到数据,
匹配不到数据的话就是NaN数据缺失
那么就要用dropna()
方法了
但是,这里只是数据重复
,不是数据缺失,
所以可以用drop_duplicates()
方法对DataFrame对象
的某一列进行操作,keep=first意思是保留第一条重复的数据,不保留其余重复数据。
df01 = df[['id','userName']].merge(df01,on='userName',how='left').drop_duplicates(['id'],keep='first')
场景二
如果你想类似于Excel那样,透视表操作的话,看这篇,写的很好:
场景三
如果你想简单的可视化的话,可以瞧瞧这个样例,可能不是很好: