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

高效筛选满足受访者数量要求的问卷问题组合

高效找出满足条件的问卷问题组

问题背景

我有一个存储问卷编码答案的DataFrame,每行对应一位受访者,每列对应一个问题。由于问卷存在跳题逻辑,并非所有受访者都回答了相同问题,因此这是一个包含NaN的稀疏DataFrame。示例数据及生成代码如下:

import pandas as pd
import numpy as np

# 创建示例DataFrame
prng = np.random.RandomState(42)
df = pd.DataFrame(prng.randint(0,5, size=(10, 3)), columns=['Q1','Q2','Q3'])
# 随机添加NaN模拟跳题
df = df.mask(np.random.random(df.shape) < .3)
print(df)

输出的示例DataFrame:

Q1   Q2   Q3
0  3.0  4.0  2.0
1  4.0  4.0  NaN
2  2.0  NaN  2.0
3  4.0  NaN  2.0
4  4.0  NaN  3.0
5  NaN  3.0  4.0
6  0.0  NaN  NaN
7  4.0  3.0  NaN
8  0.0  NaN  2.0
9  NaN  3.0  3.0

实际场景中,这个DataFrame规模约为40000行、700列,需要找出至少包含n个问题、且被至少x位受访者全部回答的问题组。

基础方法的局限性

原尝试用itertools.combinations生成所有列的组合,再逐个计算符合条件的受访者数量。但对于700列的数据集,全量组合数是天文数字(仅2列组合就有C(700,2)=244650个,n越大组合数爆炸式增长),完全无法处理大规模数据。

高效解决方案

核心思路

基于受访者实际回答的问题集合来统计子集,避免遍历所有无意义的列组合:

  1. 提取每位受访者实际回答的问题集合(过滤掉NaN对应的列)
  2. 统计每个问题集合的出现次数
  3. 对每个问题集合,生成其所有长度≥n的子集,并累加每个子集的受访者数量
  4. 筛选出受访者数量≥x的子集

代码实现

import pandas as pd
import numpy as np
from itertools import combinations
from collections import defaultdict

# 生成示例数据(实际场景可直接读入你的DataFrame)
prng = np.random.RandomState(42)
df = pd.DataFrame(prng.randint(0,5, size=(10, 3)), columns=['Q1','Q2','Q3'])
df = df.mask(np.random.random(df.shape) < .3)

# 1. 提取每位受访者回答的问题集合
respondent_sets = []
for _, row in df.iterrows():
    answered = row.dropna().index.tolist()
    if answered:
        respondent_sets.append(frozenset(answered))

# 2. 统计每个问题集合的出现次数
set_counter = defaultdict(int)
for s in respondent_sets:
    set_counter[s] += 1

# 3. 统计所有符合长度要求的子集的受访者数量
min_num_questions = 2
subset_counter = defaultdict(int)

for question_set, cnt in set_counter.items():
    set_len = len(question_set)
    if set_len < min_num_questions:
        continue
    # 生成该集合所有长度≥min_num_questions的子集
    for k in range(min_num_questions, set_len + 1):
        for subset in combinations(question_set, k):
            subset_counter[subset] += cnt

# 4. 筛选出满足受访者数量要求的组
min_num_respondents = 3
final_groups = [
    (subset, count) 
    for subset, count in subset_counter.items() 
    if count >= min_num_respondents
]

# 按受访者数量降序、问题数量升序排序
final_groups.sort(key=lambda x: (-x[1], len(x[0])))
print(final_groups)

输出结果:

[(('Q1', 'Q3'), 5), (('Q1', 'Q2'), 3), (('Q2', 'Q3'), 3)]

性能优化说明

  • 仅基于实际存在的回答集合生成子集,跳过了所有无受访者完整回答的列组合,大幅减少计算量
  • 若受访者平均回答的问题数量远小于总列数(700),则子集生成的开销会非常可控
  • 可通过multiprocessing模块并行处理不同的问题集合,进一步提升大数据集下的处理速度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:35:19