【问题标题】:One to one mapping between two lists of strings in a pandas dataframe熊猫数据框中两个字符串列表之间的一对一映射
【发布时间】:2017-10-21 18:14:33
【问题描述】:

假设我有一个 pandas 数据框,其中 2 列由字符串列表组成,如下所示

df=pd.DataFrame( {'A' : [ ['a','b','c'], ['d','e','f'] ], 'B':[ ['g','h','i'], ['j','k','l'] ] })

我想用连字符将 A 中第一个列表中的第一个字符串元素与 B 中第一个列表中的第一个字符串元素连接起来,依此类推。最终产品将是另一列 C,因此

df['C'] = [ ['a-g','b-h','c-i'], ['d-j','e-k','f-l' ] ]

我尝试了 apply() 和 map() 的不同功能,但没有产生预期的结果,感谢任何帮助。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    你可以使用str.cat:

    df['C'] = df.A.str.cat(df.B, sep='-')
    
    df
    #   A   B   C
    #0  a   e   a-e
    #1  b   f   b-f
    #2  c   g   c-g
    #3  d   h   d-h
    

    或者直接添加两列:

    df.A + '-' + df.B
    
    #0    a-e
    #1    b-f
    #2    c-g
    #3    d-h
    #dtype: object
    

    更新已编辑的数据:

    df=pd.DataFrame({'A':[['a','b','c'], ['d','e','f']], 'B':[['g','h','i'], ['j','k','l']]})
    
    df['C'] = df.apply(lambda r: [a+'-'+b for a,b in zip(r.A, r.B)], axis=1)
    
    df
    #           A           B                 C
    #0  [a, b, c]   [g, h, i]   [a-g, b-h, c-i]
    #1  [d, e, f]   [j, k, l]   [d-j, e-k, f-l]
    

    【讨论】:

    • @MartinHeusen 您可以编辑您的问题以详细说明吗?
    • 感谢您的回答。实际上,我在问我的问题时犯了一个错误。我要连接的两列都是由列表组成的,所以数据框如下 df=pd.DataFrame( {'A' : [ ['a','b','c'], ['d', 'e','f'] ], 'B':[ ['g','h','i'], ['j','k','l'] ] }) 等等我想要的结果是 df['C'] = [ ['a-g','b-h','c-i'], ['d-j','e-k','f-l' ] ],你能请帮忙?
    • 试试df['C'] = df.apply(lambda r: [a+'-'+b for a,b in zip(r.A, r.B)], axis=1)
    • 尝试了你的建议,它给出了以下错误“传递值的形状是 (17,2),索引暗示 (17,32)”数据框的形状是 (17,32)跨度>
    • 任何帮助@Psidom ?
    【解决方案2】:

    我会用apply + np.core.defchararray.add 来做这个:

    from numpy.core.defchararray import add
    
    df['C'] = df[['A', 'B']].apply(lambda x: add(add(x.A, '-'), x.B).tolist(), 1)
    df
    
               A          B                C
    0  [a, b, c]  [g, h, i]  [a-g, b-h, c-i]
    1  [d, e, f]  [j, k, l]  [d-j, e-k, f-l]
    

    请记住我所说的将数据存储在列表中。


    如果您的列大小可能不相等,您可以进行if 检查:

    def foo(x):
        if len(x.A) == len(x.B):
            return add(add(x.A, '-'), x.B).tolist()
        return []
    
    df['C'] = df[['A', 'B']].apply(foo, 1)
    

    【讨论】:

    • 它不工作!实际上,它给出的错误与之前建议的答案“传递值的形状为 (17, 2),索引暗示 (17, 34)”相同,因为知道数据框的形状为 17 行和 34 列。我按原样尝试了您的答案,当数据框仅包含这两列时,它可以工作,当您添加其他类型的额外列时,它就不再起作用了。我尝试将 df.apply 替换为 df[['A', 'B']].apply 现在给我以下错误“无法将输入数组从形状 (15) 广播到形状 (2)”
    • @MartinHeusen 如果您尝试连接所有 34 列,最好确保每个单元格具有完全相同数量的元素。
    • 不,我不是要连接 34 列,只有 2 列我知道每行中列表的长度是相同的。长度可能因行而异,但每一行都是相同的!
    • @MartinHeusen df[['A', 'B']].apply 应该可以工作,前提是您确保最后传递了 axis=1 参数。是你做的吗?这很重要。
    • 我做到了,这是我正在使用的代码的 sn-p 并给出错误 df_prim['Cur_pair'] = df_prim[['From', 'To']].apply(lambda x: pd.Series(x.From).str.cat(pd.Series(x.To), sep='-').tolist(), 1) 我有一个货币兑换的数据框,其中'From'和 'T​​o' 列代表客户使用的货币对
    【解决方案3】:

    选项 1
    使用numpy.core.defchararray.add

    from numpy.core.defchararray import add
    
    a = np.array(df.values.tolist())
    
    df.assign(C=add(add(a[:, 0], '-'), a[:, 1]).tolist())
    
               A          B                C
    0  [a, b, c]  [g, h, i]  [a-g, b-h, c-i]
    1  [d, e, f]  [j, k, l]  [d-j, e-k, f-l]
    

    选项 2
    list 的自定义子类和重新定义 + 的有趣方式

    class list_(list):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
        def __add__(self, other):
            return list_(map('-'.join, (map(str, t) for t in zip(self, other))))
    
    df.assign(C=df.applymap(list_).sum(1).apply(list))
    
               A          B                C
    0  [a, b, c]  [g, h, i]  [a-g, b-h, c-i]
    1  [d, e, f]  [j, k, l]  [d-j, e-k, f-l]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2018-10-23
      • 2018-12-18
      • 2022-11-18
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      相关资源
      最近更新 更多