2016-07-10 5 views
3

Ich möchte einen Filter für den gesamten Datenrahmen erstellen, der viele Spalten hinter Spalte C enthält. Ich möchte, dass dieser Filter Werte zurückgibt jede Spalte nach Erreichen eines minimalen Schwellenwerts und stoppt, wenn ein maximaler Schwellenwert erreicht wurde. Ich möchte, dass der Mindestschwellenwert 6,5 und der Höchstwert 9,0 ist. Es ist nicht so einfach, wie es mit mir hier so hängen klingt ...Entfernen von Werten im Datenrahmen, sobald der Schwellenwert (min/max) mit Pandas erreicht wurde

Die Datenrahmen:

Time A1 A2 A3 
1 6.305 6.191 5.918 
2 6.507 6.991 6.203 
3 6.407 6.901 6.908 
4 6.963 7.127 7.116 
5 7.227 7.330 7.363 
6 7.445 7.632 7.575 
7 7.710 7.837 7.663 
8 8.904 8.971 8.895 
9 9.394 9.194 8.994 
10 8.803 8.113 9.333 
11 8.783 8.783 8.783 

Das gewünschte Ergebnis:

Time A1 A2 A3 
1 NaN  NaN  NaN 
2 6.507 6.991 NaN 
3 6.407 6.901 6.908 
4 6.963 7.127 7.116 
5 7.227 7.330 7.363 
6 7.445 7.632 7.575 
7 7.710 7.837 7.663 
8 8.904 8.971 8.895 
9 NaN  NaN  8.994 
10 NaN  NaN  NaN 
11 NaN  NaN  NaN 

zu Hause den Punkt, in Spalte A zu fahren, Zum Beispiel gibt es zu Zeitpunkt 3 einen Wert von 6.407, der niedriger ist als der Schwellenwert von 6.5, aber da der Schwellenwert zum Zeitpunkt 2 erfüllt war, möchte ich die Daten behalten, sobald der Mindestschwellenwert erreicht wurde. Was den oberen Schwellenwert anbelangt, in Spalte A zu Zeitpunkt 9, liegt der Wert über dem Grenzwert von 9,0. Daher möchte ich, dass dieser Wert und die Werte darüber hinaus weggelassen werden, auch wenn die verbleibenden Werte weniger als 9,0 betragen. Ich hoffe, dies über viele weitere Spalten zu iterieren.

Danke !!!

Antwort

2

Implementierung

Hier ist ein vektorisiert Ansatz NumPy boolean indexing -

# Extract values into an array 
arr = df.values 

# Determine the min,max limits along each column 
minl = (arr > 6.5).argmax(0) 
maxl = (arr>9).argmax(0) 

# Setup corresponding boolean mask and set those in array to be NaNs 
R = np.arange(arr.shape[0])[:,None] 
mask = (R < minl) | (R >= maxl) 
arr[mask] = np.nan 

# Finally convert to dataframe 
df = pd.DataFrame(arr,columns=df.columns) 

Bitte beachten Sie, dass alternativ kann man direkt in den Eingangsdatenrahmen Maske statt es neu erstellen, aber der interessante Fund ist hier, dass Boolean Indexierung in eine NumP Y-Array ist schneller als in einem Pandas-Datenrahmen. Da wir den gesamten Datenrahmen filtern, können wir den Datenrahmen neu erstellen.

Closer Look

Nun schauen sie sich die Maskenerstellung Teil genaues hinsehen, was der Kern dieser Lösung ist.

1) Eingangsanordnung:

In [148]: arr 
Out[148]: 
array([[ 6.305, 6.191, 5.918], 
     [ 6.507, 6.991, 6.203], 
     [ 6.407, 6.901, 6.908], 
     [ 6.963, 7.127, 7.116], 
     [ 7.227, 7.33 , 7.363], 
     [ 7.445, 7.632, 7.575], 
     [ 7.71 , 7.837, 7.663], 
     [ 8.904, 8.971, 8.895], 
     [ 9.394, 9.194, 8.994], 
     [ 8.803, 8.113, 9.333], 
     [ 8.783, 8.783, 8.783]]) 

2) min, max Grenzwerte:

