2015-07-10 16 views
7

Ho un dataframe panda in cui ogni osservazione ha una data (come una colonna di voci nel formato datetime [64]). Queste date sono distribuite su un periodo di circa 5 anni. Vorrei tracciare un grafico della densità del kernel delle date di tutte le osservazioni, con gli anni etichettati sull'asse x.Come tracciare il grafico della densità del kernel delle date in Panda?

ho capito come creare un tempo-delta rispetto ad una data di riferimento e quindi creare una trama densità del numero di ore/giorni/anni tra ogni osservazione e la data di riferimento:

df['relativeDate'].astype('timedelta64[D]').plot(kind='kde') 

Ma questo non è esattamente quello che voglio: se converto in delta anno, allora l'asse x è giusto ma perdo la variazione entro un anno. Ma se prendo un'unità di tempo più piccola come l'ora o il giorno, le etichette dell'asse x sono molto più difficili da interpretare.

Qual è il modo più semplice per eseguire questo lavoro in Pandas?

+0

un'occhiata a kde-trama in Seaborn: http://stanford.edu/~mwaskom/software/seaborn/generated/seaborn.kdeplot.html – Moritz

risposta

3

Ispirato risposta @JohnE s', un approccio alternativo per la conversione data per valore numerico è quello di utilizzare .toordinal().

import pandas as pd 
import numpy as np 

# simulate some artificial data 
# =============================== 
np.random.seed(0) 
dates = pd.date_range('2010-01-01', periods=31, freq='D') 
df = pd.DataFrame(np.random.choice(dates,100), columns=['dates']) 
# use toordinal() to get datenum 
df['ordinal'] = [x.toordinal() for x in df.dates] 

print(df) 

     dates ordinal 
0 2010-01-13 733785 
1 2010-01-16 733788 
2 2010-01-22 733794 
3 2010-01-01 733773 
4 2010-01-04 733776 
5 2010-01-28 733800 
6 2010-01-04 733776 
7 2010-01-08 733780 
8 2010-01-10 733782 
9 2010-01-20 733792 
..  ...  ... 
90 2010-01-19 733791 
91 2010-01-28 733800 
92 2010-01-01 733773 
93 2010-01-15 733787 
94 2010-01-04 733776 
95 2010-01-22 733794 
96 2010-01-13 733785 
97 2010-01-26 733798 
98 2010-01-11 733783 
99 2010-01-21 733793 

[100 rows x 2 columns]  

# plot non-parametric kde on numeric datenum 
ax = df['ordinal'].plot(kind='kde') 
# rename the xticks with labels 
x_ticks = ax.get_xticks() 
ax.set_xticks(x_ticks[::2]) 
xlabels = [dt.datetime.fromordinal(int(x)).strftime('%Y-%m-%d') for x in x_ticks[::2]] 
ax.set_xticklabels(xlabels) 

enter image description here

+2

Buona risposta. Questo è molto più robusto della mia risposta in quanto gestirà correttamente gli anni bisestili e le date di inizio diverse dal 1 gennaio. La raccomanderei come risposta accettata. – JohnE

3

Immagino che ci sia un modo migliore e automatico per farlo, ma se così non fosse, questa dovrebbe essere una soluzione decente. In primo luogo, cerchiamo di impostare alcuni dati di esempio:

np.random.seed(479) 
start_date = '2011-1-1' 
df = pd.DataFrame({ 'date':np.random.choice( 
        pd.date_range(start_date, periods=365*5, freq='D'), 50) }) 

df['rel'] = df['date'] - pd.to_datetime(start_date) 
df.rel = df.rel.astype('timedelta64[D]') 

     date rel 
0 2014-06-06 1252 
1 2011-10-26 298 
2 2013-08-24 966 
3 2014-09-25 1363 
4 2011-12-23 356 

Come si può vedere, 'rel' è solo il numero di giorni dal giorno di partenza. È essenzialmente un numero intero, quindi tutto ciò che devi veramente fare è normalizzarlo rispetto alla data di inizio.

df['year_as_float'] = pd.to_datetime(start_date).year + df.rel/365. 

     date rel year_as_float 
0 2014-06-06 1252 2014.430137 
1 2011-10-26 298 2011.816438 
2 2013-08-24 966 2013.646575 
3 2014-09-25 1363 2014.734247 
4 2011-12-23 356 2011.975342 

Avresti bisogno di registrare che un po 'per una data non a partire dal 1. gennaio che è anche ignorando qualsiasi anni bisestili che non è davvero un problema pratico se si sta solo producendo una trama di KDE in 5 anni , ma potrebbe importare a seconda di cosa potresti voler fare.

Ecco la trama

df['year_as_float']d.plot(kind='kde') 

enter image description here