猿问

Pandas - 功能有条件地更新下一行的某些列

我有 csv 文件,其中包含来自不同足球比赛的大量结果。数据类似于下面的示例。该result列可以包含 3 个可能的值:

  • H -> 主队获胜(主队获得+3分)

  • A -> 客队获胜(客场将获得 + 3 分)

  • D -> 平局(两队均获得 +1 分)

   HomeTeam    AwayTeam Result

0   FC_Fake  ABC_United      H

1  Team_123   FC_Berlin      A

2   FC_FAKE    TEAM_123      D

我想更新文件,以便每一行都包含每支球队的总积分as they are at the start of the match(因此尚未更新该行本身的比赛结果)


我使用以下代码更新数据框,因此它包含points_[TEAM_NAME]每个团队的虚拟列。


# Teams is a python list I extracted earlier

for team in teams:

    df['points_' + team] = 0

目标是转换数据帧,使上面的例子变成下面的例子。


(同样,分数应该代表比赛开始时的情况。所以即使FC_FAKE在第一行赢得比赛,Points_FC_FAKE列也是 0 )


HomeTeam | AwayTeam | Result  Points_FC_FAKE | Points_TEAM_123 | Points_FC_Berlin |  etc

-------------------------------------------------------------------------------

 FC_Fake  ABC_United    H         0                  0             0

 Team_123 FC_Berlin     A         3                  0             0

 FC_FAKE  Team_123      D         3                  0             3

我创建了以下 python 函数,如果它遍历数据帧中的所有行,则应解析结果并将正确的点数奖励给正确的团队。


def point_updater(x):

    if x['Result'] == 'H':        

        home = x['HomeTeam']

        x.shift(-1)['points_' + home] += 3

        return x


    elif x['Result'] == 'A':        

        away = x['AwayTeam']

        x.shift(-1)['points_' + away] += 3

        return x


    elif x['Result'] == 'D':        

        home = x['AwayTeam']

        away = x['AwayTeam']

        x.shift(-1)['points_' + home] += 1

        x.shift(-1)['points_' + away] += 1

        return x


问题是当我将此函数应用于数据帧时,点不会改变(全部保持为 0)


df = df.apply(point_counter, axis=1)

df['points_FC_Fake'].value_counts()

----

0    2691


有谁知道我做错了什么?


慕斯王
浏览 192回答 3
3回答

千巷猫影

在某些例外情况下,我们可以使用iterrows它。另外,在开始计算之前,我通过进行一些清理使您的代码更具故障证明性和通用性:# Convert to uppercase letters df['HomeTeam'] = df['HomeTeam'].str.upper()df['AwayTeam'] = df['AwayTeam'].str.upper()# get a list off all the teams in competitionlst_teams = list(set(list(df.HomeTeam.unique()) + list(df.AwayTeam.unique())))# Create columns for each teamfor team in lst_teams:    df[team] = 0# Iterate over each row and assign correct pointsfor idx, r in df.iterrows():    if r['Result'] == 'H':        df.loc[[idx], [r['HomeTeam']]] = 3    if r['Result'] == 'A':        df.loc[[idx], [r['AwayTeam']]] = 3    if r['Result'] == 'D':        df.loc[[idx], [r['AwayTeam']]] = 1        df.loc[[idx], [r['HomeTeam']]] = 1# Shift the rows one down, since points are only available at start of matchdf.iloc[:, 3:] = df.iloc[:, 3:].cumsum().shift(1).fillna(0).astype(int)输出print(df)   HomeTeam    AwayTeam Result  ABC_UNITED  TEAM_123  FC_FAKE  FC_BERLIN0   FC_FAKE  ABC_UNITED      H           0         0        0          01  TEAM_123   FC_BERLIN      A           0         0        3          02   FC_FAKE    TEAM_123      D           0         0        3          3

慕的地8271018

可能有一种更简洁的方式来执行这些操作,但现在应该足够了。您可以使用df.replace()将Result键映射到它们的关联值,然后使用pd.concat()和pd.DataFrame.pivot()实现您想要的结果:import pandas as pddf = pd.DataFrame({'HomeTeam': ['FC_Fake','Team_123','FC_Fake'], 'AwayTeam': ['ABC_United','FC_Berlin','Team_123'], 'Result': ['H','A','D']})remap = df.replace({'H': 3, 'A': 3, 'D': 1})new = pd.concat([remap.pivot(columns='HomeTeam', values='Result'), remap.pivot(columns='AwayTeam', values='Result')], axis=1).shift(1).fillna(0).astype(int).cumsum()final = pd.concat([df, new], axis=1)产量:   HomeTeam    AwayTeam Result  FC_Fake  Team_123  ABC_United  FC_Berlin  \0   FC_Fake  ABC_United      H        0         0           0          0   1  Team_123   FC_Berlin      A        3         0           3          0   2   FC_Fake    Team_123      D        3         3           3          3      Team_123  0         0  1         0  2         0 

慕妹3242003

将您的功能更改为:def point_updater(x):    if x['Result'] == 'H':            home = x['HomeTeam']        x['points_' + home] += 3        return x    elif x['Result'] == 'A':                away = x['AwayTeam']        x['points_' + away] += 3        return x    elif x['Result'] == 'D':                home = x['HomeTeam']        away = x['AwayTeam']        x['points_' + home] += 1        x['points_' + away] += 1        return x然后在代码的末尾添加:df = df.apply(point_updater,axis=1)for team in teams:    df["points_" + team]= df["points_" + team].cumsum()
随时随地看视频慕课网APP

相关分类

Python
我要回答