2017-02-05 69 views
5

Chciałbym napisać następujący kod w wektoryzacji, ponieważ obecny kod jest dość powolny (i chciałbym się nauczyć najlepszych praktyk Pythona). Zasadniczo kod mówi, że jeśli dzisiejsza wartość jest w granicach 10% wczorajszej wartości, to dzisiejsza wartość (w nowej kolumnie) jest taka sama jak wczorajsza wartość. W przeciwnym razie, dzisiejsza wartość jest niezmienna:Jak napisać kod w wektoryzacji zamiast używać pętli?

def test(df): 
    df['OldCol']=(100,115,101,100,99,70,72,75,78,80,110) 
    df['NewCol']=df['OldCol'] 
    for i in range(1,len(df)-1): 
     if df['OldCol'][i]/df['OldCol'][i-1]>0.9 and df['OldCol'][i]/df['OldCol'][i-1]<1.1: 
      df['NewCol'][i]=df['NewCol'][i-1] 
     else: 
      df['NewCol'][i]=df['OldCol'][i] 
    return df['NewCol'] 

Wyjście powinno być następujące:

OldCol NewCol 
0  100  100 
1  115  115 
2  101  101 
3  100  101 
4  99  101 
5  70  70 
6  72  70 
7  75  70 
8  78  70 
9  80  70 
10  110  110 

Czy możesz pomóc?

chciałbym użyć czegoś takiego, ale nie udało się rozwiązać mój problem:

def test(df): 
    df['NewCol']=df['OldCol'] 
    cond=np.where((df['OldCol'].shift(1)/df['OldCol']>0.9) & (df['OldCol'].shift(1)/df['OldCol']<1.1)) 
    df['NewCol'][cond[0]]=df['NewCol'][cond[0]-1]  
    return df  
+1

'df' jest ramka danych, prawda? Co to jest 'dtype' z' df ['OldCol'] 'lub' NewCol '? Myślę, że jest to raczej dobry kod pandowy niż Pythoniczny. – hpaulj

+0

Jaki jest pożądany wynik dla '' 'OldCol = (100,115,101,1009,9,70,72,75,78,80,81,82,110)' ''? – wwii

Odpowiedz

0

Należy Boolean maskować swój pierwotny dataframe:

df[(0.9 <= df['NewCol']/df['OldCol']) & (df['NewCol']/df['OldCol'] <= 1.1)] daje wszystkie wiersze gdzie NewCol jest w granicach 10% OldCol

Tak, aby ustawić pole NewCol w tych wierszach:

within_10 = df[(0.9 <= df['NewCol']/df['OldCol']) & (df['NewCol']/df['OldCol'] <= 1.1)] 
within_10['NewCol'] = within_10['OldCol'] 
0

Ponieważ wydajesz się być w dobrej drodze do znalezienia dni "skoku", pokażę tylko nieco trudniejsze. Załóżmy więc, że masz tablicę numpy z old o długości N i tablicę numerek boolowskich jump o tym samym rozmiarze. Zgodnie z konwencją, zerowy element jump jest ustawiony na True. Następnie można najpierw obliczyć liczbę powtórzeń między skokami:

jump_indices = np.where(jumps)[0] 
repeats = np.diff(np.r_[jump_indices, [N]]) 

Po tych można użyć np.repeat:

new = np.repeat(old[jump_indices], repeats) 
2

rozwiązanie w trzech etapach:

df['variation']=(df.OldCol/df.OldCol.shift()) 
df['gap']=~df.variation.between(0.9,1.1) 
df['NewCol']=df.OldCol.where(df.gap).fillna(method='ffill') 

Za:

OldCol variation gap NewCol 
0  100  nan True  100 
1  115  1.15 True  115 
2  101  0.88 True  101 
3  100  0.99 False  101 
4  99  0.99 False  101 
5  70  0.71 True  70 
6  72  1.03 False  70 
7  75  1.04 False  70 
8  78  1.04 False  70 
9  80  1.03 False  70 
10  110  1.38 True  110 

Wydaje się być 30 razy szybszy niż pętle na tym przykładzie.

W jednym wierszu:

x=df.OldCol;df['NewCol']=x.where(~(x/x.shift()).between(0.9,1.1)).fillna(method='ffill') 
+0

To jest dokładnie to, czego potrzebuję - wielkie dzięki – crazyfrog