【问题标题】:Pandas dataframe vectorizing/filtering: ValueError: Can only compare identically-labeled Series objectsPandas 数据帧矢量化/过滤:ValueError:只能比较标记相同的系列对象
【发布时间】:2019-11-02 01:17:09
【问题描述】:

我有两个带有 NHL 曲棍球统计数据的数据框。一个包含过去十年每支球队参加的每场比赛,另一个是我想用计算值填充它的地方。简而言之,我想从一支球队的前五场比赛中获取一个指标,将其相加,然后将其放入另一个 df 中。我已经在下面修剪了我的 dfs 以排除其他统计数据,并且只会查看一个统计数据。

df_all 包含所有游戏:

>>> df_all
        season      gameId playerTeam opposingTeam  gameDate  xGoalsFor  xGoalsAgainst
1         2008  2008020001        NYR          T.B  20081004      2.287          2.689
6         2008  2008020003        NYR          T.B  20081005      1.793          0.916
11        2008  2008020010        NYR          CHI  20081010      1.938          2.762
16        2008  2008020019        NYR          PHI  20081011      3.030          3.020
21        2008  2008020034        NYR          N.J  20081013      1.562          3.454
...        ...         ...        ...          ...       ...        ...            ...
142576    2015  2015030185        L.A          S.J  20160422      2.927          2.042
142581    2017  2017030171        L.A          VGK  20180411      1.275          2.279
142586    2017  2017030172        L.A          VGK  20180413      1.907          4.642
142591    2017  2017030173        L.A          VGK  20180415      2.452          3.159
142596    2017  2017030174        L.A          VGK  20180417      2.427          1.818

df_sum_all 将包含计算的统计数据,现在它有一堆空列:

>>> df_sum_all
     season team  xg5  xg10  xg15  xg20
0      2008  NYR    0     0     0     0
1      2009  NYR    0     0     0     0
2      2010  NYR    0     0     0     0
3      2011  NYR    0     0     0     0
4      2012  NYR    0     0     0     0
..      ...  ...  ...   ...   ...   ...
327    2014  L.A    0     0     0     0
328    2015  L.A    0     0     0     0
329    2016  L.A    0     0     0     0
330    2017  L.A    0     0     0     0
331    2018  L.A    0     0     0     0

这是我计算 xGoalsFor 和 xGoalsAgainst 比率的函数。

def calcRatio(statfor, statagainst, games, season, team, statsdf):
    tempFor = float(statsdf[(statsdf.playerTeam == team) & (statsdf.season == season)].nsmallest(games, 'gameDate').eval(statfor).sum())
    tempAgainst = float(statsdf[(statsdf.playerTeam == team) & (statsdf.season == season)].nsmallest(games, 'gameDate').eval(statagainst).sum())
    tempRatio = tempFor / tempAgainst
    return tempRatio

我相信这是合乎逻辑的。我输入了我想要计算比率的统计数据,要计算的比赛场次,要匹配的赛季和球队,然后从哪里获取统计数据。我已经分别测试了这些函数,并且知道我可以很好地过滤,并对统计数据求和,等等。以下是 tempFor 计算的独立实现示例:

>>> statsdf = df_all
>>> team = 'TOR'
>>> season = 2015
>>> games = 3
>>> tempFor = float(statsdf[(statsdf.playerTeam == team) & (statsdf.season == season)].nsmallest(games, 'gameDate').eval(statfor).sum())
>>> print(tempFor)
8.618

看到了吗?它返回一个值。但是我不能在整个数据框中做同样的事情。我错过了什么?我认为这种工作方式基本上适用于每一行,它将“xg5”列设置为 calcRatio 函数的输出,该函数使用该行的“季节”和“团队”来过滤 df_all。

>>> df_sum_all['xg5'] = calcRatio('xGoalsFor','xGoalsAgainst',5,df_sum_all['season'], df_sum_all['team'], df_all)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in calcRatio
  File "/home/sebastian/.local/lib/python3.6/site-packages/pandas/core/ops/__init__.py", line 1142, in wrapper
    raise ValueError("Can only compare identically-labeled " "Series objects")
