2016-07-01 10 views
3

Ich migriere einige Code aus Python-Liste primitive in eine Pandas-Implementierung. Für einige Zeitreihen möchte ich alle diskontinuierlichen Segmente mit ihrer Dauer finden. Gibt es einen sauberen Weg, dies in Pandas zu tun?Finden der Länge der maximalen Diskontinuität

Meine Datenrahmen sieht wie folgt aus:

In [23]: df 
Out[23]: 
2016-07-01 05:35:00 60.466667 
2016-07-01 05:40:00   NaN 
2016-07-01 05:45:00   NaN 
2016-07-01 05:50:00   NaN 
2016-07-01 05:55:00   NaN 
2016-07-01 06:00:00   NaN 
2016-07-01 06:05:00   NaN 
2016-07-01 06:10:00   NaN 
2016-07-01 06:15:00   NaN 
2016-07-01 06:20:00   NaN 
2016-07-01 06:25:00   NaN 
2016-07-01 06:30:00   NaN 
2016-07-01 06:35:00   NaN 
2016-07-01 06:40:00   NaN 
2016-07-01 06:45:00   NaN 
2016-07-01 06:50:00   NaN 
2016-07-01 06:55:00   NaN 
2016-07-01 07:00:00   NaN 
2016-07-01 07:05:00   NaN 
2016-07-01 07:10:00   NaN 
2016-07-01 07:15:00   NaN 
2016-07-01 07:20:00   NaN 
2016-07-01 07:25:00   NaN 
2016-07-01 07:30:00   NaN 
2016-07-01 07:35:00   NaN 
2016-07-01 07:40:00   NaN 
2016-07-01 07:45:00 63.500000 
2016-07-01 07:50:00 67.293333 
2016-07-01 07:55:00 67.633333 
2016-07-01 08:00:00 68.306667 
         ... 
2016-07-01 11:20:00   NaN 
2016-07-01 11:25:00   NaN 
2016-07-01 11:30:00 62.000000 
2016-07-01 11:35:00 69.513333 
2016-07-01 11:40:00 64.931298 
2016-07-01 11:45:00 51.980000 
2016-07-01 11:50:00 55.253333 
2016-07-01 11:55:00 51.273333 
2016-07-01 12:00:00 52.080000 
2016-07-01 12:05:00 54.580000 
2016-07-01 12:10:00 55.306667 
2016-07-01 12:15:00 55.200000 
2016-07-01 12:20:00 57.140000 
2016-07-01 12:25:00 57.020000 
2016-07-01 12:30:00 57.526667 
2016-07-01 12:35:00 57.880000 
2016-07-01 12:40:00 67.286667 
2016-07-01 12:45:00 58.153333 
2016-07-01 12:50:00 57.460000 
2016-07-01 12:55:00 54.413333 
2016-07-01 13:00:00 55.526667 
2016-07-01 13:05:00 56.120000 
2016-07-01 13:10:00 55.620000 
2016-07-01 13:15:00 56.420000 
2016-07-01 13:20:00 51.893333 
2016-07-01 13:25:00 74.451613 
2016-07-01 13:30:00 54.898551 
2016-07-01 13:35:00   NaN 
2016-07-01 13:40:00 63.355140 
2016-07-01 13:45:00 61.000000 
Freq: 5T, dtype: float64 

Wo zum Beispiel die erste diskontinuierliche Ereignis von 5.40 bis 07.40 Uhr ist.

+0

, die wie eine Serie sieht, kein Datenrahmen. – chrisaycock

Antwort

6

Dies sollte so lange funktionieren, wie Sie eine Reihe oder einen einspaltigen Datenrahmen haben.

>>>pd.Series(df.isnull().index).diff() 

, die verbessert werden können, mit einer Nutzleistung zu erhalten:

MIN_GAP_TIMEDELTA = Timedelta(minutes=30) 
discontinuities = pd.Series(df.isnull().index).diff() 
discontinuities.sort(ascending=False) 
discontinuities[discontinuities > MIN_GAP_TIMEDELTA].size 
+0

Das ist schlau. :) – ayhan

2

nicht so elegant oder kurz wie Pandas basierte Lösung (en), aber mit Leistung im Verstand, kann man NumPy verwenden aussehen Arrays und Funktionen. Also, zu lösen solchen Fall und unter der Annahme, das Datum-mal eine regelmäßige Frequenz haben, hier ist ein NumPy basierten Ansatz Diskontinuität Längen, max Längen zu erhalten und schwellenwert zählt -

# Get indices of start and stop indices of discontinuities signified by NaNs 
idx = np.where(np.diff(np.hstack(([False],np.isnan(df[0]),[False]))))[0] 

# Do differentiation on those indices which would give us the length of 
# intervals of discontinuities. These could be used in various ways. 
discontinuity_lens = np.diff(idx.reshape(-1,2),axis=1) 

# Max discontinuity length 
discontinuity_maxlen = discontinuity_lens.max() 

# Count of discontinuities that are greater than a threshold of 30 mins as 
# listed with threshold parameter : MIN_GAP_TIMEDELTA = Timedelta(minutes=30) 
# (in terms of steps that would be 6 because freq of input dataframe is 5 mins) 
thresholded_count = (discontinuity_lens>=6).sum() 

Bitte beachten Sie diese weitgehend auf eine andere NumPy solution to : Longest run/island of a number in Python.

Runtime Test

ich würde @ilmarinen's pandas based solution und der NumPy basierte Ansatz gepostet früher in diesem Beitrag nicht auf einem ausreichend großen Datenrahmen gefüllt mit zufälligen Elementen wird Timing und platziert zufällig 50% NaNs.

Funktionsdefinitionen:

def thresholdedcount_pandas(df): 
    MIN_GAP_TIMEDELTA = pd.Timedelta(minutes=30) 
    discontinuities = df.dropna().reset_index()['index'].diff() 
    return (discontinuities > MIN_GAP_TIMEDELTA).sum() 

def thresholdedcount_numpy(df): 
    idx = np.where(np.diff(np.hstack(([False],np.isnan(df[0]),[False]))))[0] 
    nan_interval_lens = np.diff(idx.reshape(-1,2),axis=1) 
    return (nan_interval_lens>=6).sum() 

Timings:

In [325]: # Random dataframe with 5 min interval data and filled with 50% NaNs 
    ...: rng = pd.date_range('1/1/2011', periods=10000, freq='5Min') 
    ...: df = pd.DataFrame(np.random.randn(len(rng)), index=rng) 
    ...: df[0][np.random.randint(0,df.shape[0],(int(df.shape[0]/2)))] = np.nan 
    ...: 

In [326]: np.allclose(thresholdedcount_pandas(df),thresholdedcount_numpy(df)) 
Out[326]: True 

In [327]: %timeit thresholdedcount_pandas(df) 
100 loops, best of 3: 3 ms per loop 

In [328]: %timeit thresholdedcount_numpy(df) 
1000 loops, best of 3: 318 µs per loop 
+0

Wird in diese Lösung schauen. Im Moment gehe ich eher mit einer einfacheren Lösung, da Leistung für diese nicht ein großes Problem ist, da es hauptsächlich auf Hintergrundjobs ist. – leonsas

Verwandte Themen