【问题标题】:pandas dataframe: return column that is a compression of other columns熊猫数据框:返回列是其他列的压缩
【发布时间】:2014-05-18 17:23:15
【问题描述】:

我有一个包含很多列的数据框,其中列名符合特定字符串模式的任意数量。如果任何其他列中包含“r”,我想创建一个设置为“r”的新列。我可以这样做:

for col in df.columns:
    if 'abc' in col:
        for i in df.index:
            if df.ix[i, col] == 'r':
                df.ix[i, 'newcol'] = 'r'

但是这有点丑陋和缓慢。有没有更快的方法来做到这一点?

编辑:包括我的源数据的示例:

df = pd.DataFrame({'abc1':['r','r','n','n'], 'abc2':['r','n','n','r'], 'xyz1':['r','n','n','n'], 'xyz2':['n','n','r','n']})

我需要的输出(在'newcol'中)是:

  abc1 abc2 xyz1 xyz2 newcol
0    r    r    r    n      r
1    r    n    n    n      r
2    n    n    n    r    nan
3    n    r    n    n      r

(只要不是 'r',nan 几乎可以用任何东西代替)。 或者 newcol 可以包含 True, True, False, True 这对于我的目的也可以正常工作。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    好吧,我可能会这样做(一个示例数据框,希望能很好地捕捉您的情况):

    >>> df
    
       A  B abc1 abc2 abc3 abc4
    0  1  4    x    r    a    d
    1  1  3    y    d    b    e
    2  2  4    z    e    c    r
    3  3  5    r    g    d    f
    4  4  8    z    z    z    z
    

    获取感兴趣的列:

    >>> cols = [x for x in df.columns if 'abc' in x]
    >>> cols
    ['abc1', 'abc2', 'abc3', 'abc4']
    
    >>> df['newcol'] = (df[cols] == 'r').any(axis=1).map({True:'r',False:'np.nan'})
    >>> df
    
      A  B abc1 abc2 abc3 abc4  newcol
    0  1  4    x    r    a    d       r
    1  1  3    y    d    b    e  np.nan
    2  2  4    z    e    c    r       r
    3  3  5    r    g    d    f       r
    4  4  8    z    z    z    z  np.nan
    

    这应该很快;我认为即使在这里使用 map 也将是一个 Cythonized 调用。如果一个 boleen 向量对于 newcol 来说已经足够了,您可以将其简化为以下内容:

    >>> df['newcol'] = (df[cols] == 'r').any(axis=1)
    >>> df
    
       A  B abc1 abc2 abc3 abc4 newcol
    0  1  4    x    r    a    d   True
    1  1  3    y    d    b    e  False
    2  2  4    z    e    c    r   True
    3  3  5    r    g    d    f   True
    4  4  8    z    z    z    z  False
    

    现在,如果您需要检查字符串是否包含 'r' 而不是等于 'r',您可以执行以下操作:

    >>> df
    
      A  B abc1  abc2 abc3 abc4
    0  1  4    x  root    a    d
    1  1  3    y     d    b    e
    2  2  4    z     e    c  bar
    3  3  5    r     g    d    f
    4  4  8    z     z    z    z
    
    >>> cols = [x for x in df.columns if 'abc' in x]
    >>> df['newcol'] = df[cols].apply(lambda x: x.str.contains('r'),axis=0).any(axis=1)
    >>> df['newcol'] = df['newcol'].map({True:'r',False:'np.nan'}) 
    >>> df
    
       A  B abc1  abc2 abc3 abc4  newcol
    0  1  4    x  root    a    d       r
    1  1  3    y     d    b    e  np.nan
    2  2  4    z     e    c  bar       r
    3  3  5    r     g    d    f       r
    4  4  8    z     z    z    z  np.nan
    

    这仍然应该很快,因为它对每一列使用pandas'矢量化字符串方法(应用是跨列,而不是对行的迭代)。

    【讨论】:

    • 这太完美了——感​​谢您提供这么多选择。为了简单起见,我决定使用第二个(布尔向量)选项。我不知何故错过了 any(),这非常有用。
    【解决方案2】:

    尝试在 axis=1 上使用 apply 和自定义函数:

    get_val_for_row = lambda items: 'r' if (items == 'r').any() else None
    
    df['newcol'] = df.apply(get_val_for_row, axis=1)
    

    【讨论】:

    • 谢谢,我喜欢这个,但它不能直接使用所有列的子集。
    • @fantabolous 实际上,确实如此。只需在应用函数时指定列,如下所示:df[['col1', 'col2']].apply(...)
    猜你喜欢
    • 2021-12-16
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2021-03-22
    • 2017-01-14
    • 1970-01-01
    相关资源
    最近更新 更多