Python 是否有方法将先前计算的行值与数据帧中不同列的总和一起使用?

Python 是否有方法将先前计算的行值与数据帧中不同列的总和一起使用?,python,pandas,dataframe,Python,Pandas,Dataframe,我有以下数据帧: A B 2021-05-19 07:00:00 Nan Nan 2021-05-19 07:30:00 0.00 Nan 2021-05-19 08:00:00 0.00 Nan 2021-05-19 08:30:00 0.00 Nan 2021-05-19 09:00:00 19.91 Nan 2021-05-19 09:30:00 0.11

我有以下数据帧:

                     A          B
2021-05-19 07:00:00  Nan        Nan
2021-05-19 07:30:00  0.00       Nan
2021-05-19 08:00:00  0.00       Nan
2021-05-19 08:30:00  0.00       Nan
2021-05-19 09:00:00  19.91      Nan
2021-05-19 09:30:00  0.11       Nan
2021-05-19 10:00:00  0.00       Nan
2021-05-19 10:30:00  22.99      Nan
2021-05-19 11:00:00  0.00       Nan
要求:

                     A          B
2021-05-19 07:00:00  Nan        0.00
2021-05-19 07:30:00  0.00       0.00
2021-05-19 08:00:00  0.00       0.00
2021-05-19 08:30:00  0.00       0.00
2021-05-19 09:00:00  19.91      3.32
2021-05-19 09:30:00  0.11       2.78
2021-05-19 10:00:00  0.00       2.32
2021-05-19 10:30:00  22.99      5.76
2021-05-19 11:00:00  0.00       4.80
B列的计算:

B1 = A1
B2 = ((B1*5)+A2)/6
B3 = ((B2*5)+A3)/6
B4 = ((B3*5)+A4)/6
etc.

我已经尝试用Python使用shift函数进行计算,但这不起作用,如果有人能帮我找到正确的方向,那就太好了。

如果你想表达这个函数

B[i] = (A[i-1] * 5 + A[i])/6
B[i] = (B[i-1] * 5 + A[i])/6
你的轮班安排是对的

B=((A.shift(1)*5)+A)/6
B.iat[0]=A.iat[0]
但是,如果要表示递归函数

B[i] = (A[i-1] * 5 + A[i])/6
B[i] = (B[i-1] * 5 + A[i])/6

然后,正如另一个答案所指出的那样,您不能使用矢量化的pandas操作,只能使用普通的Python代码进行计算。

您可以在数据帧中循环并设置列
B
,因为
B
的每个值都取决于它自己以前的值

for i, date in enumerate(df.index):
    if i==0:
        df.at[date, "B"] = 0
    else:
        df.at[date, "B"] = (df["B"].iat[i-1]*5+df.at[date, "A"])/6
df
>>
                         A         B
2021-05-19 07:00:00   0.00  0.000000
2021-05-19 07:30:00   0.00  0.000000
2021-05-19 08:00:00   0.00  0.000000
2021-05-19 08:30:00   0.00  0.000000
2021-05-19 09:00:00  19.91  3.318333
2021-05-19 09:30:00   0.11  2.783611
2021-05-19 10:00:00   0.00  2.319676
2021-05-19 10:30:00  22.99  5.764730
2021-05-19 11:00:00   0.00  4.803942

通过一些数学运算,我们可以将此递归公式转化为几何级数,如:

df["B"] = (df.A
             .fillna(0)
             .expanding()
             .apply(lambda s: (1/6)*(s * ((5/6) ** np.arange(len(s))[::-1])).sum() + (5/6)**s.size*s.iloc[0]))
这相当于

N := window.size

B_j = (5/6)^(N-1) A_1 + (1/6) \sum_{j=2}^{N} (5/6)^(N-j) A_j
其中,窗口是并对应于代码中的
s
。然而,在代码中,我们将
A_1
与其他代码相加,从而取
1/6
;因此,我们将剩余的
5/6
添加到它前面,因此在它前面添加
(5/6)^N
(而不是
N-1
);产量相当。我们还将
A
中的
NaN
s设置为0,以防止它们传播

得到

                         A         B
2021-05-19 07:00:00    NaN  0.000000
2021-05-19 07:30:00   0.00  0.000000
2021-05-19 08:00:00   0.00  0.000000
2021-05-19 08:30:00   0.00  0.000000
2021-05-19 09:00:00  19.91  3.318333
2021-05-19 09:30:00   0.11  2.783611
2021-05-19 10:00:00   0.00  2.319676
2021-05-19 10:30:00  22.99  5.764730
2021-05-19 11:00:00   0.00  4.803942

我们可以定义一个函数
fast\u sum
来执行所需的计算,然后使用称为即时编译的技术,将此函数编译为机器代码,以便它能够以
C
类似的速度更高效地运行

import numba

@numba.jit(nopython=True)
def fast_sum(a):
    b = np.zeros_like(a)
    b[0] = a[0]
    for i in range(1, len(a)):
        b[i] = (b[i - 1] * 5 + a[i]) / 6 
    return b

df['B'] = fast_sum(df['A'].fillna(0).to_numpy())

90000行的样本数据帧进行性能测试

df = pd.concat([df] * 10000, ignore_index=True)

%%timeit
df['B'] = fast_sum(df['A'].fillna(0).to_numpy())
# 1.62 ms ± 93.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

移位是否应该是A.shift(-1)
。B2是B1和A2的函数,而不是A1和A2。否,
shift(1)
将所有值向前移位。因此
A.shift(1)
的第一个元素是
nan
,第二个元素是
A[0]
,但是检查他写的计算,它看起来应该是向后移动的。这没有像预期的那样起作用,只是尝试了一下:
df[“B”]=((df[“B”].shift(1)*5)+df[“A”)/6
。B2应该在计算中取上一个B1值。显然,循环需要时间,效率不高。是的,但列的每个值都取决于它自己的上一个值,因此我看不到实现
shift
的方法。请随意提供更有效的答案。这给了我以下错误:
文件“pandas\\ libs\index.pyx”,第96行,在pandas中。\ libs.index.IndexEngine.set\值文件“pandas\\ libs\index.pyx”,第107行,在pandas中。\ libs.index.IndexEngine.set\值文件“pandas\\ libs\index.pyx”,第595行,在pandas._libs.index.convert_scalar ValueError:无法将nan分配给整数系列
您可以检查
df.dtypes的输出吗
?或者在我的代码前面加上一行
df=df.astype('float64')
。即使我也找不到比循环更好的方法。无法使用shift和cumsum:/解决此问题。我觉得这没问题。你不能真正使用
shift
,因为下一个值取决于上一个值的计算等等。那么这就是问题的结束;)@AnuragDhadse你什么意思
:)
?@Tenzin接受这个答案,如果它有效的话,否则我们又花了宝贵生命的一个小时df[“B”]=(df.A.expansing().apply(lambda s:(s*((5/6)**np arange(len(s))[:-1])。sum()/6+(5/6)**s.size*s.iloc[0])给出:name错误:name'np不是defined@Tenzin对在你分享的问题的第一个版本中,没有
NaN
,但我知道它被添加了。要解决这个问题,您可以在
NaN
s中预先填入0:
df.A=df.A.fillna(0)
,然后填入上面的代码。