2013-04-23 12 views
32

Sono in grado di leggere e tagliare panda dati frame utilizzando oggetti datetime python, tuttavia sono obbligato a utilizzare solo date esistenti nell'indice. Ad esempio, questo funziona:python pandas dataframe slicing per condizioni di data

>>> data 
<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 252 entries, 2010-12-31 00:00:00 to 2010-04-01 00:00:00 
Data columns: 
Adj Close 252 non-null values 
dtypes: float64(1) 

>>> st = datetime.datetime(2010, 12, 31, 0, 0) 
>>> en = datetime.datetime(2010, 12, 28, 0, 0) 

>>> data[st:en] 
      Adj Close 
Date     
2010-12-31  593.97 
2010-12-30  598.86 
2010-12-29  601.00 
2010-12-28  598.92 

Tuttavia, se io uso una data di inizio o di fine che non è presente nel DF, ottengo pitone KeyError.

La mia domanda: Come faccio a interrogare l'oggetto dataframe per un intervallo di date; anche quando le date di inizio e fine non sono presenti in DataFrame. I panda consentono l'affettamento basato sulla gamma?

Sto usando i panda versione 0.10.1

risposta

39

Usa searchsorted per trovare i tempi più vicini, e poi usarlo per tagliare.

In [15]: df = pd.DataFrame([1, 2, 3], index=[dt.datetime(2013, 1, 1), dt.datetime(2013, 1, 3), dt.datetime(2013, 1, 5)]) 

In [16]: df 
Out[16]: 
      0 
2013-01-01 1 
2013-01-03 2 
2013-01-05 3 

In [22]: start = df.index.searchsorted(dt.datetime(2013, 1, 2)) 

In [23]: end = df.index.searchsorted(dt.datetime(2013, 1, 4)) 

In [24]: df.ix[start:end] 
Out[24]: 
      0 
2013-01-03 2 
+0

Se si copia incolla l'esempio, funziona correttamente. Ma le variabili di inizio e fine nel mio programma, sempre predefinite per la lunghezza del dataframe! Che cosa sto facendo di sbagliato? - http://pastebin.com/raw.php?i=hfpHqF7s –

+0

Sembra che dovresti ordinare il tuo 'DataFrame' in ordine crescente. – waitingkuo

+0

Grazie, ha funzionato quando i dati sono stati ordinati in ordine crescente. –

23

Risposta breve: ordinare i dati (data.sort()) e quindi penso che tutto funzionerà il modo in cui vi aspettate.

Sì, è possibile eseguire il taglio utilizzando i datetimes non presenti in DataFrame. Ad esempio:

In [12]: df 
Out[12]: 
        0 
2013-04-20 1.120024 
2013-04-21 -0.721101 
2013-04-22 0.379392 
2013-04-23 0.924535 
2013-04-24 0.531902 
2013-04-25 -0.957936 

In [13]: df['20130419':'20130422'] 
Out[13]: 
        0 
2013-04-20 1.120024 
2013-04-21 -0.721101 
2013-04-22 0.379392 

Come si può vedere, non è nemmeno necessario creare oggetti datetime; le stringhe funzionano

Poiché i tempi di trasmissione nell'indice non sono sequenziali, il comportamento è strano. Se mischiare l'indice del mio esempio qui ...

In [17]: df 
Out[17]: 
        0 
2013-04-22 1.120024 
2013-04-20 -0.721101 
2013-04-24 0.379392 
2013-04-23 0.924535 
2013-04-21 0.531902 
2013-04-25 -0.957936 

... e prendiamo la stessa fetta, otteniamo un risultato diverso. Restituisce il primo elemento all'interno dell'intervallo e si ferma sul primo elemento all'esterno dell'intervallo.

In [18]: df['20130419':'20130422'] 
Out[18]: 
        0 
2013-04-22 1.120024 
2013-04-20 -0.721101 
2013-04-24 0.379392 

Questo comportamento probabilmente non è utile. Se si desidera selezionare intervalli di date, avrebbe senso prima ordinarlo per data?

df.sort_index() 
+0

Quando provo a farlo, ottengo un'eccezione python: TimeSeriesError: l'indicizzazione parziale è valida solo per le serie temporali ordinate. –

+0

L'eccezione era auto-esplicativa: non ero riuscito a ordinare i dati ,(: - Grazie, l'affettamento basato sul testo come hai mostrato sopra funziona come previsto, ma ho usato la funzione di ricerca in quanto le date nel programma erano già oggetti datetime –

+2

df ['20130419': '20130422'] è eccezionale! Funziona anche con dati sparsi (esspecificando una data che non esiste nell'indice). Grazie! – fantabolous

4

È possibile utilizzare una semplice maschera per raggiungere questo obiettivo:

date_mask = (data.index > start) & (data.index < end) 
dates = data.index[date_mask] 
data.ix[dates] 

A proposito, questo funziona per l'indicizzazione gerarchica pure. In tal caso, data.index verrà sostituito con data.index.levels[0] o simile.

+0

Questa risposta ha bisogno di più upvotes. L'ho cercato per settimane! –