当前位置: 首页 > news >正文

Task05|joyfulpandas|变形

目录

  • 元素和列索引之间的转换
    • 1. pivot(长表变宽)
    • 2. pivot_table
        • 【练一练】
    • 3. melt 逆操作把宽表转为长表
    • 4. wide_to_long(交叉列)
  • 二、索引的变形
  • 行列索引之间的变换
    • stack和unstack
      • 2. 聚合与变形的关系
  • 三、其他变形函数
    • 1. crosstab
      • 2. explode
      • 3. get_dummies 转化为零一矩阵,特征构建
    • 四、练习
      • Ex1:美国非法药物数据集
      • Ex2:特殊的wide_to_long方法

元素和列索引之间的转换

1. pivot(长表变宽)

  • index 变形后的行索引
  • columns 需要转到列索引的列
  • values 数值
df = pd.DataFrame({'Class':[2,2,1,1],
                   'Name':['San Zhang','San Zhang','Si Li','Si Li'],
                   'Subject':['Chinese','Math','Chinese','Math'],
                   'Grade':[80,75,90,85]})
df.loc[1,'Subject']='Chinese'
try:
	df.pivot(index='Name',columns='Subject',values='Grade')
except Exception as e:
	Err_Msg=e

df = pd.DataFrame({'Class':[1, 1, 2, 2, 1, 1, 2, 2],
                   'Name':['San Zhang', 'San Zhang', 'Si Li', 'Si Li',
                              'San Zhang', 'San Zhang', 'Si Li', 'Si Li'],
                   'Examination': ['Mid', 'Final', 'Mid', 'Final',
                                    'Mid', 'Final', 'Mid', 'Final'],
                   'Subject':['Chinese', 'Chinese', 'Chinese', 'Chinese',
                                 'Math', 'Math', 'Math', 'Math'],
                   'Grade':[80, 75, 85, 65, 90, 85, 92, 88],
                   'rank':[10, 15, 21, 15, 20, 7, 6, 2]})
pivot_multi= df.pivot(index = ['Class', 'Name'],
                       columns = ['Subject','Examination'],
                       values = ['Grade','rank'])

  • 唯一性要求
    原表中的index和columns对应两个列的行组合必须唯一
    pivot 会返回多级索引
    在这里插入图片描述

2. pivot_table

pivot的使用依赖于唯一性条件
不满足唯一性条件必须通过聚合操作使得相同行列组合对应的多个值变为一个值

  • aggfunc 使用聚合函数 aggfunc参数可以计入上一章所有的合法聚合字符串
    可以传入序列为输入,列表为输出的聚合函数
  • margins=True 边际汇总 (合计)
