【问题标题】:Creating a column based on the presence of part of a string in multiple other columns根据多个其他列中存在的部分字符串创建列
【发布时间】:2019-01-08 05:35:25
【问题描述】:

我有一个名为 df 的数据框,看起来与此类似(除了“mat_deliv”列的数量上升到 mat_deliv_8 并且有数百个客户端 - 我在这里对其进行了简化)。

Client_ID  mat_deliv_1  mat_deliv_2  mat_deliv_3  mat_deliv_4
C1019876   xxx,yyy,zzz  aaa,bbb,xxx  ccc          ddd
C1018765   yyy,zzz      xxx          bbb          None
C1017654   yyy,xxx      aaa,bbb      ccc          ddd
C1016543   aaa,bbb      ccc          None         None
C1019876   yyy          None         None         None

我想创建一个名为xxx_deliv 的新列,其中包含两个值01。如果mat_deliv_1mat_deliv_2mat_deliv_3mat_deliv_4 中的任何一个包含xxx,我想将xxx_deliv 设置为等于1,如果它们不包含0

所以,我想添加一个列,以 df 为例,如下所示:

Client_ID  mat_deliv_1  mat_deliv_2  mat_deliv_3  mat_deliv_4  xxx_deliv
C1019876   xxx,yyy,zzz  aaa,bbb,xxx  ccc          ddd          1
C1018765   yyy,zzz      xxx          bbb          None         1
C1017654   yyy,xxx      aaa,bbb      ccc          ddd          1
C1016543   aaa,bbb      ccc          None         None         0
C1019876   yyy          None         None         None         0

我知道以下代码执行所需的任务:

df['xxx_deliv'] = 0
df.loc[(df.Mat_deliv_1.str.contains("xxx", na=False)) |
       (df.Mat_deliv_2.str.contains("xxx", na=False)) |
       (df.Mat_deliv_3.str.contains("xxx", na=False)) |
       (df.Mat_deliv_4.str.contains("xxx", na=False)),
       'xxx_deliv'] = 1

但我希望能够做到这一点,而无需遍历每一列 - 我需要能够一次搜索多个列。

【问题讨论】:

    标签: python string pandas


    【解决方案1】:

    您需要单独检查每一列。您可以通过apply 执行此操作,检查字符串是否包含目标文本。然后将any 应用于该行(通过指定axis=1)。通过.astype(int) 将布尔结果转换为整数,然后使用assign 将其作为新列添加到数据帧中。

    我使用loc[:, target_cols] 将我的搜索范围指定为数据框中的所有行以及所有选择的target_cols

    target_cols = ['mat_deliv_1', 'mat_deliv_2', 'mat_deliv_3', 'mat_deliv_4']
    df = (df
          .assign(xxx_deliv=df.loc[:, target_cols].apply(lambda col: col.str.contains('xxx'))
          .any(axis=1)
          .astype(int))
    >>> df
      Client_ID  mat_deliv_1  mat_deliv_2 mat_deliv_3 mat_deliv_4  xxx_deliv
    0  C1019876  xxx,yyy,zzz  aaa,bbb,xxx         ccc         ddd          1
    1  C1018765      yyy,zzz          xxx         bbb        None          1
    2  C1017654      yyy,xxx      aaa,bbb         ccc         ddd          1
    3  C1016543      aaa,bbb          ccc        None        None          0
    4  C1019876          yyy         None        None        None          0
    

    【讨论】:

    • 效果很好,谢谢亚历山大。我进行了一次编辑,将 iloc 替换为 loc,因为我在 Client_IDmat_deliv_1 之间有许多列,而且这个数字可能会改变;通过标签而不是位置进行修复意味着我将来不必更改脚本:df = df.assign(xxx_deliv=df.loc[:, "mat_deliv_1":"mat_deliv_4"].apply(lambda col: col.str.contains('xxx')).any(axis=1).astype(int)) 我将不得不了解更多关于lambda 的信息,我到处都看到了!
    • @FGreen 请参阅上面的编辑答案。我添加了一个列表容器来保存您要检查内容的目标列。
    • 谢谢@Alexander - 快速跟进问题:如果我希望xxx_deliv 列计算xxx 在四个mat_deliv 列中出现的次数(例如2 在第 0 行,1 在第 1 行),而不仅仅是缺席/在场的二进制 0/1 值?
    • @FGreen 您应该将后续问题作为新问题提出(提供原始问题的链接以提供上下文)。这种情况可以试试..apply(lambda col: col.str.count('xxx')).sum(axis=1)
    • 这里提出的新问题:[stackoverflow.com/questions/54098875/…Thanks Alexander.
    【解决方案2】:

    你可以使用apply:

    def contains(xs, pat='xxx'):
        return int(any(pat in x for x in xs.values))
    
    
    df['xxx_deliv'] = df[['mat_deliv_1', 'mat_deliv_2', 'mat_deliv_3', 'mat_deliv_4']].apply(contains, axis=1)
    print(df)
    

    输出

      Client_ID  mat_deliv_1    ...    mat_deliv_4 xxx_deliv
    0  C1019876  xxx,yyy,zzz    ...            ddd         1
    1  C1018765      yyy,zzz    ...           None         1
    2  C1017654      yyy,xxx    ...            ddd         1
    3  C1016543      aaa,bbb    ...           None         0
    4  C1019876          yyy    ...           None         0
    
    [5 rows x 6 columns]
    

    【讨论】:

      猜你喜欢
      • 2013-11-13
      • 2019-06-13
      • 2022-09-23
      • 2019-03-08
      • 1970-01-01
      • 2021-04-19
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多