python
transaction['purchase_day_diff'] = transaction.groupby("card_id")['purchase_day'].diff()
等价于 SQL 里的窗口函数:
sql
SELECT
card_id,
purchase_day,
-- 按用户分组,按时间排序,取上一行的 purchase_day,即LAG使时间滞后一步(后移一格),反之,LEAD = 超前一步(前移一格)
LAG(purchase_day) OVER (PARTITION BY card_id ORDER BY purchase_day) AS prev_day,
-- 当前天 - 上一天 = 时间差
purchase_day - LAG(purchase_day) OVER (PARTITION BY card_id ORDER BY purchase_day) AS purchase_day_diff
FROM transaction
一、该python语句等价于 SQL 里的窗口函数
groupby(列).diff() = SQL 的 LAG() 窗口函数,算组内行与行的差值!
1、实现功能
按每个用户分组,把他的交易按时间排序,然后算:当前交易日期 - 上一次交易日期 = 间隔天数
假设交易表:
| card_id | purchase_day |
|---|---|
| user1 | 10 |
| user1 | 15 |
| user1 | 20 |
| user2 | 5 |
| user2 | 9 |
执行:
python
groupby("card_id")['purchase_day'].diff()
得到:
| card_id | purchase_day | purchase_day_diff |
|---|---|---|
| user1 | 10 | NaN(第一笔,没有上一笔) |
| user1 | 15 | 5(15-10) |
| user1 | 20 | 5(20-15) |
| user2 | 5 | NaN |
| user2 | 9 | 4(9-5) |
2、对应 SQL
运行结果一模一样
sql
SELECT
card_id,
purchase_day,
purchase_day - LAG(purchase_day) OVER(PARTITION BY card_id ORDER BY purchase_day) AS purchase_day_diff
FROM transaction
结果:
| card_id | purchase_day | purchase_day_diff |
|---|---|---|
| user1 | 10 | NULL |
| user1 | 15 | 5 |
| user1 | 20 | 5 |
| user2 | 5 | NULL |
| user2 | 9 | 4 |
这里的窗口函数做了什么?
- 按用户分窗口:OVER(PARTITION BY)
- 排序:ORDER BY
- LAG 取上一行:LAG(purchase_day)
- 手动减法 = diff:purchase_day - LAG(purchase_day)
二、SQL的窗口函数
前面提到SQL的窗口函数,这里专门讲讲。
窗口函数 = 对一组内行与行之间互相计算,但不把多行压成一行(保留原行数)
对比:
- GROUP BY:多行 → 一行(汇总)
- 窗口函数:多行 → 还是多行(行与行之间计算)
1、普通聚合(GROUP BY)------压扁
sql
SELECT card_id, SUM(amount) FROM transaction GROUP BY card_id
结果:一个用户一行
2、窗口函数 ------不压扁,每行都保留
sql
SELECT card_id, SUM(amount) OVER (PARTITION BY card_id)
结果:多少行,还是多少行,但每一行都带上了该用户的总和
窗口函数结构(固定格式)
sql
函数() OVER (
PARTITION BY 列1, 列2 -- 分组(窗口)
ORDER BY 排序列 -- 组内排序
)
三部分:
- OVER:标志这是窗口函数
- PARTITION BY:把数据分成多个小组(窗口)
- ORDER BY:组内按什么顺序排
| 方式 | 结果行数 | 作用 |
|---|---|---|
| GROUP BY | 减少(每组1行) | 汇总统计 |
| 窗口函数 | 不变(原行数) | 行与行之间计算 |
三、其它类似的对应关系
1、核心对应规则
python
df.groupby(分组列)[统计列].聚合函数()
完全等价 SQL:
sql
SELECT 分组列, 聚合函数(统计列)
FROM df
GROUP BY 分组列
2、 对应举例
1)groupby + sum
python
transaction.groupby("card_id")["purchase_amount"].sum()
SQL:
sql
SELECT card_id, SUM(purchase_amount)
FROM transaction
GROUP BY card_id
含义:每个用户总消费金额
2)groupby + mean
python
transaction.groupby("card_id")["purchase_amount"].mean()
SQL:
sql
SELECT card_id, AVG(purchase_amount)
FROM transaction
GROUP BY card_id
含义:每个用户平均消费金额
3)groupby + count
python
transaction.groupby("card_id")["purchase_amount"].count()
SQL:
sql
SELECT card_id, COUNT(purchase_amount)
FROM transaction
GROUP BY card_id
含义:每个用户有多少笔交易(非空)
4)groupby + size
python
transaction.groupby("card_id").size()
SQL:
sql
SELECT card_id, COUNT(*)
FROM transaction
GROUP BY card_id
含义:每个用户总交易笔数(不管空值)
5)groupby + nunique(去重计数)
python
transaction.groupby("card_id")["merchant_category_id"].nunique()
SQL:
sql
SELECT card_id, COUNT(DISTINCT merchant_category_id)
FROM transaction
GROUP BY card_id
含义:每个用户消费过多少个不同商户类别
6)groupby + min / max
python
transaction.groupby("card_id")["purchase_amount"].min()
transaction.groupby("card_id")["purchase_amount"].max()
SQL:
sql
SELECT card_id, MIN(purchase_amount), MAX(purchase_amount)
FROM transaction
GROUP BY card_id
7)groupby + diff(本文开头提到的)
python
transaction.groupby("card_id")["purchase_day"].diff()
SQL:
sql
purchase_day - LAG(purchase_day) OVER (PARTITION BY card_id ORDER BY purchase_day)
3、多列聚合(pandas agg → SQL GROUP BY 多函数)
python
transaction.groupby("card_id").agg({
"purchase_amount": ["sum", "mean", "max"],
"merchant_id": "nunique",
"card_id": "size"
})
对应 SQL:
sql
SELECT
card_id,
SUM(purchase_amount),
AVG(purchase_amount),
MAX(purchase_amount),
COUNT(DISTINCT merchant_id),
COUNT(*)
FROM transaction
GROUP BY card_id
4、它们是包pandas的API功能
上述提到的这些函数 全部属于 pandas
python
groupby()
sum()
mean()
count()
size()
nunique()
min()
max()
diff()
agg()
👉 全部是 pandas.DataFrame / pandas.Series 的方法
你必须导入 pandas 才能用
python
import pandas as pd
没有这句,上面所有函数都不存在。
它们是 pandas 自己实现的数据分析 API ,语法风格模仿 SQL,但底层是 pandas。
附:取行、取列、新建列
回到开头的这句代码:
python
transaction['purchase_day_diff'] = transaction['purchase_day']...
左侧的中括号中是字符串!!
在交易表
transaction里,新建一列 ,名字叫purchase_day_diff,然后把右边计算好的"时间差"数据存进去。
pandas 设计就是:
中括号里写字符串 = 操作列
中括号里写数字 = 操作行
中括号里写字符串:右边取列,左边建列!
左边(等号左边)
python
transaction['purchase_day_diff'] =...
→ 新建一列 ,名字叫 purchase_day_diff
右边(等号右边)
python
...= transaction['purchase_day']...
→ 取出 purchase_day 这一列 用来计算