ValueError: Can only compare identically-labeled Series objects

干杯,感谢您的帮助!

更新:我使用了 iterrows() 并且效果很好,所以我一定不是很了解矢量化。但它是相同的功能 - 为什么它以一种方式工作,而不是另一种方式?

>>> emptyseries = []
>>> for index, row in df_sum_all.iterrows():
...     emptyseries.append(calcRatio('xGoalsFor','xGoalsAgainst',5,row['season'],row['team'], df_all))
... 
>>> df_sum_all['xg5'] = emptyseries
__main__:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
>>> df_sum_all
     season team       xg5  xg10  xg15  xg20
0      2008  NYR  0.826260     0     0     0
1      2009  NYR  1.288390     0     0     0
2      2010  NYR  0.915942     0     0     0
3      2011  NYR  0.730498     0     0     0
4      2012  NYR  0.980744     0     0     0
..      ...  ...       ...   ...   ...   ...
327    2014  L.A  0.823998     0     0     0
328    2015  L.A  1.147412     0     0     0
329    2016  L.A  1.054947     0     0     0
330    2017  L.A  1.369005     0     0     0
331    2018  L.A  0.721411     0     0     0

[332 rows x 6 columns]

【问题讨论】:

  • 看在上帝的份上,请使用itertuples 而不是iterrows!有关iterrows 的一些奇怪行为,请参阅pandas docs。性能也差很多,在非常基本的任务上,我们说的速度比itertuples 慢 1000 倍。
  • 另外,您能否提供一种更简单的方法来访问测试数据?复制粘贴和弄乱您共享的 DataFrame 输出会很乏味。考虑到计算的性质,可能需要大量的测试数据。事实上,我觉得数据的格式会对这个问题产生很大的影响。好消息是它看起来相对简单:)
  • 是的,我意识到 iterrows 很烂;但至少它确实有效,所以它确认我的功能很好。我必须从我的输入文件中对数据进行相当多的转换,分享它并不容易。
  • 数据问题:是否每场比赛出现两次,每队一次?
  • 是的,确实如此。没关系,因为我需要从每个团队的角度来看它,另一种选择是只让游戏出现一次,然后选择 playerTeam/opposingTeam 并找到两者中的前 5/10/15/etc 实例,这比我计划的要多一点。

标签: python pandas dataframe vectorization


【解决方案1】:

“ValueError:只能比较标签相同的系列对象”

tempFor = float(statsdf[(statsdf.playerTeam == team) & (statsdf.season == season)].nsmallest(games, 'gameDate').eval(statfor).sum())
tempAgainst = float(statsdf[(statsdf.playerTeam == team) & (statsdf.season == season)].nsmallest(games, 'gameDate').eval(statagainst).sum())

变量的输入:

team: df_sum_all['team']
season: df_sum_all['season']
statsdf: df_all

所以在代码中,(statsdf.playerTeam == team),它将比较来自 df_sum_all 和来自 df_all 的系列。 如果这两个标签不同,你会看到上面的错误。

【讨论】:

  • 谢谢 - 我确实认为这就是它发生的原因。那么我的问题是如何避免它?我想在整个数据帧上运行我的函数,矢量化使它非常快,但我需要使用多个数据帧,因此比较它们意味着它们的标签不同。我不认为我可以在函数中将它们转换为 str/int,因为在整个数组上运行它时,它会将整个列作为输入,而不是一次只有一个值。所以用 .apply 运行它似乎是我能得到的最快的。
  • @Sebastian 如果您为它们设置相同的索引,两个数据框仍然可以使用相同的标签。但这要求它们具有相同的长度。如果它们的长度不同,请尝试将它们连接在一起并过滤掉一些不必要的行,然后进行向量化。
  • 不幸的是,将它们连接在一起并不容易,因为它们包含截然不同的数据。我在 df.apply 上做得很好。感谢您的帮助!
猜你喜欢
  • 2020-05-05
  • 1970-01-01
  • 2020-09-17
  • 2018-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
  • 1970-01-01
相关资源
最近更新 更多