В pandas или numpy мы можем установить флаг на строке, чтобы сделать векторизацию, и использовать его для вычисления следующей строки - PullRequest
1 голос
/ 13 апреля 2019

Я новичок в python, но некоторое время был в мире программирования. Я уже пытался сделать следующее с помощью цикла if else, используя кадры данных Python и iloc, и это было успешно. Я хочу использовать векторизацию. Проблема заключается в том, что, как только данные изменяют свое состояние на основании правила 1 (b , я хочу, чтобы они оставались в этом состоянии до тех пор, пока действует правило 2 (c ,

Таким образом, вход и выход будут выглядеть следующим образом:

TABLE

Я пробовал numpy select и numpy где при сдвиге, но сравнение происходит по одному столбцу, поэтому я не смог заставить его работать. Это работает в первый раз, когда правило 2 применяется не после этого. поскольку выше приведен пример проблемы, которую я создал из той, что у меня есть, так что код трудно предоставить

Флаг - это то, что я ожидаю, но я не понимаю

df с циклами, а df1 с numpy - я не могу заставить его выглядеть одинаково

import pandas as pd
import numpy as np


df = pd.DataFrame({"a": [20,25,30,32,25,26,30,24,25,30,30,35,20,22,25,28,29,31,25,21], "b": [26,28,26,35,34,34,31,26,28,29,31,32,18,24,30,35,32,35,36,30], "c":[18,19,20,22,23,24,34,22,23,31,32,38,22,21,22,21,18,22,28,31]})

df1 = df

position=''
Flag = False
df =  df.assign(flag=Flag) 

for id1, id2 in zip(df.iterrows(), df.iloc[1:].iterrows()):

   if id1[1]['b'] < id1[1]['a'] :
        Flag=True
        position='rule1True' 
   elif ( id1[1]['c'] <  id1[1]['a'] and (position =='rule1True' or position == 'rule2True') ):
        Flag = True
        position = 'rule2True'
   else :
        Flag = False
        position = ''
   df.at[id1[0],'flag'] = Flag


print(df)

df1['rule1'] = np.select([df1['b'] < df1['a']],[True], default= False)
df1['rule2'] = np.select([( df1['rule1'].shift(1) & (df1['c'] < df1['a']))],[True], default= False)
df1['flag'] = np.select([( df1['rule1'] | df1['rule2'])],[True], default= False)

print(df1)

1 Ответ

0 голосов
/ 13 апреля 2019

Мое решение для цикла было очень медленным.Здесь это правильное векторное решение, это работает.Очень быстро.

mask1 = df['b'] < df['a']
mask2 = df['c'] < df['a']
mask3 = (mask1 == False) & (mask2 == False)

Этот флаг True / False изменяется при смене mask1 mask3.

df.loc[mask1,'flag'] = True

df.loc[mask3,'flag'] = False

Используйте прямую заливку для заполнения NaN.

df['flag'].ffill(inplace=True)

Первые несколько строк могут быть Нэн, они будут ложными.Заполните их False

df['flag'] = df['flag'].fillna(False)

Протестировано на миллион строк:

CPU times: user 917 ms, sys: 7.99 ms, total: 925 ms

Пример вывода:

     a   b   c   flag
0   22  21  37   True
1   21  31  30  False
2   25  23  32   True
3   34  36  22   True
4   31  36  30   True
5   20  32  36  False
6   25  24  24   True
7   24  20  29   True
8   36  36  22   True
9   36  24  25   True
10  22  24  20   True
11  22  24  27  False
12  31  37  26  False
13  37  24  22   True
14  28  22  26   True
15  27  27  32  False
16  26  32  36  False
17  32  37  30  False
18  28  37  36  False
19  37  22  24   True

Полный код:

df = pd.DataFrame(np.random.randint(20, 38, [1000000,3]), columns=['a', 'b', 'c'])

mask1 = df['b'] < df['a']
mask2 = df['c'] < df['a']
mask3 = (mask1 == False) & (mask2 == False)

df.loc[mask1,'flag'] = True

df.loc[mask3,'flag'] = False

df['flag'].ffill(inplace=True)

df['flag'] = df['flag'].fillna(False)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...