In [149]: # Determine the min,max limits along each column 
    ...: minl = (arr > 6.5).argmax(0) 
    ...: maxl = (arr>9).argmax(0) 
    ...: 

In [150]: minl 
Out[150]: array([1, 1, 2]) 

In [151]: maxl 
Out[151]: array([8, 8, 9]) 

3) Unter Verwendung broadcasting eine Maske zu erstellen, die über den gesamten Datenrahmen/array umspannt und wählt Elemente, sind gesetzt als NaNs:

In [152]: R = np.arange(arr.shape[0])[:,None] 

In [153]: R 
Out[153]: 
array([[ 0], 
     [ 1], 
     [ 2], 
     [ 3], 
     [ 4], 
     [ 5], 
     [ 6], 
     [ 7], 
     [ 8], 
     [ 9], 
     [10]]) 

In [154]: (R < minl) | (R >= maxl) 
Out[154]: 
array([[ True, True, True], 
     [False, False, True], 
     [False, False, False], 
     [False, False, False], 
     [False, False, False], 
     [False, False, False], 
     [False, False, False], 
     [False, False, False], 
     [ True, True, False], 
     [ True, True, True], 
     [ True, True, True]], dtype=bool) 

Laufzeittest

Lassen Sie uns die bisher aufgeführten Ansätze zur Lösung des Problems Zeit nehmen und da es erwähnt wurde, dass wir viele Spalten haben würden, verwenden wir eine anständig große Anzahl von Spalten.

Ansätze als Funktionen aufgelistet:

def cumsum_app(df): # Listed in other solution by @Merlin 
    df2 = df > 6.5 
    df = df[df2.cumsum()>0] 
    df2 = df > 9 
    df = df[~(df2.cumsum()>0)] 

def boolean_indexing_app(df): # Approaches listed in this post 
    arr = df.values 
    minl = (arr > 6.5).argmax(0) 
    maxl = (arr>9).argmax(0) 
    R = np.arange(arr.shape[0])[:,None] 
    mask = (R < minl) | (R >= maxl) 
    arr[mask] = np.nan 
    df = pd.DataFrame(arr,columns=df.columns) 

Timings:

In [163]: # Create a random array with floating pt numbers between 6 and 10 
    ...: df = pd.DataFrame((np.random.rand(11,10000)*4)+6) 
    ...: 
    ...: # Create copies for testing approaches 
    ...: df1 = df.copy() 
    ...: df2 = df.copy() 


In [164]: %timeit cumsum_app(df1) 
100 loops, best of 3: 16.4 ms per loop 

In [165]: %timeit boolean_indexing_app(df2) 
100 loops, best of 3: 2.09 ms per loop 
2

Try this:

df 
     A1  A2  A3 
Time      
1  6.305 6.191 5.918 
2  6.507 6.991 6.203 
3  6.407 6.901 6.908 
4  6.963 7.127 7.116 
5  7.227 7.330 7.363 
6  7.445 7.632 7.575 
7  7.710 7.837 7.663 
8  8.904 8.971 8.895 
9  9.394 9.194 8.994 
10 8.803 8.113 9.333 
11 8.783 8.783 8.783 

df2 = df > 6.5 
df = df[df2.cumsum()>0] 
df2 = df > 9 
df = df[~(df2.cumsum()>0)] 

df 
     A1  A2  A3 
Time      
1  NaN NaN NaN 
2  6.507 6.991 NaN 
3  6.407 6.901 6.908 
4  6.963 7.127 7.116 
5  7.227 7.330 7.363 
6  7.445 7.632 7.575 
7  7.710 7.837 7.663 
8  8.904 8.971 8.895 
9  NaN NaN 8.994 
10  NaN NaN NaN 
11  NaN NaN NaN 
+0

Danke, Merlin! Ich versuche immer noch, meinen Kopf um die Einfachheit zu legen, und ich werde es tun. Ich bin ein Neuling für all das, vor allem den ~ Trick. Ich versuche immer noch, meinen Verstand dazu zu bringen, vektorisiert zu denken. Wenn Sie die Eleganz davon erklären könnten, hoffe ich, dass ich als Einziger davon profitieren werde. Danke noch einmal. – RageQuilt

Verwandte Themen