Pandas 查看前一行值时进行循环优化(矢量化)
Pandas for Loop Optimization(Vectorization) when looking at previous row value
我正在寻求优化带有 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 Status{i}/{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)
你的第二个循环不计算前一行,所以你应该可以使用它来代替
df['Nominal'] = 0
df.loc[(df['A'] > MODEin) & (df['A'] < NormalLim600) & (df['B'] < NormalLim1), 'Nominal'] = rated/6
对于你的第一个循环,elif 语句看起来会评估这个
((df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ))
并将其设置为 1 而不管其他条件如何,因此您可以删除它并对该操作进行矢量化。没试过,但应该可以了
df.loc[(df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ), 'MODE'] = 1
然后您可以将其他条件合并为一个语句使用 |
不确定这能为您节省多少,但您应该将时间减半以摆脱第二个循环。
为了对其进行矢量化,我建议您先将您的列移到另一个列中:
df['MODE_1'] = df['MODE'].shift(1)
然后使用:
(df['MODE_1'].loc[i] == 1)
之后你应该可以矢量化
我正在寻求优化带有 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 Status{i}/{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)
你的第二个循环不计算前一行,所以你应该可以使用它来代替
df['Nominal'] = 0
df.loc[(df['A'] > MODEin) & (df['A'] < NormalLim600) & (df['B'] < NormalLim1), 'Nominal'] = rated/6
对于你的第一个循环,elif 语句看起来会评估这个
((df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ))
并将其设置为 1 而不管其他条件如何,因此您可以删除它并对该操作进行矢量化。没试过,但应该可以了
df.loc[(df['B'].loc[i] > NormalLim1) & (df['B'].loc[i] < MODELim1 ), 'MODE'] = 1
然后您可以将其他条件合并为一个语句使用 |
不确定这能为您节省多少,但您应该将时间减半以摆脱第二个循环。
为了对其进行矢量化,我建议您先将您的列移到另一个列中:
df['MODE_1'] = df['MODE'].shift(1)
然后使用:
(df['MODE_1'].loc[i] == 1)
之后你应该可以矢量化