【问题标题】:Process multiple-answer questionnaire (from Google Forms) results with pandas使用 pandas 处理多答案问卷(来自 Google 表单)结果
【发布时间】:2022-01-07 04:56:34
【问题描述】:

我有一个用于收集调查数据的 Google 表单(对于这个问题,我将使用 example form),其中的问题可以有多个答案,使用一组复选框进行选择。

当我从表单中获取数据并将其导入 pandas 时,我得到以下信息:

             Timestamp    What sweets do you like?
0  23/11/2013 13:22:30  Chocolate, Toffee, Popcorn
1  23/11/2013 13:22:34                   Chocolate
2  23/11/2013 13:22:39      Toffee, Popcorn, Fruit
3  23/11/2013 13:22:45               Fudge, Toffee
4  23/11/2013 13:22:48                     Popcorn

我想对问题的结果进行统计(有多少人喜欢巧克力,有多少人喜欢太妃糖等)。问题是,所有答案都在一列中,因此按该列分组并要求计数是行不通的。

在 Pandas 中是否有一种简单的方法可以将这种数据框转换为一个有多个列的数据框,分别称为 Chocolate、Toffee、Popcorn、Fudge 和 Fruit,并且每个列都是布尔值(1 表示是,0 表示否) ?我想不出一个明智的方法来做到这一点,我不确定它是否真的有帮助(做我想做的聚合可能会更难)。

【问题讨论】:

    标签: python pandas google-forms


    【解决方案1】:

    几天前我遇到了同样的问题,经过一番搜索,我在 pandas 文档中找到了str.get_dummies 函数。让我们看看它是如何工作的:

    pandas.Series.str.get_dummies

    如文档中所述,str.get_dummiessep 拆分系列中的每个字符串,并返回一个包含虚拟/指标变量的 DataFrame。

    这是上面提到的DataFrame的简化版本:

    In [27]: df
    Out[27]: 
         What sweets do you like?
    0  Chocolate, Toffee, Popcorn
    1                   Chocolate
    2      Toffee, Popcorn, Fruit
    3               Fudge, Toffee
    4                     Popcorn
    

    我们需要在str.get_dummies 中指定的唯一参数是sep,在我们的例子中是逗号:

    In [28]: df['What sweets do you like?'].str.get_dummies(sep=', ')
    Out[28]: 
       Chocolate  Fruit  Fudge  Popcorn  Toffee
    0          1      0      0        1       1
    1          1      0      0        0       0
    2          0      1      0        1       1
    3          0      0      1        0       1
    4          0      0      0        1       0
    

    注意:

    注意sep参数中逗号后面有一个空格,因为空格本身就是一个字符,如果我们不将它包含在sep中,结果将是类似下面的内容显然是错误

    In [29]: df['What sweets do you like?'].str.get_dummies(sep=',')
    Out[29]: 
        Fruit   Popcorn   Toffee  Chocolate  Fudge  Popcorn  Toffee
    0       0         1        1          1      0        0       0
    1       0         0        0          1      0        0       0
    2       1         1        0          0      0        0       1
    3       0         0        1          0      1        0       0
    4       0         0        0          0      0        1       0
    

    根据经验,请始终注意准确书写分隔符!

    【讨论】:

      【解决方案2】:

      作为固定宽度的表格读入,删除第一列

      In [30]: df = pd.read_fwf(StringIO(data),widths=[3,20,27]).drop(['Unnamed: 0'],axis=1)
      
      In [31]: df
      Out[31]: 
                   Timestamp What sweets do you like0
      0  23/11/2013 13:22:34                Chocolate
      1  23/11/2013 13:22:39   Toffee, Popcorn, Fruit
      2  23/11/2013 13:22:45            Fudge, Toffee
      3  23/11/2013 13:22:48                  Popcorn
      

      将时间戳设置为适当的 datetime64 dtype(本练习不需要), 但几乎总是你想要的。

      In [32]: df['Timestamp'] = pd.to_datetime(df['Timestamp'])
      

      新列名

      In [33]: df.columns = ['date','sweets']
      
      In [34]: df
      Out[34]: 
                       date                  sweets
      0 2013-11-23 13:22:34               Chocolate
      1 2013-11-23 13:22:39  Toffee, Popcorn, Fruit
      2 2013-11-23 13:22:45           Fudge, Toffee
      3 2013-11-23 13:22:48                 Popcorn
      
      In [35]: df.dtypes
      Out[35]: 
      date      datetime64[ns]
      sweets            object
      dtype: object
      

      将甜蜜的列从一个字符串拆分成一个列表

      In [37]: df['sweets'].str.split(',\s*')
      Out[37]: 
      0                 [Chocolate]
      1    [Toffee, Popcorn, Fruit]
      2             [Fudge, Toffee]
      3                   [Popcorn]
      Name: sweets, dtype: object
      

      关键步骤,这将为存在值的位置创建一个虚拟矩阵

      In [38]: df['sweets'].str.split(',\s*').apply(lambda x: pd.Series(1,index=x))
      Out[38]: 
         Chocolate  Fruit  Fudge  Popcorn  Toffee
      0          1    NaN    NaN      NaN     NaN
      1        NaN      1    NaN        1       1
      2        NaN    NaN      1      NaN       1
      3        NaN    NaN    NaN        1     NaN
      

      我们将 nans 填充为 0,然后将 astype 填充为 bool 以使 True/False 成为最终结果。然后连接 它到原来的框架

      In [40]: pd.concat([df,df['sweets'].str.split(',\s*').apply(lambda x: pd.Series(1,index=x)).fillna(0).astype(bool)],axis=1)
      Out[40]: 
                       date                  sweets Chocolate  Fruit  Fudge Popcorn Toffee
      0 2013-11-23 13:22:34               Chocolate      True  False  False   False  False
      1 2013-11-23 13:22:39  Toffee, Popcorn, Fruit     False   True  False    True   True
      2 2013-11-23 13:22:45           Fudge, Toffee     False  False   True   False   True
      3 2013-11-23 13:22:48                 Popcorn     False  False  False    True  False
      

      【讨论】:

        【解决方案3】:

        这样的事情怎么样:

        #Create some data
        import pandas as pd
        import numpy as np
        Foods = ['Chocolate, Toffee, Popcorn', 'Chocolate', 'Toffee, Popcorn, Fruit', 'Fudge,     Toffee', 'Popcorn']
        Dates = ['23/11/2013 13:22:30', '23/11/2013 13:22:34', '23/11/2013 13:22:39', '23/11/2013 13:22:45', '23/11/2013 13:22:48']
        DF = pd.DataFrame(Foods, index = Dates, columns = ['Sweets'])
        
        #create unique list of foods
        UniqueFoods = ['Chocolate', 'Toffee', 'Popcorn', 'Fruit']
        
        # Create new data frame withy columns for each food type, with indenitcal index
        DFTransformed = pd.DataFrame({Food: 0 for Food in UniqueFoods}, index = DF.index)
        
         #iterate through your data and modify the second data frame according to your wishes
        for row in DF.index:
            for Food in UniqueFoods:
                if Food in DF['Sweets'][row]:
                    DFTransformed[Food][row] = 1
        DFTransformed
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-04-17
          • 2019-10-02
          • 2012-12-30
          • 2014-06-06
          • 2023-04-03
          • 2015-02-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多