简体   繁体   English

如何在引用之前的行时遍历pandas数据框?

[英]How to iterate over a pandas dataframe while referencing previous rows?

I am iterating over a Python dataframe and finding it to be extremely slow. 我正在遍历一个Python数据框,发现它非常慢。 I understand that in Pandas you try to vectorize everything, but in this case I specifically need to iterate (or if it is possible to vectorize, I'm unclear how to do it). 我了解在Pandas中您尝试对所有内容进行矢量化,但是在这种情况下,我特别需要进行迭代(或者如果可以进行矢量化,则不清楚如何执行此操作)。

The logic is simple: you have two columns "A" and "B" and a result column "signal." 逻辑很简单:您有两个列“ A”和“ B”,以及一个结果列“ signal”。 If A equals 1, then you set signal to 1. If B equals 1, then you set signal to 0. Otherwise, signals is whatever it was previously. 如果A等于1,则将signal设置为1。如果B等于1,则将signal设置为0。否则,signals与以前相同。 In other words, column A is an "on" signal, column B is an "off" signal, and "signal" represents the state. 换句话说,列A是“开”信号,列B是“关”信号,并且“信号”表示状态。

Here is my code: 这是我的代码:

def signals(indata):
    numrows = len(indata)
    data = pd.DataFrame(index= range(0,numrows))
    data['A'] = indata['A']
    data['B'] = indata['B']
    data['signal'] = 0


    for i in range(1,numrows):
        if data['A'].iloc[i] == 1:
            data['signal'].iloc[i] = 1
        elif data['B'].iloc[i] == 1:
            data['signal'].iloc[i] = 0
        else:
            data['signal'].iloc[i] = data['signal'].iloc[i-1]
    return data

Example input/output: 输入/输出示例:

indata = pd.DataFrame(index = range(0,10))
indata['A'] = [0, 1, 0, 0, 0, 0, 1, 0, 0, 0]
indata['B'] = [1, 0, 0, 0, 1, 0, 0, 0, 1, 1]

signals(indata)

Output: 输出:

    A   B   signal
0   0   1   0
1   1   0   1
2   0   0   1
3   0   0   1
4   0   1   0
5   0   0   0
6   1   0   1
7   0   0   1
8   0   1   0
9   0   1   0

This simple logic takes my computer 46 seconds to run on a dataframe of 2000 rows with randomly generated data. 这种简单的逻辑使我的计算机需要46秒才能在具有随机生成的数据的2000行数据帧上运行。

df['signal'] = df.A.groupby((df.A != df.B).cumsum()).transform('head', 1)

df
   A  B  signal
0  0  1       0
1  1  0       1
2  0  0       1
3  0  0       1
4  0  1       0
5  0  0       0
6  1  0       1
7  0  0       1
8  0  1       0
9  0  1       0

The logic here involves dividing your series into groups based on the inequality between A and B , and every group's value is determined by A . 这里的逻辑涉及根据AB之间的不等式将序列划分为组,每个组的值由A决定。

You dont need to iterate at all you can do some Boolean indexing 您完全不需要迭代就可以执行一些布尔索引

#set condition for A
indata.loc[indata.A == 1,'signal'] = 1
#set condition for B
indata.loc[indata.B == 1,'signal'] = 0
#forward fill NaN values
indata.signal.fillna(method='ffill',inplace=True)

The simplest answer to my problem was to not write to the dataframe while iterating through it. 解决我的问题的最简单答案是在遍历数据帧时不写入数据帧。 I created an array of zeros in numpy, then did my iterative logic in the array. 我在numpy中创建了一个零数组,然后在该数组中执行了迭代逻辑。 Then I wrote the array to the column in my dataframe. 然后,将数组写入数据框的列中。

def signals3(indata):
    numrows = len(indata)
    data = pd.DataFrame(index= range(0,numrows))

    data['A'] = indata['A'] 
    data['B'] = indata['B']
    out_signal = np.zeros(numrows)

    for i in range(1,numrows):
        if data['A'].iloc[i] == 1:
            out_signal[i] = 1
        elif data['B'].iloc[i] == 1:
            out_signal[i] = 0
        else:
            out_signal[i] = out_signal[i-1]


    data['signal'] = out_signal

    return data

On a dataframe of 2000 rows of random data, this takes only 43 milliseconds as opposed to 46 seconds (~1,000x faster). 在2000行随机数据的数据帧上,这只需要43毫秒,而不是46秒(快1000倍)。

I also tried a variant where I assigned the dataframe columns A and B to series, and then iterated through the series. 我还尝试了一个变体,在该变体中,我将数据帧的A列和B列分配给了系列,然后遍历该系列。 This was a bit faster (27 milliseconds). 这有点快(27毫秒)。 But it appears most of the slowness is in writing to a dataframe. 但是看来,大多数的慢是写数据帧。

Both coldspeed and djk's answers were faster than my solution (about 4.5ms) but in practice I'll probably just iterate through series even though that is not optimal. Coldspeed和djk的答案都比我的解决方案快(约4.5毫秒),但实际上,即使不是最佳选择,我也可能会迭代整个序列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM