映射大DF

2024-05-29 10:53:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个数据帧需要映射并合并成一个。第一个数据框包含NBA球员。标题为“日期”、“球员”、“团队”、“职位”、“工资”、“职位ID”、“分钟”、“FPTS”、“USG”。然后我有第二个数据帧,这是第一个数据帧,但按日期和团队分组。此df的标题为“日期”、“团队”、“分钟”、“FGA”、“FTA”、“To”。我试图计算第一个数据帧中每个播放器的USG速率。要做到这一点,我需要知道在给定的日期,每场比赛中每支球队的总分钟数、射门次数、罚球次数和失误次数。然后,我将同一名球员的数据除以球队的总数据。我有一个可行的解决方案,但它非常缓慢,似乎不是最有效的方法

代码如下:

import pandas as pd

player_df = pd.read_csv('Sample Data') # replace with sample data file

no_dups = player_df.drop_duplicates()
no_dups.loc[:, 'USG'] = pd.Series(dtype=float)
no_dups = no_dups[no_dups.Minutes != 0]

grouped_teams = no_dups.groupby(['Date', 'Team']).agg({'Minutes':['sum'], 'FGA': ['sum'], 'FTA': ['sum'], 'TO': ['sum'] })
grouped_teams.columns = ['Minutes', 'FGA', 'FTA', 'TO']
grouped_teams = grouped_teams.reset_index()

for index, row in no_dups.iterrows():
    for i, r in grouped_teams.iterrows():
        if no_dups.at[index, 'Team'] == grouped_teams.at[i, 'Team'] and no_dups.at[index, 'Date'] == grouped_teams.at[i, 'Date']:
            no_dups.at[index, 'USG'] = (100*((no_dups.at[index, 'FGA'] + 0.44 * no_dups.at[index, 'FTA'] + no_dups.at[index, 'TO'])*(grouped_teams.at[i, 'Minutes']/5))) / (no_dups.at[index, 'Minutes']*(grouped_teams.at[i, 'FGA']+0.44*grouped_teams.at[i, 'FTA']+grouped_teams.at[i, 'TO']))
    
final_df = no_dups[['Date', 'Player', 'Team', 'Position', 'Salary',  'Minutes', 'FPTS', 'USG']]

print(final_df)

我已经删除了所有没有参加比赛的球员,因为同一个球员可以在一个晚上参加多场比赛,所以我删除了那些球员。然后,我创建了一个名为grouped_teams的df,它是df中按日期和团队名称分组的每个团队。然后,我使用iterrows和第二个df以相同的方式迭代第一个df。我需要找到每个球员的球队和具体日期,然后将他的统计数据除以计算出的总数,得到使用率。该列为no_dups.at[index, 'USG']。在我的df中有73k行,因此遍历每一行需要很长时间

Sample Data


Tags: 数据nodfdateindex团队at球员
1条回答
网友
1楼 · 发布于 2024-05-29 10:53:21

它需要永远,因为您正在逐行迭代。我似乎找不到这篇文章,但我记得在某个地方读过一篇文章,在比较遍历数据帧的方法时,itertuples比iterrows快10倍左右,zip快100倍左右。但是,有时我想从iterrows切换到itertuples时遇到的问题是,您会丢失作为索引的列名,因此您需要特别确保使用itertuples时列的顺序(尽管现在我正在考虑,我认为有一种方法可以动态跟踪)

但最快的方法是对所有行进行计算,而不是逐个进行计算

我要做的是,在第二个数据框中,计算团队总数。因此,在['Date','Team']上进行左连接/合并,以匹配no_dups数据帧上的总数。然后,您可以使用整行列来计算它,而不是一次只计算一行。我还稍微更改了列的名称,好像您合并了,并且有同名的列,它将添加一个后缀_x_y。有办法解决这个问题,但我想直接改变名字。我还稍微改变了列的命名方式,通过不硬编码(这意味着列必须按顺序排列),它可以以更健壮的方式处理名称

你还有另一个问题。日期列有不同的格式(即'1/1/18''2018-01-01'),因此在您的groupby中,这些格式不会聚合在一起。因此,我们需要首先处理这一问题。它似乎仅适用于Brooklyn网络,但在您的完整数据集中可能会更多

代码:

import pandas as pd

player_df = pd.read_csv('Sample Data.csv') # replace with sample data file

# Get the date column to be the same
player_df['Date'] = pd.to_datetime(player_df['Date'])

no_dups = player_df.drop_duplicates()
no_dups = no_dups[no_dups.Minutes != 0]

grouped_teams = no_dups.groupby(['Date', 'Team']).agg({'Minutes':['sum'], 'FGA': ['sum'], 'FTA': ['sum'], 'TO': ['sum'] })
grouped_teams.columns = ['tot_' + col[0] for col in grouped_teams.columns]
grouped_teams = grouped_teams.reset_index()


# Merge grouped_teams to no_dups on Team and Date
no_dups = no_dups.merge(grouped_teams, how='left', on=['Team','Date'])

# Do the calculations
no_dups['USG'] = (100*((no_dups['FGA'] + 0.44 * no_dups['FTA'] + no_dups['TO'])*(no_dups['tot_Minutes']/5))) / (no_dups['Minutes']*(no_dups['tot_FGA']+0.44*no_dups['tot_FTA']+no_dups['tot_TO']))
    
final_df = no_dups[['Date', 'Player', 'Team', 'Position', 'Salary',  'Minutes', 'FPTS', 'USG']]

print(final_df)

时间:

我对每种方式都进行了计时(不包括在csv中读取的时间)

在样本数据(4493行)上,iError花费了大约3 minutes 46.66 seconds
我的代码花了大约0.0568 seconds,所以快了将近4000倍

相关问题 更多 >

    热门问题