提取对是/否标识符的多个稀疏打包响应,同时保留行信息

问题描述 投票:0回答:2

我有一些来自 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中有更好的方法。

python pandas google-sheets
2个回答
2
投票

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

1
投票

您可以尝试以下方法:

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
© www.soinside.com 2019 - 2024. All rights reserved.