Code前端首页关于Code前端联系我们

Python/Pandas如何处理数百亿行、数十列的数据?

terry 2年前 (2023-09-25) 阅读数 64 #后端开发

作者:量子位

使用 Python 和 Pandas 以及循环进行数据分析即将推出。

但其中,即使对于较小的DataFrame,使用标准循环也更耗时。

遇到更大的DataFrame需要更长的时间并且会导致更多的头痛。

现在有些人受不了了。他是来自德国的数据分析师,名叫BenediktDroste。

他表示,在等待了半个多小时代码运行后,他决定寻找更快的替代方案。

在此替代方案中,使用 Numpy 矢量化,与使用标准循环相比,加速率为 71803 倍。 Python/Pandas如何处理百亿行,数十列的数据?

他是如何实现这一目标的?让我们看看 ~

处理 3 年足球比赛数据的标准周期:20.7 秒

DataFrame 是一个具有行和列的 Panda 对象。如果使用循环,则必须循环遍历整个对象。

Python 无法使用任何内置函数并且速度非常慢。在BenediktDroste提供的示例中,这是一个有 65 列和 1140 行的数据框,包含 2016-2019 赛季足球比赛的结果。

要解决的问题是:创建一个新列来指示特定球队是否抽签。您可以这样开始:

def soc_loop(leaguedf,TEAM,):
 leaguedf['Draws'] = 99999
 for row in range(0, len(leaguedf)):
 if ((leaguedf['HomeTeam'].iloc[row] == TEAM) & (leaguedf['FTR'].iloc[row] == 'D')) | \
 ((leaguedf['AwayTeam'].iloc[row] == TEAM) & (leaguedf['FTR'].iloc[row] == 'D')):
 leaguedf['Draws'].iloc[row] = 'Draw'
 elif ((leaguedf['HomeTeam'].iloc[row] == TEAM) & (leaguedf['FTR'].iloc[row] != 'D')) | \
 ((leaguedf['AwayTeam'].iloc[row] == TEAM) & (leaguedf['FTR'].iloc[row] != 'D')):
 leaguedf['Draws'].iloc[row] = 'No_Draw'
 else:
 leaguedf['Draws'].iloc[row] = 'No_Game'
Python/Pandas如何处理百亿行,数十列的数据?

在本例中是阿森纳。在实现目标之前,您需要确认阿森纳参加了哪些比赛,无论是主场还是客场。然而,使用标准循环的速度非常慢,执行时间为20.7秒。

那么我们怎样才能更有效率呢?

Pandas 内置函数:iterrows() ー 快 321 倍

在第一个示例中,整个 DataFrame 是循环的。 iterrows() 为每一行返回一个序列,该序列作为索引对迭代 DataFrame,并将感兴趣的列作为序列迭代。这使得它比标准循环更快:

def soc_iter(TEAM,home,away,ftr):
 #team, row['HomeTeam'], row['AwayTeam'], row['FTR']
 if [((home == TEAM) & (ftr == 'D')) | ((away == TEAM) & (ftr == 'D'))]:
 result = 'Draw'
 elif [((home == TEAM) & (ftr != 'D')) | ((away == TEAM) & (ftr != 'D'))]:
 result = 'No_Draw'
 else:
 result = 'No_Game'
 return result
Python/Pandas如何处理百亿行,数十列的数据?

代码运行时间为 68 毫秒,比标准循环快 321 倍。但许多人不建议使用它,因为仍然有更快的选项,并且 iterrows() 无法存储行之间的数据类型。

这意味着如果您使用DataFrame dtypes iterrows(),您可以更改它,但这会导致很多问题。

如果需要存储dtypes,也可以使用itertuples()。这里就不详细介绍了,官方文档可以在这里找到:

pandas.DataFrame.itertuples - pandas 0.25.1 文档​pandas.pydata.org

apply() 方法 ー811 倍快

自己应用虽然速度不快,但与 DataFrame 结合时有优势。这取决于所应用的表达式的内容。如果应用程序可以像这里一样在 Cython 空间中运行,那么它会快得多。

Apply 可以在 lambda 函数中使用。您所要做的就是指定轴。在本文的示例中,使用轴 1 执行逐列操作: Python/Pandas如何处理百亿行,数十列的数据?

此代码甚至比之前的方法更快,在 27 毫秒内完成。

Pandas 矢量化 - 快 9280 倍

此外,您还可以利用矢量化来创建非常快的代码。

目标是避免像前面示例中那样的 Python 级循环,并使用更有效地使用内存的优化 C 代码。只需稍微更改一下函数即可:

def soc_iter(TEAM,home,away,ftr):
 df['Draws'] = 'No_Game'
 df.loc[((home == TEAM) & (ftr == 'D')) | ((away == TEAM) & (ftr == 'D')), 'Draws'] = 'Draw'
 df.loc[((home == TEAM) & (ftr != 'D')) | ((away == TEAM) & (ftr != 'D')), 'Draws'] = 'No_Draw'

现在您可以使用 Panda 列作为输入创建新列:Python/Pandas如何处理百亿行,数十列的数据?

在这种情况下,您甚至不需要循环。需要做的就是定制该功能的内容。您现在可以将 Panda 列直接传递给函数,从而获得巨大的加速。

Numpy 向量化 — 快 71803 倍

在上面的示例中,Panda 函数传递了一列。当你添加值时,你得到一个 Numpy 数组: Python/Pandas如何处理百亿行,数十列的数据?

因为参考点的优势,Numpy 数组非常快。代码运行时间仅为 0.305 毫秒,比一开始使用的标准循环快了 71803 倍。

谁更强,一目了然

最后,BenediktDroste总结了上述方案。

他说如果你使用Python、Pandas和Numpy进行数据分析,代码总是有改进的空间。

对比以上五种方法,哪一种更快就一目了然了:Python/Pandas如何处理百亿行,数十列的数据?

从这个图中可以得出两个结论:

  • 1。如果要使用循环,则应始终选择 apply 方法。
  • 2。否则,使用矢量化是最好的,因为它更快!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门