You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python/SQL长表转宽表并生成全数据组合的高效实现方案

高效实现长表转宽表并生成客户维度全组合的方案

需求概述

需要将长格式的客户-月份-问题数据转换为宽格式,生成每个客户在各月份下所有可能的问题组合,最终统计不同组合模式的客户数量。

输入数据:

CUSTOMER    MONTH   ISSUE
1   M1  ABC
1   M1  DEF
1   M2  ABC
1   M3  QRS
2   M1  PQR
2   M2  PQR
2   M2  ABC
2   M3  DEF

期望输出(宽表组合):

CUSTOMER    M1  M2  M3
1   ABC ABC QRS
1   DEF ABC QRS
2   PQR PQR DEF
2   PQR ABC DEF

现有问题:SQL自连接会因数据量庞大导致性能极差;常规Pivot(Python/SQL)无法处理同一客户-月份下的重复Issue,Python中会抛出ValueError: Index contains duplicate entries, cannot reshape。


Python 高效解决方案

核心思路是先按客户分组聚合各月份的Issue列表,再通过笛卡尔积生成所有组合,避免直接Pivot的重复索引问题。

代码实现

import pandas as pd
from itertools import product

# 读取输入数据
df = pd.DataFrame({
    "CUSTOMER": [1,1,1,1,2,2,2,2],
    "MONTH": ["M1","M1","M2","M3","M1","M2","M2","M3"],
    "ISSUE": ["ABC","DEF","ABC","QRS","PQR","PQR","ABC","DEF"]
})

# 1. 按客户+月份分组,聚合Issue为列表
grouped = df.groupby(["CUSTOMER", "MONTH"])["ISSUE"].apply(list).unstack()

# 2. 对每个客户生成各月份Issue的笛卡尔积
result = []
for idx, row in grouped.iterrows():
    # 过滤掉空值(如果有客户缺失某个月份数据)
    valid_lists = [lst for lst in row.values if isinstance(lst, list)]
    # 生成所有组合
    for combo in product(*valid_lists):
        result.append({
            "CUSTOMER": idx,
            "M1": combo[0],
            "M2": combo[1],
            "M3": combo[2]
        })

# 3. 转换为DataFrame
wide_df = pd.DataFrame(result)

# 4. 统计不同模式的客户数量(按M1-M3组合分组,计数不同客户)
pattern_count = wide_df.groupby(["M1", "M2", "M3"])["CUSTOMER"].nunique().reset_index(name="CUSTOMER_COUNT")

print("宽表组合结果:")
print(wide_df)
print("\n模式统计结果:")
print(pattern_count)

优势

  • 仅在分组后的小范围数据上生成笛卡尔积,避免全量数据的交叉计算,性能远优于SQL自连接
  • 天然处理同一月份的重复Issue,无需额外去重

SQL 高效解决方案(以PostgreSQL为例)

利用数组聚合+unnest函数实现笛卡尔积,避免多次自连接的性能损耗。

代码实现

-- 1. 按客户分组,聚合各月份的Issue为数组
WITH customer_month_issues AS (
    SELECT
        CUSTOMER,
        ARRAY_AGG(DISTINCT ISSUE) FILTER (WHERE MONTH = 'M1') AS m1_issues,
        ARRAY_AGG(DISTINCT ISSUE) FILTER (WHERE MONTH = 'M2') AS m2_issues,
        ARRAY_AGG(DISTINCT ISSUE) FILTER (WHERE MONTH = 'M3') AS m3_issues
    FROM your_table
    GROUP BY CUSTOMER
),
-- 2. 生成每个客户的所有组合
customer_combinations AS (
    SELECT
        CUSTOMER,
        m1 AS M1,
        m2 AS M2,
        m3 AS M3
    FROM customer_month_issues,
         UNNEST(m1_issues) AS m1,
         UNNEST(m2_issues) AS m2,
         UNNEST(m3_issues) AS m3
)
-- 3. 统计不同模式的客户数量
SELECT
    M1,
    M2,
    M3,
    COUNT(DISTINCT CUSTOMER) AS CUSTOMER_COUNT
FROM customer_combinations
GROUP BY M1, M2, M3;

优势

  • 用数组聚合减少中间数据量,UNNEST+交叉连接比多次自连接更高效
  • 支持大表场景,数据库引擎会优化数组和嵌套循环的执行计划

内容的提问来源于stack exchange,提问作者Anjana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:17:32