【问题标题】:How to combine different columns in a dataframe using comprehension-python如何使用 comprehension-python 组合数据框中的不同列
【发布时间】:2017-05-18 07:01:40
【问题描述】:

假设一个数据框包含

攻击者_1 攻击者_2 攻击者_3 攻击者_4
兰尼斯特楠楠楠
南史塔克葛雷乔伊南

我想创建另一个名为 AttackerCombo 的列,它将 4 列聚合为 1 列。 我将如何在 python 中定义这样的代码? 我一直在练习 python,我认为这种列表理解是有道理的,但是 [list(x) for x in attacks] 其中攻击者是 4 列的 numpy 数组,显示所有 4 列聚合为 1 列,但是我也想删除所有 nans。 所以每一行的结果而不是看起来像

starknannanlannister
看起来像
stark/lannister

【问题讨论】:

    标签: python-3.x pandas numpy nan string-concatenation


    【解决方案1】:

    我认为您需要 applyjoin 并通过 dropna 删除 NaN

    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']] \
                        .apply(lambda x: '/'.join(x.dropna()), axis=1)
    print (df)
      attacker_1 attacker_2 attacker_3  attacker_4      attackers
    0  Lannister        NaN        NaN         NaN      Lannister
    1        NaN      Stark    greyjoy         NaN  Stark/greyjoy
    

    如果需要separator空字符串使用DataFrame.fillna:

    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']].fillna('') \
                        .apply(''.join, axis=1)
    print (df)
      attacker_1 attacker_2 attacker_3  attacker_4     attackers
    0  Lannister        NaN        NaN         NaN     Lannister
    1        NaN      Stark    greyjoy         NaN  Starkgreyjoy
    

    list comprehension 的另外 2 个解决方案 - 首先通过 notnull 进行比较,然后检查是否为 string

    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']] \
                        .apply(lambda x: '/'.join([e for e in x if pd.notnull(e)]), axis=1)
    print (df)
      attacker_1 attacker_2 attacker_3  attacker_4      attackers
    0  Lannister        NaN        NaN         NaN      Lannister
    1        NaN      Stark    greyjoy         NaN  Stark/greyjoy
    
    
    #python 3 - isinstance(e, str), python 2 - isinstance(e, basestring)
    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']] \
                        .apply(lambda x: '/'.join([e for e in x if isinstance(e, str)]), axis=1)
    print (df)
      attacker_1 attacker_2 attacker_3  attacker_4      attackers
    0  Lannister        NaN        NaN         NaN      Lannister
    1        NaN      Stark    greyjoy         NaN  Stark/greyjoy
    

    【讨论】:

    • 完美解决方案!谢谢。您能否根据文档扩展“轴”的行,如果轴 = 0,则函数应用于列,如果轴 = 1,则函数应用于行,您能解释一下它是如何工作的吗?
    • 正如您在评论中所说的那样。你可以通过df[['attacker_1','attacker_2','attacker_3','attacker_4']].apply(print)df[['attacker_1','attacker_2','attacker_3','attacker_4']].apply(print, axis=1)进行测试
    • 让我试着解释一下我到目前为止所知道的,当我取 4 列的一个子集并使用 apply 应用一个函数时,'lambda x' 是一个可迭代的所有行子集,这里应用的函数是'a string "/" 与 dropna 连接在一起,应用于每一行,这是使用axis = 1'指定的。这是正确的还是我错过了什么
    • 你能提出更多相同操作的细微差别吗?例如,在列表理解中,我的想法是查看一行中的每个元素并检查其是否为 NaN,然后​​将非 NaN 添加到列表中。这可能会解决一些性能障碍的问题。
    • 我添加了另外 2 个解决方案,希望它们更快。
    【解决方案2】:

    您可以在数据框中设置一个新列,这要归功于 lambda 函数:

    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']].apply(lambda x : '{}{}{}{}'.format(x[0],x[1],x[2],x[3]), axis=1)
    

    你没有指定如何你想聚合它们,例如,如果你想用破折号分隔:

    df['attackers'] = df[['attacker_1','attacker_2','attacker_3','attacker_4']].apply(lambda x : '{}-{}-{}-{}'.format(x[0],x[1],x[2],x[3]), axis=1)
    

    【讨论】:

    • 有没有办法使用 numpy 计算类似的操作,假设数据帧被转换为 numpy。以及可以使用的其他可能的理解功能是什么。谢谢
    • 我尝试修改@nlassaux提供的命令,battledf[['attacker_1','attacker_2','attacker_3','attacker_4']].fillna('').apply(lambda x :'{}{}{}{}'.format(x[0],x[1],x[2],x[3]),axis=1).unique()。这确实产生了相关的解决方案。但我不确定这是否是最佳选择
    • 格式被认为是最优的,因为它直接调用 C 代码。此外,.apply() 速度很快,但不如 pandas 内置的并行方法快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多