【问题标题】:Better way to execute iterative function for very large dataset in python在python中为非常大的数据集执行迭代函数的更好方法
【发布时间】:2021-09-10 13:10:59
【问题描述】:
for i in range(1,len(df_raw)):
    if df_raw.loc[i-1, 'A']!= 0 & df_raw.loc[i, 'A']== 0 & df_raw.loc[i+1, 'A']== 0:
        df_raw.loc[i,'B'] = df_raw.loc[i+5,'B']

大家好, 我正在尝试在我的数据上运行上面的代码行。 直到数据在 100,000-150,000 行范围内,我才能运行此代码,但对于更大的数据,它只会继续运行而没有输出。 你能帮我用更好的方式编写这段代码以获得更大的数据量吗?

【问题讨论】:

  • 请解释您在此处尝试执行的逻辑(您的代码),以便人们更容易以更有效的方式解决您想要的问题。此外,提供一个示例数据框(即使是 5 行)将有助于理解您的列和逻辑。

标签: python pandas for-loop iteration


【解决方案1】:

我认为您缺少的有效执行这种逻辑的方法是shift。这是我的建议:

df_raw = df_raw.sort_index() # Optional, if index is not sorted
df_raw['A_is_zero'] = df_raw['A'] == 0
df_raw['prev_A_is_zero'] = df_raw['A_is_zero'].shift(1).fillna(True)
df_raw['next_A_is_zero'] = df_raw['A_is_zero'].shift(-1).fillna(False)
B_to_change = df_raw['A_is_zero'] & df_raw['next_A_is_zero'] & ~df_raw['prev_A_is_zero']
df_raw.loc[B_to_change, 'B'] = df_raw['B'].shift(-5).loc[B_to_change]

由于您没有提供示例数据框,但我没有对其进行测试,因此我不能保证它会起作用,但我认为我提供了实现解决方案的主要思想。例如,在最后一行之前的四行中,如果 B_to_change 为 True,您将在“B”中获得 NaN。另一件事是您将.loc 与整数一起使用,但我不知道您的索引是否是一个范围,在这种情况下,我的第一行是无用的,或者如果不是并且您打算使用iloc(请参阅 this link 关于 loc / iloc 的区别),在这种情况下,我的第一行应该被删除,因为它不会导致预期的结果。


编辑:

我的要求有一些迭代条件顺序操作, 例如:

for i in range(1, len(df_raw)):
    if df_raw.loc[i, 'B'] != 0:
        df_raw.loc[i, 'A'] = df_raw.loc[i-1, 'A']

在这种情况下(您应该在问题中指定),您可以使用前向填充,如下所示:

B_is_zero = df_raw['B'] == 0
df_raw['new_A'] = None
df_raw.loc[B_is_zero, 'new_A'] = df_raw.loc[B_is_zero, 'A'] 
df_raw['A'] = df_raw['new_A'].fillna(method='ffill')

再一次,您应该注意如何处理“B”在第一行非零的边缘情况。

【讨论】:

  • 感谢回复...但我的要求有一些迭代条件顺序操作,这些操作无法使用“移位”方法。例如:` for i in range(1,len(df_raw)):` if df_raw.loc[i, 'B'] != 0: df_raw.loc[i,'A'] = df_raw.loc[i-1,'A']
  • @tausifshams 请注意,这仍然可以进行矢量化。 TLouf 更新的ffill 代码可能是最简单的,而且会比循环快得多。
【解决方案2】:

您的代码可能需要很长时间才能运行,因为它必须执行大量步骤。 (超过 150,000 人)。我建议您做几件事:

  1. 查看是否需要为数组中的每个元素运行代码。如果没有,这将显着提高性能。
  2. 检查top/任务管理器/系统监视器(取决于操作系统),看看你的内存是否用完了。
  3. 将您的按位和 (&) 更改为更惯用和更快的(短路)and
  4. Profile your code
  5. 添加进度条:
    在命令行:pip install tqdm
    在您的代码中
from tqdm import tqdm

for i in tqdm(range(1,len(df_raw))):
    if df_raw.loc[i-1, 'A'] != 0 and df_raw.loc[i, 'A'] == 0 and df_raw.loc[i+1, 'A']== 0:
        df_raw.loc[i,'B'] = df_raw.loc[i+5,'B']
  1. 考虑multiprocessing。如果您可以将代码拆分为离散的段,则可以在多核系统上将其并行化。这可能很难正确完成,所以我将从上述步骤开始。如果您决定采用这条路线并需要帮助,请使用更完整的代码示例编辑您的问题。

【讨论】:

  • 非常感谢您的回复...只是从 '&' --> 'and' 的一个小变化,大大提高了速度.... Aslo tqdm 有助于很好地可视化进度....
猜你喜欢
  • 1970-01-01
  • 2020-06-28
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-14
相关资源
最近更新 更多