【问题标题】:Correct way to iterate over a dataframe using multiple conditionals使用多个条件迭代数据帧的正确方法
【发布时间】:2020-01-24 09:20:32
【问题描述】:

我有一个足球比赛数据集作为 Pandas 数据框,格式如下:

    Home            Away             Result     HG  AG
0   Liverpool       Norwich City     Liverpool  4   1
1   West Ham        Man City         Man City   0   5
2   AFC Bournemouth Sheffield United Draw       1   1
3   Burnley         Southampton      Burnley    3   0
4   Crystal Palace  Everton          Draw       0   0

我想在列表字典中按团队跟踪结果:
{'Liverpool': [W,W, ... ,W], 'West Ham': [W, D, L, ... ], ... } 等。

我的方法自然是用条件遍历所有行(下面是伪代码)

if df.Result == 'Draw':
    dict[df[Home]].append('D')
    dict[df[Away]].append('D')
elif df.Home == df.Result:
    dict[df[Home]].append('W')
    dict[df[Away]].append('L')
else:
    dict[df[Home]].append('L')
    dict[df[Away]].append('W')

我相信我可以使用df.iterrows() 做到这一点,但我知道这不是 Pandas 所希望的一般方法。有没有办法在利用 Pandas DataFrames 的强大功能的同时进行这种操作?我已经看到 df.Home == df.Result 返回一系列 True/False 值,但我不知道如何利用它或将其扩展到上述多个条件。

我还看到了 this answer 中的 np.wherenp.select,但我不认为它适用于我想根据每行条件的结果做某事的情况,使用行中的条目作为键。

感觉好像迭代是这里唯一的解决方案,我确信 Pandas 会支持这样的东西,但我不知道如何搜索它。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    这是一种使用DataFrame.meltnumpy.selectDataFrame.groupbylist 聚合的方法。

    注意我在您的示例数据中添加了“利物浦”和“诺维奇城”之间的重新匹配,以显示输出应该如何看待一个团队多次出现的位置:

    #Setup
    df = pd.DataFrame({'Home': ['Liverpool', 'West Ham', 'AFC Bournemouth', 'Burnley', 'Crystal Palace', 'Norwich City'], 'Away': ['Norwich City', 'Man City', 'Sheffield United', 'Southampton', 'Everton', 'Liverpool'], 'Result': ['Liverpool', 'Man City', 'Draw', 'Burnley', 'Draw', 'Norwich City'], 'HG': [4, 0, 1, 3, 0, 4], 'AG': [1, 5, 1, 0, 0, 1]})
    
    # Restructure the DataFrame into a long-form with "Melt"
    df_melted = (df.reset_index()
                 .melt(id_vars=['Result', 'index'],
                       value_vars=['Home', 'Away'])
                 .sort_values('index')) # This maintains the match order of original df
    
    # Use numpy.select to create your conditions and choices ('W', 'L' or 'D')
    df_melted['outcome'] = np.select(
        condlist=[df_melted['Result'] == 'Draw',
                  df_melted['Result'] == df_melted['value'],
                  df_melted['Result'] != df_melted['value']],
        choicelist=['D', 'W', 'L'])
    
    
    # Groupby team agg with list and return output as dict
    df_melted.groupby('value', sort=False)['outcome'].apply(list).to_dict()
    

    [出]

    {'Liverpool': ['W', 'L'],
     'Norwich City': ['L', 'W'],
     'West Ham': ['L'],
     'Man City': ['W'],
     'AFC Bournemouth': ['D'],
     'Sheffield United': ['D'],
     'Burnley': ['W'],
     'Southampton': ['L'],
     'Crystal Palace': ['D'],
     'Everton': ['D']}
    

    【讨论】:

    • 已接受答案,因为方法更详细,我将研究melt、apply 和groupby 以供将来的应用程序使用。这种方法实际上在我的(完整)数据中找到了一个不应该存在的键,而 Jim 没有,我觉得这很有趣
    【解决方案2】:

    您自然可以得到每个团队的公式,如下所示:

    team_list = list(set(list(df.Home)+list(df.Away)))
    
    d = {i:list(df.loc[(df.Home==i)|(df.Away==i),'Result'].map({i:'W','Draw':'D'}).fillna('L')) 
         for i in team_list}
    

    基本上,对于每个唯一的团队名称,我们会获取他们参与的游戏的数据框,然后获取结果列并使用 map 将他们的名称变成 W 并绘制成 D - 其他任何东西都变成 nan 所以我们使用fillna 将它们变成L,然后使用list()

    出来:

    {'West Ham': ['L'],
     'Man City': ['W'],
     'Everton': ['D'],
     'Burnley': ['W'],
     'AFC Bournemouth': ['D'],
     'Liverpool': ['W'],
     'Norwich City': ['L'],
     'Southampton': ['L'],
     'Sheffield United': ['D'],
     'Crystal Palace': ['D']}
    

    定时器编辑:

    在长度为 1,000,000 的随机 Home/Away/Result 数据集上进行测试,此解决方案似乎比 Chris A. 慢约 10%:

    %timeit d1(df) #d1 is Chris A.'s method
    1.88 s ± 19.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %timeit d2(df) #d2 is my dict comprehension
    2.14 s ± 9.24 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    【讨论】:

    • 这是一个很棒的单行代码,在我的数据集上完美运行,我也很容易接受这个答案。我很感兴趣这两个答案将如何在更大的数据上进行速度比较(我的数据只有 380 行,因为它是一个季节,但速度适用于历史数据)。
    猜你喜欢
    • 1970-01-01
    • 2020-11-22
    • 2017-07-28
    • 2023-01-24
    • 1970-01-01
    • 2022-01-04
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多