
本文详细介绍了如何利用 Python Pandas 库高效地处理多重响应(Multiple Response)数据,并生成交叉分析表。核心方法包括使用 `melt` 函数将宽格式数据转换为长格式,再结合 `groupby` 和 `pivot_table` 进行数据聚合与透视,最终实现多重响应变量与目标变量的交叉分析,并支持计算列百分比。
在市场调研或问卷分析中,多重响应问题(Multiple Response Questions)非常常见,即受访者可以从多个选项中选择一个或多个答案。例如,“您通过哪些渠道了解我们的产品?”(可多选)。在数据集中,这类问题通常被表示为多个二元变量(0/1 或有/无),或者如本例所示,每个选项占据一个独立的列,如果被选中则填写具体值,未选中则为空。
传统的数据分析方法,如直接使用 pd.crosstab 或 pivot_table,难以直接处理这种宽格式的多重响应数据。主要挑战在于:
解决多重响应交叉表问题的关键在于将数据从“宽格式”转换为“长格式”。一旦数据处于长格式,每个响应选项都成为独立的一行,就可以像处理常规分类变量一样进行聚合和透视。Pandas 提供了 melt、groupby 和 pivot_table 等强大工具来完成这一转换和分析。
我们将以一个示例数据集为例,演示如何生成一个多重响应变量(如 Q2 包含 Q2_1, Q2_2, Q2_3)与另一个分类变量(Q3)的交叉表。
假设我们有以下数据,其中 Q2_1、Q2_2、Q2_3 是多重响应问题 Q2 的各个选项,Q3 是一个二元分类变量:
import io
import pandas as pd
data = '''Q2_1,Q2_2,Q2_3,Q3
Na loja,Email,Folheto,Sim
Na loja,,,Não
Na loja,Email,,Sim
,,Folheto,Sim'''
df = pd.read_csv(io.StringIO(data), sep=',', engine='python')
print("原始数据集:")
print(df)输出:
原始数据集:
Q2_1 Q2_2 Q2_3 Q3
0 Na loja Email Folheto Sim
1 Na loja NaN NaN Não
2 Na loja Email NaN Sim
3 NaN NaN Folheto Simmelt 函数可以将 DataFrame 从宽格式重塑为长格式。对于多重响应数据,我们可以将所有表示响应选项的列“融化”到一个新的列中,而将其他不需融化的列(如 Q3)保留为标识符变量。
在本例中,Q3 是标识符变量 (id_vars),Q2_1、Q2_2、Q2_3 是需要融化的值变量 (value_vars)。
# 确定需要融化的多重响应列
multiple_response_cols = ['Q2_1', 'Q2_2', 'Q2_3']
# 使用 melt 函数将多重响应列转换为长格式
# id_vars: 保持不变的列
# value_vars: 需要融化的列
# dropna=True: 移除由于NaN值产生的行,因为NaN表示未选择该选项
dfm = df.melt(id_vars=['Q3'], value_vars=multiple_response_cols, dropna=True)
# 移除 melt 自动生成的 'variable' 列,因为它在本场景中不重要
dfm = dfm.drop('variable', axis=1)
print("\n经过 melt 转换后的长格式数据:")
print(dfm)输出:
经过 melt 转换后的长格式数据:
Q3 value
0 Sim Na loja
1 Não Na loja
2 Sim Na loja
4 Sim Email
6 Sim Email
8 Sim Folheto
11 Sim Folheto现在,每个 Q2 的有效响应都独立成一行,并且与对应的 Q3 值关联。value 列包含了具体的响应选项(如“Na loja”、“Email”)。
在长格式数据 dfm 的基础上,我们可以使用 groupby 进行分组计数,然后通过 pivot_table 将结果重新整形为交叉表。
分组计数 (groupby): 我们将数据按 value(响应选项)和 Q3(目标变量)进行分组,并计算每个组的行数。
# 按响应选项和Q3分组,并计数
dfg = dfm.groupby(['value', 'Q3']).agg(count=('value', 'count')).reset_index()
print("\n分组计数结果:")
print(dfg)输出:
分组计数结果: value Q3 count 0 Email Sim 2 1 Folheto Sim 2 2 Na loja Não 1 3 Na loja Sim 2
透视表 (pivot_table): 现在,我们可以将 dfg 转换为最终的交叉表格式,其中 value 作为行索引,Q3 作为列。
# 使用 pivot_table 将分组计数结果转换为交叉表
# index: 行索引 (多重响应选项)
# columns: 列 (目标变量 Q3)
# values: 聚合值 (计数)
# aggfunc: 聚合函数 (求和)
# fill_value: 填充缺失值 (用0填充未出现的组合)
dff = pd.pivot_table(dfg, values='count', index=['value'], columns=['Q3'], aggfunc="sum", fill_value=0)
print("\n最终交叉表 (绝对值):")
print(dff)输出:
最终交叉表 (绝对值): Q3 Não Sim value Email 0 2 Folheto 0 2 Na loja 1 2
这个结果清晰地展示了每个多重响应选项在不同 Q3 类别下的出现次数。
在得到绝对值的交叉表后,计算列百分比是一个常见的需求。这可以通过将每列的元素除以该列的总和来实现。
# 计算列百分比
# dff.sum(axis=0) 计算每列的总和
# dff.div(..., axis=1) 将 dff 的每个元素除以对应列的总和
dff_percentage = dff.div(dff.sum(axis=0), axis=1) * 100
print("\n最终交叉表 (列百分比):")
print(dff_percentage)输出:
最终交叉表 (列百分比): Q3 Não Sim value Email 0.000000 33.333333 Folheto 0.000000 33.333333 Na loja 100.000000 33.333333
现在,交叉表显示的是每个响应选项在对应 Q3 类别中所占的百分比。例如,在 Q3 为“Não”的受访者中,100%选择了“Na loja”。
为了提高代码的复用性,可以将上述逻辑封装到一个函数中。这个函数可以接受 DataFrame、多重响应列列表、交叉分析的目标列以及一个用于指定是否计算百分比的参数。
def calculate_multiple_response_crosstab(
dataframe: pd.DataFrame,
multiple_response_cols: list,
target_col: str,
as_percentage: bool = False
) -> pd.DataFrame:
"""
计算多重响应变量与目标变量的交叉表。
参数:
dataframe (pd.DataFrame): 原始数据集。
multiple_response_cols (list): 包含多重响应选项的列名列表。
target_col (str): 用于交叉分析的目标列名。
as_percentage (bool): 如果为 True,则返回列百分比;否则返回绝对计数。
返回:
pd.DataFrame: 生成的交叉表。
"""
# 1. 数据转换:使用 melt 函数
df_melted = dataframe.melt(
id_vars=[target_col],
value_vars=multiple_response_cols,
dropna=True # 忽略未选择的选项
).drop('variable', axis=1) # 移除 melt 自动生成的 'variable' 列
# 2. 数据聚合与透视:groupby 和 pivot_table
# 首先进行分组计数
df_grouped = df_melted.groupby(['value', target_col]).size().reset_index(name='count')
# 然后进行透视
crosstab_df = pd.pivot_table(
df_grouped,
values='count',
index=['value'],
columns=[target_col],
aggfunc="sum",
fill_value=0
)
# 3. 计算列百分比(如果需要)
if as_percentage:
# 避免除以零,处理所有列总和为零的情况
col_sums = crosstab_df.sum(axis=0)
# 对于所有总和为0的列,百分比也应为0
crosstab_df = crosstab_df.div(col_sums.replace(0, 1), axis=1) * 100
# 将原来总和为0的列对应的百分比重新设置为0
crosstab_df.loc[:, col_sums == 0] = 0.0
return crosstab_df
# 使用函数示例
# 绝对值交叉表
crosstab_abs = calculate_multiple_response_crosstab(df, multiple_response_cols, 'Q3', as_percentage=False)
print("\n通过函数生成的绝对值交叉表:")
print(crosstab_abs)
# 列百分比交叉表
crosstab_pct = calculate_multiple_response_crosstab(df, multiple_response_cols, 'Q3', as_percentage=True)
print("\n通过函数生成的列百分比交叉表:")
print(crosstab_pct)这个函数增强了灵活性,能够根据需求生成绝对计数或列百分比的交叉表。
通过 Pandas 的 melt、groupby 和 pivot_table 组合,我们可以优雅且高效地处理多重响应数据,并生成清晰的交叉分析表。这种方法将复杂的多重响应问题转化为标准的数据透视问题,极大地简化了分析流程,并提供了灵活的输出选项,如绝对计数或百分比。掌握这些技巧对于进行深入的数据探索和报告至关重要。
以上就是使用 Pandas 处理多重响应数据交叉表的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号