查看前一行值时用于循环优化(矢量化)的 Pandas

Posted

技术标签:

【中文标题】查看前一行值时用于循环优化(矢量化)的 Pandas【英文标题】:Pandas for Loop Optimization(Vectorization) when looking at previous row value 【发布时间】:2021-05-12 12:06:05 【问题描述】:

我希望通过 for 循环优化函数所花费的时间。下面的代码适用于较小的数据帧,但对于较大的数据帧,它需要的时间太长。该函数基于使用其他列值和参数的计算有效地创建一个新列。该计算还考虑其中一列的前一行值的值。我读到最有效的方法是使用 Pandas 向量化,但是当我的 for 循环考虑 1 列的前一行值以在当前行上填充新列时,我很难理解如何实现这一点。我是一个完全的新手,但是环顾四周,找不到任何适合这个特定问题的东西,虽然我是从一个相对无知的位置搜索的,所以可能错过了一些东西。

函数如下,我也创建了一个测试数据框和随机参数。如果有人能指出我正确的方向以缩短处理时间,那就太好了。提前致谢。

def MODE_Gain (Data, rated, MODELim1, MODEin, Normalin,NormalLim600,NormalLim1):
    print('Calculating Gains')
    df = Data
    df.fillna(0, inplace=True)
    df['MODE'] = ""
    df['Nominal'] = ""
    df.iloc[0, df.columns.get_loc('MODE')] = 0
    for i in range(1, (len(df.index))):
        print('Computing Statusi/r'.format(i=i, r=len(df.index)))
        if ((df['MODE'].loc[i-1] == 1) & (df['A'].loc[i] > Normalin)) :
            df['MODE'].loc[i] = 1
        elif (((df['MODE'].loc[i-1] == 0) & (df['A'].loc[i] > NormalLim600))|((df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ))):
            df['MODE'].loc[i] = 1
        else:
            df['MODE'].loc[i] = 0
    df[''] = (df['C']/6)
    for i in range(len(df.index)):
       print('Computing MODE Gains i/r'.format(i=i, r=len(df.index)))
       if ((df['A'].loc[i] > MODEin) & (df['A'].loc[i] < NormalLim600)&(df['B'].loc[i] < NormalLim1)) :
            df['Nominal'].loc[i] = rated/6
       else:
            df['Nominal'].loc[i] = 0
    df["Upgrade"] = df[""] - df["Nominal"]
    
    return df


A = np.random.randint(0,28,size=(8000))
B = np.random.randint(0,45,size=(8000))
C = np.random.randint(0,2300,size=(8000))

df = pd.DataFrame()

df['A'] = pd.Series(A)
df['B'] = pd.Series(B)
df['C'] = pd.Series(C)

MODELim600 = 32
MODELim30 = 28
MODELim1 = 39
MODEin = 23
Normalin = 20
NormalLim600 = 25
NormalLim1 = 32
rated = 2150

finaldf = MODE_Gain(df, rated, MODELim1, MODEin, Normalin,NormalLim600,NormalLim1)

【问题讨论】:

【参考方案1】:

您的第二个循环不会评估前一行,因此您应该可以改用它

df['Nominal'] = 0
df.loc[(df['A'] > MODEin) & (df['A'] < NormalLim600) & (df['B'] < NormalLim1), 'Nominal'] = rated/6

对于您的第一个循环,elif 语句看起来会对此进行评估

((df['B'].loc[i] &gt; NormalLim1) &amp; (df['B'].loc[i] &lt; MODELim1 )) 并将其设置为 1 而不管其他条件如何,因此您可以删除它并矢量化该操作。没试过,但应该这样做

df.loc[(df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ), 'MODE'] = 1

那么您可以将其他条件合并到一个语句中使用|

不确定所有这些能节省多少,但您应该将时间减半,摆脱第二个循环。

【讨论】:

谢谢乔纳森,删除第二个循环效果很好,而且很有意义。有时只见树木不见森林。此外,对于第一个循环,我通过实施您建议的更改,仅使用 df.loc[(df['B'] > NormalLim1) & (df['B'] 很高兴它有帮助。【参考方案2】:

为了对其进行矢量化,我建议您首先将您的列移到另一列中:

df['MODE_1'] = df['MODE'].shift(1)

然后使用:

(df['MODE_1'].loc[i] == 1) 

之后你应该能够矢量化

【讨论】:

以上是关于查看前一行值时用于循环优化(矢量化)的 Pandas的主要内容,如果未能解决你的问题,请参考以下文章

如何使一行代码在循环中运行一次,并且只运行下一行代码,直到前一行运行一次?

用于对熊猫进行比较的循环

如何在 Visual Studio 2015(用于 C++)中仅禁用 SIMD 自动矢量化优化?

panda迭代

循环矢量化以及如何避免它

你将如何优化这个简短但非常慢的 Python 循环?