如何在不使用 for 循环的情况下使用涉及前几行单元格的计算来填充 Pandas 列
How to Fill Pandas Column with calculations involving cells from previous rows without Using for loop
以绿色突出显示的单元格是需要在 pandas 数据框中完成的计算,无需应用 for 循环。
我尝试了下面的代码。
但它在“Val”列中给出了错误的值。
从代码中获得的输出是
数据框:df
帕瓦尔
0 50 50.0
1 60 57.0
2 70 67.0
3 80 77.0
4 90 87.0
5 100 97.0
在不使用循环应用程序的情况下获取图像中显示的值时需要帮助。
[![在此处输入图片描述][2]][2]
[![在此处输入图片描述][2]][2]
df = pd.DataFrame()
df['Par'] = [50,60,70,80,90,100]
k = df['Par'].shift(1).fillna(df['Par'][0]).astype(float)
df['Val'] = (df['Par']*0.7) + (k*0.3)
print("DataFrame: df\n",df)`
我不确定这个答案是否足够好。
首先,您的代码无法像 Excel 那样工作的原因是 Excel 使用的是累积计算,这意味着 k 值是根据公式的结果更新的df["par"] 和 k 的前一行中的值。问题本身的性质必须通过使用前一行来解决;这意味着逐行。
如何做到这一点很简单。
import pandas as pd
df = pd.DataFrame()
df['Par'] = [50,60,70,80,90,100]
df.loc[0,"Val"] = df.loc[0,"Par"] #similar to =A5 in excel
Par Val
0 50 50.0
1 60 NaN
2 70 NaN
3 80 NaN
4 90 NaN
5 100 NaN
的概念是na的值会填充上一行和同行不同的计算。但是第三、四、五行没有之前的值需要计算,所以,它们会重新用na填充。
df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
Par Val
0 50 50.0
1 60 57.0
2 70 NaN
3 80 NaN
4 90 NaN
5 100 NaN
在我们估算了 Val 的第二行之后,第三行现在有一个以前的值来估算自己。所以,我们运行再次上线。
Par Val
0 50 50.0
1 60 57.0
2 70 66.1
3 80 NaN
4 90 NaN
5 100 NaN
所以,现在第四次也是如此,然后是第五次。但是当你有超过 5 行时,一次又一次地 运行 宁这一行对你来说将是一件苦差事。所以,在这种情况下,我们会使用(是的)循环。
但是您的请求包括 without Using for loop 部分,我对此感到不知所措。可能有办法做到这一点,但对我来说,我坚持计算 -> 获取价值 -> 计算。因此,这里有几个循环,它们不使用数据帧本身的任何数据,而只是重复代码多次。
i == 0
if i < len(df):
df["Val"]=df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
++i
for i in range(len(df)):
df["Val"]=df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
++i
import itertools
for _ in itertools.repeat(None, len(df)):
df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
如果您找到了不使用循环的方法,请与我们分享。多亏了你们,我今天度过了一个非常有趣的夜晚。
递归计算不可向量化,为了提高性能使用 numba:
from numba import jit
@jit(nopython=True)
def f(a):
d = np.empty(a.shape)
d[0] = a[0]
for i in range(1, a.shape[0]):
d[i] = d[i-1] * 0.3 + a[i] * 0.7
return d
df['Val'] = f(df['Par'].to_numpy())
print (df)
Par Val
0 50 50.0000
1 60 57.0000
2 70 66.1000
3 80 75.8300
4 90 85.7490
5 100 95.7247
1k 行的性能差异:
from numba import jit
import itertools
np.random.seed(2022)
df = pd.DataFrame({'Par': np.random.randint(100, size=1000)})
In [64]: %%timeit
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...: import itertools
...:
...: df.loc[0,"Val"] = df.loc[0,"Par"]
...: for _ in itertools.repeat(None, len(df)):
...: df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
...:
1.05 s ± 193 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [65]: %%timeit
...: @jit(nopython=True)
...: def f(a):
...: d = np.empty(a.shape)
...: d[0] = a[0]
...: for i in range(1, a.shape[0]):
...: d[i] = d[i-1] * 0.3 + a[i] * 0.7
...: return d
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
121 ms ± 3.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
测试 100krows:
np.random.seed(2022)
df = pd.DataFrame({'Par': np.random.randint(100, size=100000)})
In [70]: %%timeit
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...: import itertools
...:
...: df.loc[0,"Val"] = df.loc[0,"Par"]
...: for _ in itertools.repeat(None, len(df)):
...: df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
...:
4min 47s ± 5.39 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [71]: %%timeit
...: @jit(nopython=True)
...: def f(a):
...: d = np.empty(a.shape)
...: d[0] = a[0]
...: for i in range(1, a.shape[0]):
...: d[i] = d[i-1] * 0.3 + a[i] * 0.7
...: return d
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...:
129 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
以绿色突出显示的单元格是需要在 pandas 数据框中完成的计算,无需应用 for 循环。
我尝试了下面的代码。 但它在“Val”列中给出了错误的值。
从代码中获得的输出是
数据框:df 帕瓦尔 0 50 50.0 1 60 57.0 2 70 67.0 3 80 77.0 4 90 87.0 5 100 97.0
在不使用循环应用程序的情况下获取图像中显示的值时需要帮助。 [![在此处输入图片描述][2]][2]
[![在此处输入图片描述][2]][2]
df = pd.DataFrame()
df['Par'] = [50,60,70,80,90,100]
k = df['Par'].shift(1).fillna(df['Par'][0]).astype(float)
df['Val'] = (df['Par']*0.7) + (k*0.3)
print("DataFrame: df\n",df)`
我不确定这个答案是否足够好。 首先,您的代码无法像 Excel 那样工作的原因是 Excel 使用的是累积计算,这意味着 k 值是根据公式的结果更新的df["par"] 和 k 的前一行中的值。问题本身的性质必须通过使用前一行来解决;这意味着逐行。
如何做到这一点很简单。
import pandas as pd
df = pd.DataFrame()
df['Par'] = [50,60,70,80,90,100]
df.loc[0,"Val"] = df.loc[0,"Par"] #similar to =A5 in excel
Par Val
0 50 50.0
1 60 NaN
2 70 NaN
3 80 NaN
4 90 NaN
5 100 NaN
的概念是na的值会填充上一行和同行不同的计算。但是第三、四、五行没有之前的值需要计算,所以,它们会重新用na填充。
df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
Par Val
0 50 50.0
1 60 57.0
2 70 NaN
3 80 NaN
4 90 NaN
5 100 NaN
在我们估算了 Val 的第二行之后,第三行现在有一个以前的值来估算自己。所以,我们运行再次上线。
Par Val
0 50 50.0
1 60 57.0
2 70 66.1
3 80 NaN
4 90 NaN
5 100 NaN
所以,现在第四次也是如此,然后是第五次。但是当你有超过 5 行时,一次又一次地 运行 宁这一行对你来说将是一件苦差事。所以,在这种情况下,我们会使用(是的)循环。 但是您的请求包括 without Using for loop 部分,我对此感到不知所措。可能有办法做到这一点,但对我来说,我坚持计算 -> 获取价值 -> 计算。因此,这里有几个循环,它们不使用数据帧本身的任何数据,而只是重复代码多次。
i == 0
if i < len(df):
df["Val"]=df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
++i
for i in range(len(df)):
df["Val"]=df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
++i
import itertools
for _ in itertools.repeat(None, len(df)):
df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
如果您找到了不使用循环的方法,请与我们分享。多亏了你们,我今天度过了一个非常有趣的夜晚。
递归计算不可向量化,为了提高性能使用 numba:
from numba import jit
@jit(nopython=True)
def f(a):
d = np.empty(a.shape)
d[0] = a[0]
for i in range(1, a.shape[0]):
d[i] = d[i-1] * 0.3 + a[i] * 0.7
return d
df['Val'] = f(df['Par'].to_numpy())
print (df)
Par Val
0 50 50.0000
1 60 57.0000
2 70 66.1000
3 80 75.8300
4 90 85.7490
5 100 95.7247
1k 行的性能差异:
from numba import jit
import itertools
np.random.seed(2022)
df = pd.DataFrame({'Par': np.random.randint(100, size=1000)})
In [64]: %%timeit
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...: import itertools
...:
...: df.loc[0,"Val"] = df.loc[0,"Par"]
...: for _ in itertools.repeat(None, len(df)):
...: df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
...:
1.05 s ± 193 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [65]: %%timeit
...: @jit(nopython=True)
...: def f(a):
...: d = np.empty(a.shape)
...: d[0] = a[0]
...: for i in range(1, a.shape[0]):
...: d[i] = d[i-1] * 0.3 + a[i] * 0.7
...: return d
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
121 ms ± 3.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
测试 100krows:
np.random.seed(2022)
df = pd.DataFrame({'Par': np.random.randint(100, size=100000)})
In [70]: %%timeit
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...: import itertools
...:
...: df.loc[0,"Val"] = df.loc[0,"Par"]
...: for _ in itertools.repeat(None, len(df)):
...: df["Val"] = df["Val"].fillna((df["Par"]*0.7)+(df["Val"].shift(1)*(0.3)))
...:
4min 47s ± 5.39 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [71]: %%timeit
...: @jit(nopython=True)
...: def f(a):
...: d = np.empty(a.shape)
...: d[0] = a[0]
...: for i in range(1, a.shape[0]):
...: d[i] = d[i-1] * 0.3 + a[i] * 0.7
...: return d
...:
...: df['Val1'] = f(df['Par'].to_numpy())
...:
...:
129 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)