Possiedo dataframes con indici DateTime di vari tipi (potrebbero essere dati settimanali, mensili, annuali). Voglio generare colonne che sono valori ritardati di altre colonne. Ottengo questi importati da un foglio di calcolo, non sto generando l'indice datetime all'interno di python.Pythonic way to lag colonne indicizzate in base al datetime
Sto lottando per trovare il modo "pitonico" per farlo. Immagino che se utilizzo la funzionalità datetime di Pandas, il ritardo potrebbe essere più robusto nel caso di dati strani o eccezionali.
Ho creato un esempio di giocattolo che sembra funzionare, ma non riesce nell'esempio del mio mondo reale.
L'esempio giocattolo che funziona correttamente (fa una nuova colonna che ha il valore di 'foo' del mese precedente)
rng = pd.date_range('2012-01-01', '2013-1-01', freq="M")
toy2 = pd.DataFrame(pd.Series(np.random.randint(0, 50, len(rng)), index=rng, name="foo"))
foo
2012-01-31 4
2012-02-29 2
2012-03-31 27
2012-04-30 7
2012-05-31 44
2012-06-30 22
2012-07-31 16
2012-08-31 18
2012-09-30 35
2012-10-31 35
2012-11-30 16
2012-12-31 32
toy2['lag_foo']= toy2['foo'].shift(1,'m')
foo lag_foo
2012-01-31 4 NaN
2012-02-29 2 4.0
2012-03-31 27 2.0
2012-04-30 7 27.0
2012-05-31 44 7.0
2012-06-30 22 44.0
2012-07-31 16 22.0
2012-08-31 18 16.0
2012-09-30 35 18.0
2012-10-31 35 35.0
2012-11-30 16 35.0
2012-12-31 32 16.0
Ma quando ho eseguito questo sul mio esempio di vita reale, non riesce con:
ValueError: cannot reindex from a duplicate axis
print type(toy)
print toy.columns
print toy['IPE m2'][0:5]
<class 'pandas.core.frame.DataFrame'>
Index([u'IPE m2'], dtype='object')
Date
2016-04-30 43.29
2016-03-31 40.44
2016-02-29 34.17
2016-01-31 32.47
2015-12-31 39.35
Name: IPE m2, dtype: float64
La traccia eccezione:
ValueError Traceback (most recent call last)
<ipython-input-170-9cb57a2ed681> in <module>()
----> 1 toy['prev_1m']= toy['IPE m2'].shift(1,'m')
C:\Users\mds\Anaconda2\lib\site-packages\pandas\core\frame.pyc in __setitem__(self, key, value)
2355 else:
2356 # set column
-> 2357 self._set_item(key, value)
2358
2359 def _setitem_slice(self, key, value):
C:\Users\mds\Anaconda2\lib\site-packages\pandas\core\frame.pyc in _set_item(self, key, value)
2421
2422 self._ensure_valid_index(value)
-> 2423 value = self._sanitize_column(key, value)
2424 NDFrame._set_item(self, key, value)
2425
C:\Users\mds\Anaconda2\lib\site-packages\pandas\core\frame.pyc in _sanitize_column(self, key, value)
2555
2556 if isinstance(value, Series):
-> 2557 value = reindexer(value)
2558
2559 elif isinstance(value, DataFrame):
C:\Users\mds\Anaconda2\lib\site-packages\pandas\core\frame.pyc in reindexer(value)
2547 # duplicate axis
2548 if not value.index.is_unique:
-> 2549 raise e
2550
2551 # other
ValueError: cannot reindex from a duplicate axis
Sembra che manchi una certa sottigliezza degli indici datetime di Pandas, penso. Inoltre non sono nemmeno sicuro che questo sia il modo ideale per farlo. l'unica cosa che potevo sospettare è che il toy.index non funzionante ha Nessuno come freq, mentre il lavoro toy2 esempio, ha la sua frequenza impostata come 'M'
toy.index
DatetimeIndex(['2016-04-30', '2016-03-31', '2016-02-29', '2016-01-31',
'2015-12-31', '2015-11-30', '2015-10-31', '2015-09-30',
'2015-08-31', '2015-07-31',
...
'NaT', 'NaT', 'NaT', 'NaT',
'NaT', 'NaT', 'NaT', 'NaT',
'NaT', 'NaT'],
dtype='datetime64[ns]', name=u'Date', length=142, freq=None)
toy2.index
DatetimeIndex(['2012-01-31', '2012-02-29', '2012-03-31', '2012-04-30',
'2012-05-31', '2012-06-30', '2012-07-31', '2012-08-31',
'2012-09-30', '2012-10-31', '2012-11-30', '2012-12-31'],
dtype='datetime64[ns]', freq='M')
In [ ]:
======== ===================
ho buttato via il NAT
toy = toy.dropna()
toy['prev_1m']= toy['IPE m2'].shift(1,'m')
e lo faccio ottenere i risultati che volevo. Tuttavia, ho anche ricevuto un avviso:
C:\Users\mds\Anaconda2\lib\site-packages\ipykernel\__main__.py:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
if __name__ == '__main__':
====
questo modo di assegnazione sopprime le avvertenze:
toy.loc[:,'prev_1m2']= toy['IPE m2'].shift(1,'m')
Ho usato dropna() per eliminare i NaT e funziona, tuttavia fornisce alcuni avvertimenti. Ho aggiunto l'appendice alla domanda originale. – user3556757
Sei sicuro di aver bisogno di 'dropna'? Rimuove tutte le righe dove sono 'NaN' nelle colonne.Se sì, usa' copy': 'toy = toy.dropna(). Copy()' Se necessario rimuovere i record con 'NaN' nell'indice, usa' toy = toy [ pd.notnull (toy.index)] '. – jezrael