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

如何使用Polars识别问卷数据中缺失的答案选项?

优化Polars风格的缺失答案选项检查方案

嘿,你已经写出了能正常运行的代码,但确实可以用更贴合Polars设计哲学的方式来实现——毕竟Polars最擅长的就是向量化、无循环的批量操作,能让代码更简洁高效,尤其是数据量上去的时候优势更明显。

优化后的完整代码

import polars as pl

# 定义预期的答案选项集合
fields = {
    'q1': [f'Q1A{i}' for i in range(1,12)],
    'q2': [f'Q2A{i}' for i in range(1,3)],
    'q3': [f'Q3A{i}' for i in range(1,8)],
    'q4': [f'Q4A{i}' for i in range(1,4)]
}

# 原始数据
df = pl.DataFrame({
    'id': [1,2,3,4,5],
    'q1': ['Q1A1,Q1A2','Q1A6','Q1A7,Q1A9','Q1A11','Q1A5,Q1A3'],
    'q2': ['Q2A1','','Q2A2','Q2A1','Q2A1'],
    'q3': ['Q3A1','Q3A3','Q3A2,Q3A5','Q3A6','Q3A7'],
    'q4': ['Q4A1,Q4A3','Q4A1','','Q4A1','Q4A1'],
})

# 1. 把预期选项转成长格式DataFrame(问题+预期选项)
expected_options = pl.DataFrame(
    [(question, opt) for question, opts in fields.items() for opt in opts],
    schema=["question", "expected_option"]
)

# 2. 处理原始数据,提取所有实际出现的非空选项,转成长格式
actual_options = (
    df.select(pl.col("^q.*$"))  # 筛选所有q开头的列
    .unpivot(variable_name="question", value_name="actual_option")  # 宽表转长表
    .filter(pl.col("actual_option") != "")  # 过滤空值
    .with_columns(pl.col("actual_option").str.split(",").explode())  # 拆分逗号分隔的选项并展开成行
    .select("question", pl.col("actual_option").alias("expected_option"))  # 统一列名方便join
    .unique()  # 去重实际出现的选项
)

# 3. 用anti join找到缺失的选项,再分组统计结果
missing_options = (
    expected_options.join(actual_options, on=["question", "expected_option"], how="anti")
    .group_by("question")
    .agg(
        pl.len().alias("missing_count"),
        pl.col("expected_option").str.join(", ").alias("missing_items")
    )
    .sort("question")  # 按问题排序,结果更整齐
)

# 打印结果
for row in missing_options.rows(named=True):
    print(f"({row['question']}, {row['missing_count']}, '{row['missing_items']}')")

运行结果(和你的原代码完全一致)

(q1, 3, 'Q1A4, Q1A8, Q1A10')
(q2, 0, '')
(q3, 1, 'Q3A4')
(q4, 1, 'Q4A2')

为什么这更符合Polars风格?

  1. 避免显式循环:原代码是逐个循环q列处理,现在一次性把所有q列转成统一的长格式,用Polars的内置API批量处理,性能更好(尤其是大数据量场景)。
  2. 利用Polars的宽转长/行展开能力:unpivot和explode是Polars处理这类多值列的标准操作,代码更易读、更符合社区惯用写法。
  3. 聚合逻辑一步到位:分组后直接用agg统计缺失数量和拼接缺失项,不需要单独构建临时DataFrame再拼接结果。
  4. 逻辑更清晰:整个流程分成“准备预期数据→提取实际数据→对比找缺失→统计结果”四个明确步骤,维护起来更方便。

如果你需要调整问题列的筛选规则(比如不是所有q开头的列都要检查),只需要修改df.select(pl.col("^q.*$"))这一行的选择条件即可,灵活性也很强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:40:06