2016-06-21 36 views
11

ho un df in questo modo:Identificazione occorrenze consecutive di un valore di

Count 
1 
0 
1 
1 
0 
0 
1 
1 
1 
0 

e voglio restituire un 1 in una nuova colonna se ci sono due o più occorrenze consecutive di 1 in Count e 0 se non c'è. Quindi nella nuova colonna ogni riga otterrebbe un valore 1 in base a questi criteri soddisfatti nella colonna Count. La mia uscita desiderata sarebbe allora:

Count New_Value 
1  0 
0  0 
1  1 
1  1 
0  0 
0  0 
1  1 
1  1 
1  1 
0  0 

Sto pensando che potrebbe essere necessario utilizzare itertools ma ho letto su di esso e non sono imbattuto in quello che mi serve ancora. Mi piacerebbe essere in grado di utilizzare questo metodo per contare un numero qualsiasi di occorrenze consecutive, non solo 2. Ad esempio, a volte ho bisogno di contare 10 occorrenze consecutive, io uso solo 2 nell'esempio qui.

+0

Controllare se 'df ['Count'] [1] == df ['Count'] [1] .shift (1)', e in tal caso, '1', altrimenti' 0'. Quindi dovresti '.append()' questi valori (0 o 1) a un 'array'. Quindi imposta il primo elemento ('array [0]') su '0' (predefinito). Quindi devi capire come unire/unire/tappare/concatenare' il tuo 'array' nel tuo' dataframe'. 100% non testato, ma penso che questo possa funzionare ... :) –

+0

Forse avrei semplificato la mia domanda troppo, e se volessi 3 occorrenze consecutive? Non penso che funzioni allora –

risposta

10

Si potrebbe:

df['consecutive'] = df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count 

di ottenere:

Count consecutive 
0  1   1 
1  0   0 
2  1   2 
3  1   2 
4  0   0 
5  0   0 
6  1   3 
7  1   3 
8  1   3 
9  0   0 

Da qui è possibile , per qualsiasi soglia:

threshold = 2 
df['consecutive'] = (df.consecutive > threshold).astype(int) 

per ottenere:

Count consecutive 
0  1   0 
1  0   0 
2  1   1 
3  1   1 
4  0   0 
5  0   0 
6  1   1 
7  1   1 
8  1   1 
9  0   0 

o, in un unico stadio:

(df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count >= threshold).astype(int) 

In termini di efficienza, utilizzando pandas metodi fornisce un aumento di velocità significativo quando la dimensione del problema cresce:

df = pd.concat([df for _ in range(1000)]) 

%timeit (df.Count.groupby((df.Count != df.Count.shift()).cumsum()).transform('size') * df.Count >= threshold).astype(int) 
1000 loops, best of 3: 1.47 ms per loop 

rispetto a:

%%timeit 
l = [] 
for k, g in groupby(df.Count): 
    size = sum(1 for _ in g) 
    if k == 1 and size >= 2: 
     l = l + [1]*size 
    else: 
     l = l + [0]*size  
pd.Series(l) 

10 loops, best of 3: 76.7 ms per loop 
+0

Ecco un one-liner: 'df.assign (consecutive = df.Count.groupby ((df.Count! = Df.Count.shift()). Cumsum()). Transform ('size')). query ('consecutive> @threshold') 'che funzionerà per qualsiasi valore consecutivo (non solo uno e zero) – MaxU

1

Non so se questo è ottimizzato, ma si può fare un tentativo:

from itertools import groupby 
import pandas as pd 

l = [] 
for k, g in groupby(df.Count): 
    size = sum(1 for _ in g) 
    if k == 1 and size >= 2: 
     l = l + [1]*size 
    else: 
     l = l + [0]*size 

df['new_Value'] = pd.Series(l) 

df 

Count new_Value 
0 1 0 
1 0 0 
2 1 1 
3 1 1 
4 0 0 
5 0 0 
6 1 1 
7 1 1 
8 1 1 
9 0 0