【转】Spark实现行列转换pivot和unpivot
背景
做过数据清洗ETL工作的都知道,行列转换是一个常见的数据整理需求。在不同的编程语言中有不同的实现方法,比如SQL中使用case+group,或者Power BI的M语言中用拖放组件实现。今天正好需要在pyspark中处理一个数据行列转换,就把这个方法记录下来。
首先明确一下啥叫行列转换,因为这个叫法也不是很统一,有的地方叫转置,有的地方叫透视,不一而足。我们就以下图为例,定义如下:
- 从左边这种变成右边这种,叫透视(pivot)
- 反之叫逆透视(unpivot)
Spark实现
构造样本数据
首先我们构造一个以行格式保存数据的数据集
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('JupyterPySpark').enableHiveSupport().getOrCreate() import pyspark.sql.functions as F # 原始数据
df = spark.createDataFrame([('2018-01','项目1',100), ('2018-01','项目2',200), ('2018-01','项目3',300),
('2018-02','项目1',1000), ('2018-02','项目2',2000), ('2018-03','项目x',999)
], ['年月','项目','收入'])
样本数据如下,我们可以看到,每一个项目在指定月份都只有一行记录,并且项目是稀疏的。即,不是每个项目都会出现在每一个月份中,如项目2仅出现在2018-01当中。
+-------+---+----+
| 年月| 项目| 收入|
+-------+---+----+
|2018-01|项目1| 100|
|2018-01|项目2| 200|
|2018-01|项目3| 300|
|2018-02|项目1|1000|
|2018-02|项目2|2000|
|2018-03|项目x| 999|
+-------+---+----+
透视Pivot
透视操作简单直接,逻辑如下
- 按照不需要转换的字段分组,本例中是年月;
- 使用pivot函数进行透视,透视过程中可以提供第二个参数来明确指定使用哪些数据项;
- 汇总数字字段,本例中是收入;
代码如下
df_pivot = df.groupBy('年月')\
.pivot('项目', ['项目1','项目2','项目3','项目x'])\
.agg(F.sum('收入'))\
.fillna(0)
结果如下
+-------+----+----+---+---+
| 年月| 项目1| 项目2|项目3|项目x|
+-------+----+----+---+---+
|2018-03| 0| 0| 0|999|
|2018-02|1000|2000| 0| 0|
|2018-01| 100| 200|300| 0|
+-------+----+----+---+---+
逆透视Unpivot
Spark没有提供内置函数来实现unpivot操作,不过我们可以使用Spark SQL提供的stack函数来间接实现需求。有几点需要特别注意:
- 使用selectExpr在Spark中执行SQL片段;
- 如果字段名称有中文,要使用反引号**`** 把字段包起来;
代码如下
df_pivot.selectExpr("`年月`",
"stack(4, '项目1', `项目1`,'项目2', `项目2`, '项目3', `项目3`, '项目x', `项目x`) as (`项目`,`收入`)")\
.filter("`收入` > 0 ")\
.orderBy(["`年月`", "`项目`"])\
.show()
结果如下
+-------+---+----+
| 年月| 项目| 收入|
+-------+---+----+
|2018-01|项目1| 100|
|2018-01|项目2| 200|
|2018-01|项目3| 300|
|2018-02|项目1|1000|
|2018-02|项目2|2000|
|2018-03|项目x| 999|
+-------+---+----+
Reference:
https://juejin.im/post/5b1e343f518825137c1c6a27 掘金
【转】Spark实现行列转换pivot和unpivot的更多相关文章
- 通过sql做数据透视表,数据库表行列转换(pivot和Unpivot用法)(一)
在mssql中大家都知道可以使用pivot来统计数据,实现像excel的透视表功能 一.MSsqlserver中我们通常的用法 1.Sqlserver数据库测试 ---创建测试表 Create tab ...
- sql行列转换PIVOT与unPIVOT
基本语法 select * from Mould pivot ( count(ID)for ProductTypeCode in ( [FC], [RCU], [RCD] )) as PVT; wit ...
- SQL Fundamentals: 子查询 || 行列转换(PIVOT,UNPIVOT,DECODE),设置数据层次(LEVEL...CONNECT BY)
SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...
- SQL Server中行列转换 Pivot UnPivot
SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...
- SQL Server中行列转换 Pivot UnPivot
PIVOT用于将列值旋转为列名(即行转列),在SQLServer 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVOT(聚合函数(列)FOR 列 in (-) )AS P 完 ...
- SQLServer中行列转换Pivot UnPivot
PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )AS P ...
- 多列的行列转换(PIVOT,UNPIVOT)
形式1 形式2 形式3 有时候可能会有这样的需求: 将一张表的所有列名转做为数据的一列数据,将一列数据作为整张表的列名 当列比较多时,只用PIVOT是解决不了的,经过研究,需要将UNPIVOT 和 P ...
- SQL中行列转换Pivot
--建表 ),课程 ),分数 int) --插入数据 ) ) ) ) ) ) 1.静态行转列(确定有哪些列) select 姓名, end)语文, end)数学, end)物理 from tb gro ...
- 行列转换 pivot
select * from ( select isnull(c.type,'其他') type,d from ( select ID,Record_code,code,day(thedate) d f ...
随机推荐
- 结合JDK源码看设计模式——享元模式
前言 在说享元模式之前,你一定见到过这样的面试题 public class Test { public static void main(String[] args) { Integer a=Inte ...
- 关于token和refresh token
最近在做公司的认证系统,总结了如下一番心得. 传统的认证方式一般采用cookie/session来实现,这是我们的出发点. 1.为什么选用token而不选用cookie/session? 本质上tok ...
- NLP&深度学习:近期趋势概述
NLP&深度学习:近期趋势概述 摘要:当NLP遇上深度学习,到底发生了什么样的变化呢? 在最近发表的论文中,Young及其同事汇总了基于深度学习的自然语言处理(NLP)系统和应用程序的一些最新 ...
- 虚拟主机、VPS主机与云服务器的区别
本文转载自星光云 http://www.365yun.top/news/list.asp?newsid=22 虚拟主机是利用虚拟技术将一台物理服务器划分成多个“虚拟”服务器,虚拟主机的出现大大节省了服 ...
- JMeter中文返回乱码
JMeter中文返回乱码 结果树响应数据中文返回乱码 其实有几个方法: 在线程组->http请求的字符集里设置 在http 消息管理头中设置 3.如果以上方法还没有解决,请打开安装目录 ...
- 电脑一键U盘启动快捷键
下面是我特意列出的品牌电脑.笔记本电脑.组装电脑一键U盘启动快捷键对应列表,仅供大家查阅参考! [品牌-笔记本电脑] 笔记本品牌 启动按键 联想笔记本 F12 宏基笔记本 F12 华硕笔记本 ...
- js计算剩余分钟
// 剩余时间提醒 function checkTime() { if (timeCompare()) { document.getElementById('distanceDeadline').in ...
- 云服务器挂载/dev/vdb1磁盘
1.首先检查是否有一块硬盘还未被挂载 2.如图所示,vdb还未被使用,开始分配它吧 [root@localhost ~]# fdisk /dev/vdb Command (m for help): n ...
- 数据库之redis篇(1)—— redis数据库安装,简单使用
简介 reids,由Salvatore Sanfilippo写的一个高性能的key-value数据库,并且它是非关系型数据库,也就是没有像mysql那样多表链接操作,并且它是是完全开源免费的,遵守BS ...
- python ----面向对象的三大特性---多态
多态 多态 不同的子类对象调用相同的父类方法,产生不同的执行结果. 以继承和重写父类方法为前提