代码之家  ›  专栏  ›  技术社区  ›  Andrew

在pandas中传播条件列值

  •  6
  • Andrew  · 技术社区  · 7 年前

    我想创建一个指示符变量,它将传播到与指示符具有相同客户周期值对的所有行。具体来说,如果 baz yes ,我希望同一客户和时段电子邮件的所有行都显示我的指标。

    df
      Customer  Period Question Score
            A       1      foo     2
            A       1      bar     3
            A       1      baz   yes
            A       1      biz     1
            B       1      bar     2
            B       1      baz    no
            B       1      qux     3
            A       2      foo     5
            A       2      baz   yes
            B       2      baz   yes          
            B       2      biz     2          
    

    我试过了

    df['Indicator'] = np.where(
                     (df.Question.str.contains('baz') & (df.Score == 'yes')),            
                     1, 0)
    

       Customer  Period Question Score  Indicator
             A       1      foo     2          0
             A       1      bar     3          0
             A       1      baz   yes          1
             A       1      biz     1          0
             B       1      bar     2          0
             B       1      baz    no          0
             B       1      qux     3          0
             A       2      foo     5          0
             A       2      baz   yes          1
             B       2      baz   yes          1
             B       2      biz     2          0
    

    但这是期望的输出:

       Customer  Period Question Score  Indicator
             A       1      foo     2          1
             A       1      bar     3          1
             A       1      baz   yes          1
             A       1      biz     1          1
             B       1      bar     2          0
             B       1      baz    no          0
             B       1      qux     3          0
             A       2      foo     5          1
             A       2      baz   yes          1
             B       2      baz   yes          1
             B       2      biz     2          1
    

    我不知道怎样才能得到我想要的。也许是和菲尔的groupby和另一个和贝菲尔的groupby?

    3 回复  |  直到 7 年前
        1
  •  5
  •   Zero    7 年前

    你可以用

    In [954]: df['Indicator'] = (df.assign(eq=df.Question.eq('baz') & df.Score.eq('yes'))
                                   .groupby(['Customer', 'Period'])['eq']
                                   .transform('any').astype(int))
    
    In [955]: df
    Out[955]:
       Customer  Period Question Score  Indicator
    0         A       1      foo     2          1
    1         A       1      bar     3          1
    2         A       1      baz   yes          1
    3         A       1      biz     1          1
    4         B       1      bar     2          0
    5         B       1      baz    no          0
    6         B       1      qux     3          0
    7         A       2      foo     5          1
    8         A       2      baz   yes          1
    9         B       2      baz   yes          1
    10        B       2      biz     2          1
    

    细节

    In [956]: df.Question.eq('baz') & df.Score.eq('yes')
    Out[956]:
    0     False
    1     False
    2      True
    3     False
    4     False
    5     False
    6     False
    7     False
    8      True
    9      True
    10    False
    dtype: bool
    
    In [957]: df.assign(eq=df.Question.eq('baz') & df.Score.eq('yes'))
    Out[957]:
       Customer  Period Question Score  Indicator     eq
    0         A       1      foo     2          1  False
    1         A       1      bar     3          1  False
    2         A       1      baz   yes          1   True
    3         A       1      biz     1          1  False
    4         B       1      bar     2          0  False
    5         B       1      baz    no          0  False
    6         B       1      qux     3          0  False
    7         A       2      foo     5          1  False
    8         A       2      baz   yes          1   True
    9         B       2      baz   yes          1   True
    10        B       2      biz     2          1  False
    
        2
  •  4
  •   jpp    7 年前

    MultiIndex . 然后使用 pd.Series.isin

    mask = (df['Question'] == 'baz') & (df['Score'] == 'yes')
    idx_cols = ['Customer', 'Period']
    idx = df.set_index(idx_cols).loc[mask.values].index
    
    df['Indicator'] = pd.Series(df.set_index(idx_cols).index.values).isin(idx).astype(int)
    
    print(df)
    
       Customer  Period Question Score  Indicator
    0         A       1      foo     2          1
    1         A       1      bar     3          1
    2         A       1      baz   yes          1
    3         A       1      biz     1          1
    4         B       1      bar     2          0
    5         B       1      baz    no          0
    6         B       1      qux     3          0
    7         A       2      foo     5          1
    8         A       2      baz   yes          1
    9         B       2      baz   yes          1
    10        B       2      biz     2          1
    
        3
  •  4
  •   piRSquared    7 年前

    你可以把 Customer Period . 然后使用 np.logical_or.at 让大家都知道 any

    i, r = pd.factorize([*zip(df.Customer, df.Period)])
    a = np.zeros(len(r), dtype=np.bool8)
    np.logical_or.at(a, i, df.eval('Question == "baz" and Score == "yes"'))
    df.assign(Indicator=a[i].astype(np.int64))
    
       Customer  Period Question Score  Indicator
    0         A       1      foo     2          1
    1         A       1      bar     3          1
    2         A       1      baz   yes          1
    3         A       1      biz     1          1
    4         B       1      bar     2          0
    5         B       1      baz    no          0
    6         B       1      qux     3          0
    7         A       2      foo     5          1
    8         A       2      baz   yes          1
    9         B       2      baz   yes          1
    10        B       2      biz     2          1
    

    解释

    i, r = pd.factorize([*zip(df.Customer, df.Period)])
    

    产生独特的 (Customer, Period) 成对 r i 是一个数组,用于跟踪 去哪里以产生元组的原始列表

    1. [*zip(df.Customer, df.Period)]
      
      [('A', 1),
       ('A', 1),
       ('A', 1),
       ('A', 1),
       ('B', 1),
       ('B', 1),
       ('B', 1),
       ('A', 2),
       ('A', 2),
       ('B', 2),
       ('B', 2)]
      
    2. 分解后,唯一元组

      r
      
      array([('A', 1), ('B', 1), ('A', 2), ('B', 2)], dtype=object)
      
    3. 以及位置

      i
      
      array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3])
      

    作为评价分组的指标 任何 at 方法打开 ufuncs . 基本上,这允许我创建一个数组,其值可以根据 操作。然后指定一个索引数组(这就是 将是)和一个与

    我最终用做我的匹配数组

    df.eval('Question == "baz" and Score == "yes"')
    
    0     False
    1     False
    2      True
    3     False
    4     False
    5     False
    6     False
    7     False
    8      True
    9      True
    10    False
    dtype: bool
    

    让我详细地介绍一下

         Flag  GroupIndex   Group    State of a
    0   False           0  (A, 1)  [0, 0, 0, 0]  # Flag is False, So do Nothing
    1   False           0  (A, 1)  [0, 0, 0, 0]  # Flag is False, So do Nothing
    2    True           0  (A, 1)  [1, 0, 0, 0]  # Flag is True, or_eq for Index 0
    3   False           0  (A, 1)  [1, 0, 0, 0]  # Flag is False, So do Nothing
    4   False           1  (B, 1)  [1, 0, 0, 0]  # Flag is False, So do Nothing
    5   False           1  (B, 1)  [1, 0, 0, 0]  # Flag is False, So do Nothing
    6   False           1  (B, 1)  [1, 0, 0, 0]  # Flag is False, So do Nothing
    7   False           2  (A, 2)  [1, 0, 0, 0]  # Flag is False, So do Nothing
    8    True           2  (A, 2)  [1, 0, 1, 0]  # Flag is True, or_eq for Index 2
    9    True           3  (B, 2)  [1, 0, 1, 1]  # Flag is True, or_eq for Index 3
    10  False           3  (B, 2)  [1, 0, 1, 1]  # Flag is False, So do Nothing
    

    决赛 State [1, 0, 1, 1] [True, False, True, True] . 这代表着 or a

    a
    
    array([ True, False,  True,  True])
    

    如果我把它和 作为整数,我得到

    a[i].astype(np.int64)
    
    array([1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1])
    

    最后,我用 assign 生成数据帧及其新列的副本。

    df.assign(Indicator=a[i].astype(np.int64))
    
       Customer  Period Question Score  Indicator
    0         A       1      foo     2          1
    1         A       1      bar     3          1
    2         A       1      baz   yes          1
    3         A       1      biz     1          1
    4         B       1      bar     2          0
    5         B       1      baz    no          0
    6         B       1      qux     3          0
    7         A       2      foo     5          1
    8         A       2      baz   yes          1
    9         B       2      baz   yes          1
    10        B       2      biz     2          1
    

    为什么这么做?!

    Numpy通常更快。

    i, r = pd.factorize([*zip(df.Customer, df.Period)])
    a = np.zeros(len(r), dtype=np.bool8)
    q = df.Question.values == 'baz'
    s = df.Score.values == 'yes'
    m = q & s
    np.logical_or.at(a, i, m)
    df.assign(Indicator=a[i].astype(np.int64))