2015-08-05 19 views
5

Questo è abbastanza simile alla domanda here ma mi chiedo se c'è un modo pulito in panda per rendere conto un giorno lavorativo TimedeltaIndex? In definitiva sto cercando di ottenere il numero di giorni lavorativi (senza calendario delle festività) tra un DatetimeIndex e un Timestamp. Come per la questione si fa riferimento, qualcosa di simile a questo funzionaNumero panda di giorni lavorativi tra un DatetimeIndex e un Timestamp

import pandas as pd 
import numpy as np 
drg = pd.date_range('2015-07-31', '2015-08-05', freq='B') 
A = [d.date() for d in drg] 
B = pd.Timestamp('2015-08-05', 'B').date() 
np.busday_count(A, B) 

che dà

array([3, 2, 1, 0], dtype=int64) 

ma questo sembra un po 'kludgy. Se provo qualcosa di simile

drg - pd.Timestamp('2015-08-05', 'B') 

ho un TimedeltaIndex ma la frequenza giorno lavorativo viene fatto cadere

TimedeltaIndex(['-5 days', '-2 days', '-1 days', '0 days'], dtype='timedelta64[ns]', freq=None) 

Chiedo solo se c'è un modo più elegante per andare su questo.

risposta

8

TimedeltaIndex es rappresentano intervalli di tempo fissi. Possono essere aggiunti ai timestamp di Pandas per incrementarli di importi fissi. Il loro comportamento non dipende mai dal fatto che Timestamp sia o meno un giorno lavorativo. TimedeltaIndex non è mai al corrente del giorno lavorativo.

Poiché l'obiettivo finale è contare il numero di giorni tra un DatetimeIndex e un Timestamp, guarderei in un'altra direzione rispetto alla conversione in TimedeltaIndex.


Purtroppo, i calcoli di data sono piuttosto complicate, e un certo numero di strutture di dati sono sorti per trattare con loro - Python datetime.dates, datetime.datetime s, Panda Timestamps, NumPy datetime64 s.

Ognuno di loro ha i suoi punti di forza, ma nessuno di loro è buono a tutti gli effetti. Per sfruttare i loro punti di forza, è talvolta necessario convertire tra questi tipi.

Per utilizzare np.busday_count è necessario convertire il DatetimeIndex e timestamp per un certo tipo np.busday_count capisce. Quello che chiami kludginess è il codice richiesto per convertire i tipi. Non c'è modo di supporre che vogliamo usare np.busday_count - e non conosco nessuno strumento migliore per questo lavoro di np.busday_count.

Quindi, anche se non credo che ci sia un modo più succinto contare giorni lavorativi che rispetto al metodo che proponete, c'è un modo molto più performante: Converti in datetime64[D] 's invece di Python datetime.date oggetti:

import pandas as pd 
import numpy as np 
drg = pd.date_range('2000-07-31', '2015-08-05', freq='B') 
timestamp = pd.Timestamp('2015-08-05', 'B') 

def using_astype(drg, timestamp): 
    A = drg.values.astype('<M8[D]') 
    B = timestamp.asm8.astype('<M8[D]') 
    return np.busday_count(A, B) 

def using_datetimes(drg, timestamp): 
    A = [d.date() for d in drg] 
    B = pd.Timestamp('2015-08-05', 'B').date() 
    return np.busday_count(A, B) 

Questo è più di 100 volte più veloce per l'esempio di cui sopra (dove len(drg) è vicino a 4000):

In [88]: %timeit using_astype(drg, timestamp) 
10000 loops, best of 3: 95.4 µs per loop 

In [89]: %timeit using_datetimes(drg, timestamp) 
100 loops, best of 3: 10.3 ms per loop 

np.busday_count converte il proprio input in datetime64[D] s in ogni caso, quindi evitare questa conversione aggiuntiva da e verso datetime.date s è molto più efficiente.

+0

Grazie, anche se la mia applicazione non è molto performante, la mia soluzione era decisamente abbastanza lenta da infastidirmi, quindi questa accelerazione è molto apprezzata. Buono a sapersi su cosa sta succedendo sotto il cofano. – mgilbert

+0

Sono un po 'confuso qui. Se stiamo solo cercando di contare il numero di giorni lavorativi, non 'pd.date_range (start, end, freq = 'B'). Size' ce lo danno immediatamente? Non c'è bisogno di usare Numpy affatto. –

+1

@JohnTyree: il problema è trovare il numero di giorni lavorativi tra un DatetimeIndex e un Timestamp. 'pd.date_range (start, end, freq = 'B'). size' trova il numero di giorni lavorativi tra due date. Dovresti chiamarlo in un ciclo per ogni giorno nel DatetimeIndex. Se hai tempo '[pd.date_range (drg [i], timestamp, freq = 'B'). Size - 1 per i in range (len (drg))]" troverai che è estremamente lento. – unutbu

Problemi correlati