【问题标题】:Python Pandas conditional flaggingPython Pandas 条件标记
【发布时间】:2018-10-03 23:57:27
【问题描述】:

使用 python pandas 数据框 df:

product_id |transaction_id | category | color
234          54              A           black
349          54              B           silver
213          46              A           silver
490          46              A           black
245          87              A           black
249          87              B           black
294          87              A           silver

我想用相同颜色标记具有 A 和 B 类别的事务 ID。所以在上面的场景中,交易 87 有一个黑色的产品 A 和一个黑色的产品 B。

期望的输出:

product_id |transaction_id | category | color  | flag
234          54              A           black
349          54              B           silver
213          46              A           silver
490          46              A           black
245          87              A           black    X
249          87              B           black    X
294          87              A           silver   X

我试图在类别和颜色之间创建一个唯一键,然后是 groupby,但它变得混乱,我仍然必须手动完成它。必须有更简单的方法。

df['key']=df['category']&df['color']

df['transaction_analysis']= df.groupby('transaction_id').key.transform(lambda x : '&'.join(set(x)))

【问题讨论】:

    标签: python pandas if-statement conditional-statements


    【解决方案1】:

    不确定是否更简单,但肯定更干净。您可以在transaction_idcategorygroupby,使用unique 找到独特的颜色,然后取消堆叠。

    在此之后,生成标志值的映射并稍后分配给df

    v = (
        df.groupby(['transaction_id', 'category'])
          .color
          .unique()
          .unstack(fill_value=set())
    )
    m = {
      k : 'X' if set(x).intersection(y) else '' for k, x, y in zip(v.index, v.A, v.B)
    }    
    df['flag'] = df['transaction_id'].map(m)
    

    df
    
       product_id  transaction_id category   color flag
    0         234              54        A   black     
    1         349              54        B  silver     
    2         213              46        A  silver     
    3         490              46        A   black     
    4         245              87        A   black    X
    5         249              87        B   black    X
    6         294              87        A  silver    X
    

    【讨论】:

    • 呃!让我试试这个,这和我的逻辑相似,但我同意它到目前为止更干净
    • 你介意更详细地解释一下吗 k : 'X' if set(x).intersection(y) else '' for k, x, y in zip(v.index, vA, vB )?我希望将来能够单独执行类似的逻辑,而不会在 stackoverflow 上打扰用户
    • @jeangelj 从第一行你得到两列,每个类别一个,索引是 txn_id。现在我想通过使用 set.intersection 来查找哪些类别有共同的颜色。我用它来标记 txn_ids。之后,就像使用 pd.Series.map 将这些标志映射回原始标志一样简单。
    【解决方案2】:

    这是另一种方法:

    import pandas as pd
    
    df = pd.DataFrame({'category': ['A', 'B', 'A', 'A', 'A', 'B', 'A'],
                       'color': ['black', 'silver', 'silver', 'black', 
                                 'black', 'black', 'silver'],
                       'product_id': [234, 349, 213, 490, 245, 249, 294],
                       'transaction_id': [54, 54, 46, 46, 87, 87, 87]})
    
    pivoted = df.pivot_table(index=['transaction_id','color'], columns=['category'], 
                             values='product_id')
    transaction_color_mask = pd.notnull(pivoted).all(axis=1)
    transaction_map = transaction_color_mask.groupby(level=0).any().map({True:'X',False:''})
    df['flag'] = df['transaction_id'].map(transaction_map)
    print(df)
    

    产量

      category   color  product_id  transaction_id flag
    0        A   black         234              54     
    1        B  silver         349              54     
    2        A  silver         213              46     
    3        A   black         490              46     
    4        A   black         245              87    X
    5        B   black         249              87    X
    6        A  silver         294              87    X
    

    主要思想是使用pivot_table 将要比较的值按行公开:

    In [182]: pivoted
    Out[182]: 
    category                   A      B
    transaction_id color               
    46             black   490.0    NaN
                   silver  213.0    NaN
    54             black   234.0    NaN
                   silver    NaN  349.0
    87             black   245.0  249.0
                   silver  294.0    NaN
    

    现在我们可以找到类别AB 具有相同颜色的行:

    In [183]: transaction_color_mask = pd.notnull(pivoted).all(axis=1); transaction_color_mask
    Out[183]: 
    transaction_id  color 
    46              black     False
                    silver    False
    54              black     False
                    silver    False
    87              black      True
                    silver    False
    dtype: bool
    

    transaction_id 分组以查找与真行关联的transaction_ids:

    In [184]: transaction_color_mask.groupby(level=0).any()
    Out[184]: 
    transaction_id
    46    False
    54    False
    87     True
    dtype: bool
    

    然后将True 映射到'X'False 到空字符串:

    In [185]: transaction_color_mask.groupby(level=0).any().map({True:'X',False:''})
    Out[185]: 
    transaction_id
    46     
    54     
    87    X
    dtype: object
    

    最后,将结果与df 重新组合:df['flag'] = df['transaction_id'].map(transaction_map) 产生所需的结果。

    【讨论】:

    • 哇!非常感谢,我可以看到这个答案所付出的努力,让我试试
    猜你喜欢
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多