【问题标题】:Combine Pandas columns containing list objects合并包含列表对象的 Pandas 列
【发布时间】:2019-02-20 19:13:44
【问题描述】:

我的问题类似于“Combine pandas string columns with missing values ”和“How to merge/combine columns in pandas?”,但由于我要组合的单元格包含列表,所有给定的答案都不起作用。

简化,我的 df 看起来像这样:

        players    players1    players2    players3
1       ['1','2']  
2       ['2','4']
3                  ['1','4']
4                              ['1','5']
5                                          ['3','5']
6
7                  ['3','4']

(所以我知道两列中永远不会有值。)

现在我想添加一个组合列表的新列:

        players    players1    players2    players3     players_combine
1       ['1','2']                                       ['1','2']
2       ['2','4']                                       ['2','4']
3                  ['1','4']                            ['1','4']
4                              ['1','5']                ['1','5']
5                                          ['3','5']    ['3','5']
6
7                  ['3','4']                            ['3','4']

我尝试了很多东西 - 主要是链接答案的变体,我的最后一个想法是级联 np.where。但它没有用。只有 'players' 的值会显示在组合列中。

df['players_combine'] = np.where(df.players.notnull(),df.players.values,np.where(df.players1.notnull(),df.players1.values,np.where(df.players2.notnull(),df.players2.values,np.where(df.players3.notnull(),df.players3.values,np.nan))))

编辑: 如 cmets 中所问:df.head(5).to_dict()

{'players': {'5b41800eaffb061b88c4beac': ['57005', '124021', '132037', '78523', '111742', '133892', '76431', '78066', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '108106', '127464', '296770'], '5b41800eaffb061b88c4bead': ['18929', '110183', '28401', '302853', '296768', '94912', '93671', '52060', '43282', '132364', '140646', '77861', '19787', '133790', '312666', '76336', '317219', '137849'], '5b41800daffb061b88c4bc7f': 'nan', '5b41800eaffb061b88c4bd62': 'nan', '5b41800eaffb061b88c4bd65': 'nan'}, 'players1': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '78066', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '108106', '127464', '76431'], '5b41800eaffb061b88c4bd62': '', '5b41800eaffb061b88c4bd65': ''}, 'players2': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': nan, '5b41800eaffb061b88c4bd62': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '108106', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '78066', '127464', '76431'], '5b41800eaffb061b88c4bd65': ''}, 'players3': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': nan, '5b41800eaffb061b88c4bd62': nan, '5b41800eaffb061b88c4bd65': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '108106', '138749', '132358', '247798', '69756', '133745', '278877', '77857', '78066', '127464', '76431']}}

【问题讨论】:

  • 你能发帖df.to_dict()吗?
  • 熊猫单元格中不能有“无值”。你到底有什么?空字符串、空列表、nans?
  • 其他列中的空值是什么?是空字符串,还是 NaN,还是空列表?
  • 如果您发布d = df.to_dict(),我们可以简单地执行pd.DataFrame(d) 并完全按原样复制数据框:)
  • @J_Scholz 然后就做df.head(5).to_dict() ;)

标签: python pandas numpy


【解决方案1】:

由于您知道每行最多只有一个列中的值,因此您可以将您不关心的值替换为NaN,然后使用.stack。

在这种情况下,您似乎同时拥有 'nan' 和 '' 字符串,应首先将其替换为 np.NaN。

import numpy as np

df['players_combine'] = df.replace({'': np.NaN, 'nan': np.NaN}, regex=True).stack().reset_index(level=1, drop=True)

样本数据

import pandas as pd
df = pd.DataFrame({'players': [['1','2'], '', '', np.NaN, ''],
                   'players1': ['', ['2','4'], '', np.NaN, ''],
                   'players2': ['', '', ['1','5'], np.NaN, ''],
                   'players3': ['', '', np.NaN, ['3', '5'], '']})

输出:

  players players1 players2 players3 players_combine
0  [1, 2]                                     [1, 2]
1           [2, 4]                            [2, 4]
2                    [1, 5]      NaN          [1, 5]
3     NaN      NaN      NaN   [3, 5]          [3, 5]
4                                                NaN

【讨论】:

    【解决方案2】:

    如果任何空单元格是空字符串 (''),首先将其设为 NaN:

    df[df==''] = np.nan
    

    然后,选择每一行中所有非NaN的最大值:

    df.apply(lambda x: x[x.notnull()].max(), axis=1)
    #1    [1, 2]
    #2    [2, 4]
    #3    [1, 4]
    #4    [1, 5]
    #5    [3, 5]
    #6       NaN
    #7    [3, 4]
    

    另一个有趣(更快)的解决方案是消除所有 NaN 行,然后在每行中找到第一个有效值:

    df.loc[df.notnull().any(axis=1)]\
      .apply(lambda x: x[x.first_valid_index()], axis=1)
    #1    [1, 2]
    #2    [2, 4]
    #3    [1, 4]
    #4    [1, 5]
    #5    [3, 5]
    #7    [3, 4]
    

    【讨论】:

    • 谢谢,np.where 解决方案比这更快。看我的回答。
    【解决方案3】:

    分析您的df.to_dict() 似乎,对于某些单元格,您有字符串 nan,对于其他单元格,您有实际的np.nan,对于其他一些单元格,您甚至有空字符串''。

    所以首先通过使空值统一来清理您的数据集:

    df = df.replace({'nan':np.nan, '':np.nan})
    

    然后你可以通过axis=1aggregate

    df['players_combine'] = df.agg(lambda s: s[~s.isnull()][0], axis=1)
    

    【讨论】:

    • 所以看起来'nan'一直是我的问题。我把它们当作真正的 np.nan。现在我的 np.where 线可以工作了。
    【解决方案4】:

    由于一些格式错误的数据是我的代码中的问题,而不是所提出的问题,我想添加一些有关所有不同选项的性能的信息。我使用 np.where 是因为它使用矢量化,而 np.apply 遍历行,因此存在巨大的性能差异。


    设置 4*2000=8000 行的 test-df:

    import pandas as pd
    import numpy as np
    
    l = [[['1','2'],np.NaN,np.NaN,np.NaN],
         [np.NaN,['2','3'],np.NaN,np.NaN],
        [np.NaN,np.NaN,['3','4'],np.NaN],
        [np.NaN,np.NaN,np.NaN,['4','5']]]
    
    l=l*2000
    
    df = pd.DataFrame(l)
    
    df.columns = ['players','players1','players2','players3']
    

    最佳选择:

    %timeit df['players_combine'] = np.where(df.players.notnull(),df.players.values,np.where(df.players1.notnull(),df.players1.values,np.where(df.players2.notnull(),df.players2.values,np.where(df.players3.notnull(),df.players3.values,np.nan))))
    
    100 loops, best of 3: 2.18 ms per loop
    

    非常好的选择:

    %timeit df.loc[df.notnull().any(axis=1)]\
      .apply(lambda x: x[x.first_valid_index()], axis=1)
    
    100 loops, best of 3: 413 ms per loop
    

    其他选项1:

    %timeit df['players_combine'] = df.agg(lambda s: s[~s.isnull()][0], axis=1)
    
    1 loop, best of 3: 4.71 s per loop
    

    还有 2:

    %timeit df['players_combine'] = df.apply(lambda x: x[x.notnull()].max(), axis=1)
    
    1 loop, best of 3: 4.86 s per loop
    

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2019-07-04
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 2018-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多