2013-10-11 13 views
48

I miei dati possono avere più eventi in una determinata data o NO eventi in una data. Prendo questi eventi, ottengo un conteggio per data e li ordino. Tuttavia, quando li diagramma, le mie due serie non sempre corrispondono.Aggiungere date mancanti a dataframe panda

idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max()) 
s = df.groupby(['simpleDate']).size() 

Nel codice di cui sopra IDX diventa una serie di dire 30 date. 09-01-2013 a 09-30-2013 Tuttavia S può avere solo 25 o 26 giorni perché non si sono verificati eventi per una determinata data. Allora ottengo un AssertionError come le dimensioni dont partita quando provo a tracciare:

fig, ax = plt.subplots()  
ax.bar(idx.to_pydatetime(), s, color='green') 

Qual è il modo corretto per affrontare questo? Voglio rimuovere le date senza valori da IDX o (che preferirei fare) è aggiungere alla serie la data mancante con un conteggio di 0. Preferirei avere un grafico completo di 30 giorni con valori 0 . Se questo approccio è corretto, qualche suggerimento su come iniziare? Ho bisogno di una sorta di funzione dinamica reindex?

Ecco un frammento di S (df.groupby(['simpleDate']).size()), notare nessuna voce per il 04 e 05.

09-02-2013  2 
09-03-2013 10 
09-06-2013  5 
09-07-2013  1 

risposta

115

si potrebbe usare Series.reindex:

import pandas as pd 

idx = pd.date_range('09-01-2013', '09-30-2013') 

s = pd.Series({'09-02-2013': 2, 
       '09-03-2013': 10, 
       '09-06-2013': 5, 
       '09-07-2013': 1}) 
s.index = pd.DatetimeIndex(s.index) 

s = s.reindex(idx, fill_value=0) 
print(s) 

rendimenti

2013-09-01  0 
2013-09-02  2 
2013-09-03 10 
2013-09-04  0 
2013-09-05  0 
2013-09-06  5 
2013-09-07  1 
2013-09-08  0 
... 
+2

wow grazie! Non stavo capendo completamente come funziona bene la reindicizzazione. – KHibma

+12

'reindex' è una funzione incredibile. Può (1) riordinare i dati esistenti per abbinarli a una nuova serie di etichette, (2) inserire nuove righe in cui non esisteva un'etichetta, (3) riempire i dati per le etichette mancanti, (incluso il riempimento avanti/indietro) (4) selezionare le righe per etichetta! – unutbu

+0

@unutbu Questo risponde a parte di una domanda che ho avuto anch'io, grazie! Ma ti stavi chiedendo se sapessi come creare dinamicamente un elenco di date con eventi? –

2

Ecco un buon metodo per inserire date mancanti in un dataframe, con la vostra scelta di fill_value, days_back da compilare, e l'ordine (date_order) utilizzato per ordinare la dataframe ordinare:

def fill_in_missing_dates(df, date_col_name = 'date',date_order = 'asc', fill_value = 0, days_back = 30): 

    df.set_index(date_col_name,drop=True,inplace=True) 
    df.index = pd.DatetimeIndex(df.index) 
    d = datetime.now().date() 
    d2 = d - timedelta(days = days_back) 
    idx = pd.date_range(d2, d, freq = "D") 
    df = df.reindex(idx,fill_value=fill_value) 
    df[date_col_name] = pd.DatetimeIndex(df.index) 

    return df 
11

Un problema è che reindex fallirà se non ci sono valori duplicati. Diciamo che stiamo lavorando con i dati timestamp, che vogliamo indice per data:

df = pd.DataFrame({ 
    'timestamps': pd.to_datetime(
     ['2016-11-15 1:00','2016-11-16 2:00','2016-11-16 3:00','2016-11-18 4:00']), 
    'values':['a','b','c','d']}) 
df.index = pd.DatetimeIndex(df['timestamps']).floor('D') 
df 

cede

  timestamps    values 
2016-11-15 "2016-11-15 01:00:00" a 
2016-11-16 "2016-11-16 02:00:00" b 
2016-11-16 "2016-11-16 03:00:00" c 
2016-11-18 "2016-11-18 04:00:00" d 

A causa della 2016-11-16 data di duplicato, un tentativo di reindicizzare:

all_days = pd.date_range(df.index.min(), df.index.max(), freq='D') 
df.reindex(all_days) 

fallisce con:

... 
ValueError: cannot reindex from a duplicate axis 

(da questo significa l'indice ha i duplicati, non che è di per sé un DUP)

Invece, possiamo usare .loc per cercare le voci per tutte le date nella gamma:

df.loc[all_days] 

rendimenti

  timestamps    values 
2016-11-15 "2016-11-15 01:00:00" a 
2016-11-16 "2016-11-16 02:00:00" b 
2016-11-16 "2016-11-16 03:00:00" c 
2016-11-17 NaN     NaN 
2016-11-18 "2016-11-18 04:00:00" d 

fillna può essere utilizzato sulla serie di colonne per riempire spazi vuoti, se necessario.

6

Una soluzione più rapida è utilizzare asfreq(). Questa creazione non richiede di un nuovo indice per chiamare all'interno reindex(). *

dates = pd.Index([pd.Timestamp('2012-05-01'), 
        pd.Timestamp('2012-05-04'), 
        pd.Timestamp('2012-05-06')]) 
s = pd.Series([1, 2, 3], dates) 

print(s.asfreq('D')) 
2012-05-01 1.0 
2012-05-02 NaN 
2012-05-03 NaN 
2012-05-04 2.0 
2012-05-05 NaN 
2012-05-06 3.0 
Freq: D, dtype: float64 

* Almeno non da parte dell'utente. Quello molto bene potrebbe essere chiamato sotto il cofano.

2

In molti casi, resample(see documentation here) offre una soluzione generale in grado di gestire le date mancanti e duplicate. Per esempio:

df.resample('D').mean() 

resample è un'operazione differita come groupby quindi è necessario seguire con un'altra operazione. In questo caso mean funziona bene, ma è anche possibile utilizzare molti metodo standard di panda lì come max, sum, ecc

Ecco i dati originali, ma con una voce in più per '2013/09/03':

  val 
date   
2013-09-02 2 
2013-09-03 10 
2013-09-03 20 
2013-09-06 5 
2013-09-07 1 

Ed ecco i risultati:

   val 
date    
2013-09-02 2.0 
2013-09-03 15.0 <- mean of original values for 2013-09-03 
2013-09-04 NaN <- NaN b/c date not present in orig 
2013-09-05 NaN <- NaN b/c date not present in orig 
2013-09-06 5.0 
2013-09-07 1.0 

nota che dopo questo si potrebbe usare metodi come fillna o interpolate per riempire i valori mancanti, se lo desideri.