使用 Pandas 数据框计算上一行数据的方法

3

我有由“Linear”和“Delta”组成的数据帧,并需要创建“New”列。

输入:

Linear   Delta
    30      -3  
    60     1.4
    65    -0.3
    62     4.4
    21    -2.5
    18    -0.1
    34    -3.1
    30    -1.5
    45     0.5
    55    -1.4
    43     2.8
    51     4.7
    62     2.7

输出:

Linear   Delta        New
    30      -3  
    60     1.4       60.0
    65    -0.3       59.7
    62     4.4       64.1
    21    -2.5       61.6
    18    -0.1       61.5
    34    -3.1       58.4
    30    -1.5       56.9
    45     0.5       57.4
    55    -1.4       55.0
    43     2.8       57.8
    51     4.7       51.0
    62     2.7       53.7

算法公式如下:
New[i] = IF( AND(Linear[i-1]<50,Linear[i]>50) ,  Linear ,  New[i-1]+Delta[i]  )

我尝试了很多不同的方法,比如使用 cumsum(),但从未找到解决方案。我已经花了很多小时,但都是徒劳。


你能解释一下新列是如何形成的吗? - Rahul Agarwal
这是我想要创建的,也就是输出。所需的计算已经提到了上面。 - user3203275
3个回答

2

虽然不是很好,但确实有效:

df['NEW'] = np.nan
for i, row in df.iterrows():
    if i > 0:
        m = (row['Linear'] > 50) & (df.loc[i-1, 'Linear'] < 50)
        df.loc[i, 'NEW'] = np.where(m, row['Linear'], row['Delta'] + df.loc[i-1, 'NEW'])

print (df)
    Linear  Delta   New   NEW
0       30   -3.0   NaN   NaN
1       60    1.4  60.0  60.0
2       65   -0.3  59.7  59.7
3       62    4.4  64.1  64.1
4       21   -2.5  61.6  61.6
5       18   -0.1  61.5  61.5
6       34   -3.1  58.4  58.4
7       30   -1.5  56.9  56.9
8       45    0.5  57.4  57.4
9       55   -1.4  55.0  55.0
10      43    2.8  57.8  57.8
11      51    4.7  51.0  51.0
12      62    2.7  53.7  53.7

2

对于这种递归算法,考虑使用手动循环的numba。你可能会发现即时编译比基于Pandas的方法/迭代更有效率。

from numba import jit

@jit(nopython=True)
def calc_new(L, D):
    res = np.zeros(L.shape)
    res[0] = np.nan
    for i in range(1, len(res)):
        res[i] = L[i] if (L[i-1] < 50) & (L[i] > 50) else res[i-1] + D[i]
    return res

df['New'] = calc_new(df['Linear'].values, df['Delta'].values)

结果

print(df)

    Linear  Delta   New
0       30   -3.0   NaN
1       60    1.4  60.0
2       65   -0.3  59.7
3       62    4.4  64.1
4       21   -2.5  61.6
5       18   -0.1  61.5
6       34   -3.1  58.4
7       30   -1.5  56.9
8       45    0.5  57.4
9       55   -1.4  55.0
10      43    2.8  57.8
11      51    4.7  51.0
12      62    2.7  53.7

使用循环是否更低效? - user3203275
一个循环本身并不一定更低效。很多时候,numba 比向量化的 Pandas 更快。问题在于你在什么层次上实现循环。如果你在非常基础的 C 级对象上实现循环(就像这里一样),那么没问题。但是如果你在复杂的 Pandas 对象上实现循环,由于开销更大,性能会变差。 - jpp
复杂的 pandas 对象例如什么?我有一个 (100K)X(100) 的数据集。 - user3203275
pd.Series 是复杂的。C 浮点值则不然,如果解决方案效率不够高,您应该提供更多信息(现在速度有多快?您期望什么性能?)。这与数据集的大小无关。 - jpp
性能还可以。你的方法并没有影响到我的代码性能。这个问题更加通用化。 - user3203275

0
在这个程序中,我使用了两个临时列表来完成工作。"prevLinear"列表用于获取Linear[i-1]结果的结果。"tempList"列表用于存储"new"列的结果,以便将来进行计算。 执行代码以获得结果。 如果有帮助,请告诉我。 谢谢。
import pandas as pd
import numpy as np


Linear = [30,60,65,62,21,18,34,30,45,55,43,51,62]
Delta = [-3,1.4,-0.3,4.4,-2.5,-0.1,-3.1,-1.5,0.5,-1.4,2.8,4.7,2.7]

df = pd.DataFrame({
            'Linear':Linear,
            'Delta':Delta
        })
prevLinear = [np.NaN if(i==0) else df.iloc[i-1,1] for i,value in enumerate(df['Linear'].values)]
df['prevLinear'] = prevLinear
tempList = []
new = []
for i,value in enumerate(df['Linear'].values):
    if(value>50 and df.iloc[i,2]<50):
        new.append(value)
        tempList.append(value)
    else:
        if(i>0):
            new.append(df.iloc[i,0]+tempList[i-1])
            tempList.append(df.iloc[i,0]+tempList[i-1])
        else:
            new.append(np.NaN)
            tempList.append(np.NaN)

new = np.round(new,1)
df['New'] = new
finalDF = df.iloc[:,[1,0,3]]
print(finalDF)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接