【问题标题】:Python 'for' loop performance too slowPython'for'循环性能太慢
【发布时间】:2020-07-27 21:03:40
【问题描述】:

我的数据框中有超过 500,000 行和许多类似的“for”循环,这导致我的代码需要一个多小时才能完成计算。是否有更有效的方法来编写以下“for”循环,以便运行得更快:

col_26 = []
col_27 = []
col_28 = []


for ind in df.index:
    if df['A_factor'][ind] > df['B_factor'][ind]:
        col_26.append('Yes')
        col_27.append('No')
        col_28.append(df['A_value'][ind])
    elif df['A_factor'][ind] < df['B_factor'][ind]:
        col_26.append('No')
        col_27.append('Yes')
        col_28.append(df['B_value'][ind])
    else:
        col_26.append('')
        col_27.append('')
        col_28.append(float('nan'))

【问题讨论】:

  • 一个包含 500,000 个项目的 for 循环在不到一秒的时间内运行。所以不是for 循环导致了问题。
  • 如果在 Pandas 或 NumPy 中完成,事情可能会快得多...
  • 使用列操作。
  • 您能提供更多信息吗?更多代码?如果您要创建许多 500,000 长度的列表,您可能会使用大量内存,这会导致速度变慢,这不是 cpu 问题。

标签: python loops


【解决方案1】:

您可能想查看 pandas iterrows() 函数或使用 apply,您也可以查看这篇文章:https://towardsdatascience.com/how-to-make-your-pandas-loop-71-803-times-faster-805030df4f06

【讨论】:

    【解决方案2】:

    尝试列操作:

    data = {'A_factor': [1, 2, 3, 4, 5],
            'A_value': [10, 20, 30, 40, 50],
               'B_factor': [2, 3, 1, 2, 6],
            'B_value': [11, 22, 33, 44, 55]}
    df = pd.DataFrame(data)
    df['col_26'] = ''
    df['col_27'] = ''
    df['col_28'] = np.nan
    
    mask = df['A_factor'] > df['B_factor']
    df.loc[mask, 'col_26'] = 'Yes'
    df.loc[~mask, 'col_26'] = 'No'
    df.loc[mask, 'col_28'] = df[mask]['A_value']
    
    df.loc[~mask, 'col_27'] = 'Yes'
    df.loc[mask, 'col_27'] = 'No'
    df.loc[~mask, 'col_28'] = df[~mask]['B_value']
    

    【讨论】:

      【解决方案3】:

      在 Python 中附加到列表非常缓慢。在迭代之前初始化列表可以加快速度。例如,

      def f():
          x = []
          for ii in range(500000):
              x.append(str(x))
      
      def f2():
          x = [""] * 500000
          for ii in range(500000):
              x[ii] = str(x)
      
      
      timeit.timeit("f()", "from __main__ import f", number=10)
      # Output: 1.6317970999989484
      timeit.timeit("f2()", "from __main__ import f2", number=10)
      # Output: 1.3037318000024243
      

      由于您已经在使用 pandas / numpy,因此有一些方法可以对您的操作进行矢量化,这样它们就不需要循环了。例如:

      a_factor = df["A_factor"].to_numpy()
      b_factor = df["B_factor"].to_numpy()
      
      col_26 = np.empty(a_factor.shape, dtype='U3') # U3 => string of size 3
      col_27 = np.empty(a_factor.shape, dtype='U3')
      col_28 = np.empty(a_factor.shape)
      
      a_greater = a_factor > b_factor
      b_greater = a_factor < b_factor
      both_equal = a_factor == b_factor
      
      col_26[a_greater] = 'Yes'
      col_26[b_greater] = 'No'
      
      col_27[a_greater] = 'Yes'
      col_27[b_greater] = 'No'
      
      col_28[a_greater] = a_factor[a_greater]
      col_28[b_greater] = b_factor[b_greater]
      col_28[both_equal] = np.nan
      

      【讨论】:

      • 感谢您花时间提供该示例。我还将研究矢量化,我对此很陌生,但在这里学习。再次感谢
      【解决方案4】:

      append 导致 python 请求堆内存以获取更多内存。在for 循环中使用append 会导致获取内存并不断释放它以获取更多内存。所以最好告诉python你需要多少项目。

      col_26 = [True]*500000
      col_27 = [False]*500000
      col_28 = [float('nan')]*500000
      
      for ind in df.index:
          if df['A_factor'][ind] > df['B_factor'][ind]:
              col_28[ind] = df['A_value'][ind]
          elif df['A_factor'][ind] < df['B_factor'][ind]:
              col_26[ind] = False
              col_27[ind] = True
              col_28[ind] = df['B_value'][ind]
          else:
              col_26[ind] = ''
              col_27[ind] = ''
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-16
        • 1970-01-01
        • 1970-01-01
        • 2016-01-01
        • 2020-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多