我有一些来自 Google Sheets 的数据,其中有一个多答案问题,如下所示:
Q1 Q2 ... Multi-Response
0 ... ... ... "A; B"
1 ... ... ... "B; C"
2 ... ... ... "D; F"
3 ... ... ... "A; B; F"
(请注意空格,分隔符是
'; '
,这是出于奇怪的解决方法原因,调查作者编写问题的方式以及 Google 表格选择输出响应表的方式)
我正在尝试扩展它,这样我就可以对其进行一些 k 模式聚类:
Q1 Q2 ... A B C D F
0 ... ... ... 1 1 0 0 0
1 ... ... ... 0 1 1 0 0
2 ... ... ... 0 0 0 1 1
3 ... ... ... 1 1 0 0 1
这个想法或多或少地将每个响应列表映射到一系列“你同意吗?是/否”问题。
但我不太清楚如何将数据帧转换为该格式。我尝试使用
pivot_table
和 get_dummies
,但如果它可以做到这一点,我不清楚它到底是如何工作的。
我可以通过
获取回复表multi_selection_question = data.keys()[-1]
expanded = data[multi_selection_question].str.split('; ', expand=True)
产生类似的东西
0 1 2
0 A B None
1 B C None
2 D F None
3 A B F
以及一个问题列表,这些问题将是正确的列名称:
questions = pandas.Series(expanded.values.flatten()).unique()
但是我看到的
pivot_table
或 get_dummies
的示例似乎需要不同格式的数据,并且列结构比输出的更一致。例如,使用 get_dummies
为每个 (column,question)
对创建一个单独的类别,因此对于上面的示例表 - 2_F
、3_F
、1_B
、2_B
等
当然,我可以求助于几个循环并逐行构建一个新的数据框并
concat
它,但是通常pandas中有更好的方法。
str.get_dummies
与 sep='; '
一起使用:
out = (df.drop(columns='Multi-Response')
.join(df['Multi-Response'].str.get_dummies(sep='; '))
)
由于分隔符必须是固定字符串,因此如果输入中有可变数量的空格,则应使用
str.replace
: 进行预处理
out = (df.drop(columns='Multi-Response')
.join(df['Multi-Response']
.str.replace('; *', '|', regex=True)
.str.get_dummies())
)
输出:
Q1 Q2 A B C D F
0 ... ... 1 1 0 0 0
1 ... ... 0 1 1 0 0
2 ... ... 0 0 0 1 1
3 ... ... 1 1 0 0 1
如果您有多个答案栏,例如:
Q1 Q2 A1 A2
0 ... ... A; B A; E
1 ... ... B; C B
2 ... ... D; F D; E; F
3 ... ... A; B; F C
然后,处理所有列:
cols = df.columns[df.columns.str.startswith('A')]
# ['A1', 'A2']
out = (df.drop(columns=cols)
.join(pd.concat([df[c].str.get_dummies('; ')
.add_prefix(f'{c}_')
for c in cols], axis=1)
)
)
输出:
Q1 Q2 A1_A A1_B A1_C A1_D A1_F A2_A A2_B A2_C A2_D A2_E A2_F
0 ... ... 1 1 0 0 0 1 0 0 0 1 0
1 ... ... 0 1 1 0 0 0 1 0 0 0 0
2 ... ... 0 0 0 1 1 0 0 0 1 1 1
3 ... ... 1 1 0 0 1 0 0 1 0 0 0
带有
enumerate
的变体可自动递增前缀:
cols = df.columns[df.columns.str.startswith('A')]
# ['A1', 'A2']
out = (df.drop(columns=cols)
.join(pd.concat([df[c].str.get_dummies('; ')
.add_prefix(f'{i}_')
for i, c in enumerate(cols, start=1)],
axis=1)
)
)
输出:
Q1 Q2 1_A 1_B 1_C 1_D 1_F 2_A 2_B 2_C 2_D 2_E 2_F
0 ... ... 1 1 0 0 0 1 0 0 0 1 0
1 ... ... 0 1 1 0 0 0 1 0 0 0 0
2 ... ... 0 0 0 1 1 0 0 0 1 1 1
3 ... ... 1 1 0 0 1 0 0 1 0 0 0
您可以尝试以下方法:
import pandas as pd
# sample data
data = pd.DataFrame({'Question': ["A; B", "B; C", "A; D", "A; B; C; D", "A; B; D"]})
print(data)
它给出:
Question
0 A; B
1 B; C
2 A; D
3 A; B; C; D
4 A; B; D
然后:
df1 = data["Question"].str.split('; ', expand=True).stack()
df2 = pd.crosstab(index=df1.index.get_level_values(0), columns=df1)
df2.index.name = None
df2.columns.name = None
print(df2)
结果:
A B C D
0 1 1 0 0
1 0 1 1 0
2 1 0 0 1
3 1 1 1 1
4 1 1 0 1