df = pd.DataFrame({'Name':['San Zhang', 'San Zhang', 
                              'San Zhang', 'San Zhang',
                              'Si Li', 'Si Li', 'Si Li', 'Si Li'],
                   'Subject':['Chinese', 'Chinese', 'Math', 'Math',
                                 'Chinese', 'Chinese', 'Math', 'Math'],
                   'Grade':[80, 90, 100, 90, 70, 80, 85, 95]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean')
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc=lambda x:x.mean())

【练一练】

在上面的边际汇总例子中,行或列的汇总为新表中行元素或者列元素的平均值,而总体的汇总为新表中四个元素的平均值。这种关系一定成立吗?若不成立,请给出一个例子来说明。

#假设Lisi 多加一项数学的成绩
df =pd.DataFrame({'Name':['San Zhang', 'San Zhang', 
                              'San Zhang', 'San Zhang',
                              'Si Li', 'Si Li', 'Si Li', 'Si Li','Si Li'],
                   'Subject':['Chinese', 'Chinese', 'Math', 'Math',
                                 'Chinese', 'Chinese', 'Math', 'Math','Math'],
                   'Grade':[80, 90, 100, 90, 70, 80, 85, 95,91]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean', margins=True)

在这里插入图片描述

可以看到lisi的数学平均分:(85+95+91)/3=90.3333
(85+95)/2=90
这导致了总均分统计的时候All=(95+91+85+70+80)/5=84.2

3. melt 逆操作把宽表转为长表

id_vars:列变量
在下面的例子中,Subject以列索引的形式存储,现在想要将其压缩到一个列中。
需要从列压缩到行的变量:value_vars:[] -> 名字var_name
原来列变量值的含义:value_name:列变量值的名字

df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese':[80,90],'Math':[80,75]})
df_melted=df.melt(id_vars=['Class','Name'],value_vars=['Chinese','Math'],var_name='Subject',value_name='Grade')
#通过pivot转回df
df_unmelted=df_melted.pivot(index=['Class','Name'],columns='Subject',values='Grade')
#多了一个Subject,需要恢复索引
df_unmelted=df_unmelted.reset_index().rename_axis({'Subject':''})

在这里插入图片描述

4. wide_to_long(交叉列)

列中包含了交叉类别,比如math_mid,math_final这样的列

  • suffix 正则后缀
  • sep 分隔符
  • stubnames:变量值的含义,转化之后的表以其为列
  • i 保持不变的id变量,等价于melt中的id_vars
  • j 压缩到行的变量名含义,等价于melt中的var_name
df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese_Mid':[80,75],'Math_Mid':[90,85],
'Chinese_Final':[80,75],'Math_Final':[90,85]
})
pd.wide_to_long(df,stubnames=['Chinese','Nath'],i=['Class','Name'],j='Examination',sep='_',suffix='.+')

res=pivot_multi.copy()#
res.columns=res.columns.map(lambda x:'_'.join(x))
res=res.reset_index()#重置索引
res=pd.wide_to_long(res,stubnames=['Grade','rank'],i=['Class','Name'],
j='Subject_Examination',sep='_',suffix='.+')

res=res.reset_index()
res[['Subject','Examination']]=res['Subject_Examination'].str.split("_",expand=True)
res=res[['Class','Name','Examination', 'Subject', 'Grade', 'rank']].sort_values('Subject')
#sort_values根据某个字段进行排序
res=res.reset_index(drop=True)

  1. pivot_multi.copy() 使用拷贝函数深拷贝复制
  2. 改变索引名字 使用map+lambda函数
    string 有一个join函数
  3. str.split(“_”,expand=True)
    使用_进行分割,expand=True可以扩展
    可以使用这个函数进行列的分割
res.columns=res.columns.map(lambda x:'_'.join(x))

在这里插入图片描述

二、索引的变形

行列索引之间的变换

利用swaplevel或者reorder_levels进行索引内部的层交换

stack和unstack

属于某一列或几列 元素 \color{red}{元素} 元素 列索引 \color{red}{列索引} 列索引之间的转换,而不是索引之间的转换
unstack 将行索引转换为列索引

  • unstack的主要参数是移动的层号,默认转化最内层,移动到列索引的最内层,同时支持同时转化多个层
    最内层的是索引最大的
  • 唯一性要求
    保证被转为列索引的行索引层和被保留的行索引层构成的组合是唯一的
df=pd.DataFrame(np.ones((4,2)),
                  index = pd.Index([('A', 'cat', 'big'),
                                    ('A', 'dog', 'small'),
                                    ('B', 'cat', 'big'),
                                    ('B', 'dog', 'small')]),
                  columns=['col_1', 'col_2'])

df.unstack()
等同于
df.unstack(2)
#同时转化多层
df.unstack([0,2])

#唯一性证明
my_index=df.index.to_list()
my_index[1]=my_index[0]
df.index=pd.Index(my_index)#构造index
try:
	df.unstack()
except Exception as e:
	Err_Msg=e
Err_Msg	

在这里插入图片描述

stack 将列索引层压入行索引

df = pd.DataFrame(np.ones((4,2)),
                  index = pd.Index([('A', 'cat', 'big'),
                                    ('A', 'dog', 'small'),
                                    ('B', 'cat', 'big'),
                                    ('B', 'dog', 'small')]),
                  columns=['index_1', 'index_2']).T
df
df.stack()
df.stack([1,2])

在这里插入图片描述

2. 聚合与变形的关系

在上面介绍的所有函数中,除了带有聚合效果的pivot_table以外,所有的函数在变形前后并不会带来values个数的改变,只是这些值在呈现的形式上发生了变化。在上一章讨论的分组聚合操作,由于生成了新的行列索引,因此必然也属于某种特殊的变形操作,但由于聚合之后把原来的多个值变为了一个值,因此values的个数产生了变化,这也是分组聚合与变形函数的最大区别。

变形:呈现形式发生了变化
分组聚合:将原来多个值变成了一个值

三、其他变形函数

1. crosstab

pivot_table能完成crosstab的所有功能
cross能统计元素组合出现的频数.(count操作)

统计learn_pandas数据集中学校和转系情况对应的频数:

df=pd.read_csv('../data/learn_pandas.csv')
pd.crosstab(index=df.School,columns=df.Transfer)
#等价于
pd.crosstab(index=df.School,columns=df.Transfer,values=[0]*df.shape[0],aggfunc='count')
#等价于
df.pivot_table(index='School',columns='Transfer',values='Name',aggfuc='count')

在这里插入图片描述
两个函数的区别:
pivot_table传入的是被调用表对应的名字
crosstab的对应位置传入的是具体的序列

2. explode

explode参数能够对某一列的元素进行纵向的展开
被展开的单元格必须存储 中的一种类型

  1. list
  2. tuple
  3. Series
  4. np.ndarray
df_ex=pd.DataFrame({'A':[[1,2],'my_str',{1,2},pd.Series([3,4])]})
df_ex.explode('A')
#此时对应的行号不会变

在这里插入图片描述

3. get_dummies 转化为零一矩阵,特征构建

get_dummies是用于特征构建的重要函数之一,其作用是把类别特征转为指示变量。

pd.get_dummies(df.Grade).head()

四、练习

Ex1:美国非法药物数据集

现有一份关于美国非法药物的数据集,其中SubstanceName, DrugReports分别指药物名称和报告数量:

  1. 将数据转为如下的形式:
    在这里插入图片描述
df = pd.read_csv('../data/drugs.csv').sort_values(['State','COUNTY','SubstanceName'],ignore_index=True)
df.head(3)
df_1=df.pivot(index=['State','COUNTY','SubstanceName'],columns="YYYY",values='DrugReports')
df_1.reset_index().rename_axis(columns={'YYYY':''})

在这里插入图片描述

在这里插入图片描述

  1. 将第1问中的结果恢复为原表。
df_2=df_1.melt(id_vars=['State','COUNTY','SubstanceName'],
          value_vars=df_1.columns[3:],
          var_name='YYYY',value_name='DrugReports').dropna(subset=['DrugReports']).astype({'YYYY':'int64','DrugReports':'int64'})
df_2=df_2.sort_values(['State','COUNTY','SubstanceName'],ignore_index=True).reindex_like(df)
df_2.equals(df)
  1. State分别统计每年的报告数量总和,其中State, YYYY分别为列索引和行索引,要求分别使用pivot_table函数与groupby+unstack两种不同的策略实现,并体会它们之间的联系。
df_3=df_2.pivot_table(index='YYYY',columns='State',values='DrugReports',aggfunc='sum')
df_3.head()
df_4=df.groupby(['State','YYYY'])['DrugReports'].sum().to_frame()
df_4.head()
df_5=df_4.unstack(0).droplevel(0,axis=1)

Ex2:特殊的wide_to_long方法

从功能上看,melt方法应当属于wide_to_long的一种特殊情况,即stubnames只有一类。请使用wide_to_long生成melt一节中的df_melted。(提示:对列名增加适当的前缀)

df = pd.DataFrame({'Class':[1,2],
                   'Name':['San Zhang', 'Si Li'],
                   'Chinese':[80, 90],
                   'Math':[80, 75]})
df1=df.rename(columns={'Chinese':'pre_Chinese','Math':'pre_Math'})
pd.wide_to_long(df1,stubnames=['pre'],
i=['Class','Name']
j='subject',sep='_',suffix='.+').reset_index().rename(columns={'pre':'Grade'})

相关文章:

  • 【SpringBoot】yaml配置文件语法—总结回顾
  • jenkins 发布项目到k8s tomcat
  • 基于ssm(非maven)学生考勤管理系统
  • C++11新特性(一)
  • WebRTC源码之摄像头视频数据采集源码分析
  • stm32f4xx-PWM输出
  • 【博客474】为什么k8s控制面pod使用的ip是node ip,而非pod cidr中的ip
  • 2022 华为 Java 高级面试题及答案
  • SpringCloud集成RocketMQ
  • 计算机java毕业设计选题汇总(2022)
  • Ruby on Rails 实践:课程导读
  • OpenGL基本架构知识
  • 神奇的卡尔曼滤波,行人追踪的福音
  • 第三章 教育法律法规
  • MATLAB | 全网唯一,使用MATLAB绘制好看的韦恩图(venn)
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Electron入门介绍
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • js如何打印object对象
  • KMP算法及优化
  • LeetCode18.四数之和 JavaScript
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • 初识MongoDB分片
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 复杂数据处理
  • 基于遗传算法的优化问题求解
  • 近期前端发展计划
  • 如何利用MongoDB打造TOP榜小程序
  • 少走弯路,给Java 1~5 年程序员的建议
  • 为什么要用IPython/Jupyter?
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • Semaphore
  • ​secrets --- 生成管理密码的安全随机数​
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • (02)Hive SQL编译成MapReduce任务的过程
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (四)汇编语言——简单程序
  • (算法)Game
  • (算法)N皇后问题
  • (一) springboot详细介绍
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)Linux整合apache和tomcat构建Web服务器
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .dwp和.webpart的区别
  • .net Application的目录
  • .NET Core 版本不支持的问题
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .Net(C#)自定义WinForm控件之小结篇
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • /etc/fstab和/etc/mtab的区别
  • @Builder用法
  • [20170713] 无法访问SQL Server
  • [383] 赎金信 js