2015-08-05 10 views
5

Jest to bardzo podobne do pytania here, ale zastanawiam się, czy istnieje czysty sposób w pandach, aby dzień roboczy był świadomy TimedeltaIndex? Ostatecznie próbuję uzyskać liczbę dni roboczych (bez kalendarza świątecznego) między datetimeIndex i timestamp. Jak na odwołanie pytanie, coś jak to działaPanda liczba dni roboczych między DatetimeIndex a datownikiem

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) 

co daje

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

ale ten wydaje się nieco kludgy. Gdy próbuję coś podobnego

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

dostaję TimedeltaIndex ale częstotliwość dzień roboczy jest odrzucany

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

prostu zastanawiasz się, czy istnieje bardziej elegancki sposób, aby przejść na ten temat.

Odpowiedz

8

TimedeltaIndex es oznaczają stałe rozpiętości czasu. Można je dodać do znaczników czasu Pandy, aby zwiększyć je o ustalone kwoty. Ich zachowanie nigdy nie zależy od tego, czy Datownik jest dniem roboczym. Sam TimedeltaIndex nigdy nie jest świadomy dnia roboczego.

Ponieważ ostatecznym celem jest policzenie liczby dni między datetimeIndex i timestamp, chciałbym spojrzeć w innym kierunku niż konwersja do TimedeltaIndex.


Niestety, obliczenia data są dość skomplikowane, a liczba struktur danych powstały w celu radzenia sobie z nimi - Python datetime.dates, datetime.datetime s, Pandy Timestamps, NumPy datetime64 ów.

Każdy ma swoje mocne strony, ale żaden z nich nie jest dobry do wszystkich celów. Aby wykorzystać ich mocne strony, konieczne jest kiedyś przekonwertowanie tych typów na następujące .

Aby korzystać np.busday_count trzeba konwertować DatetimeIndex i godziną do jakiś rodzaj np.busday_count rozumie. To, co nazywacie kludginess, jest kodem wymaganym do konwersji typów. Nie ma odwrotu, zakładając, że chcemy użyć np.busday_count - i nie znam lepszego narzędzia do tej pracy niż np.busday_count.

Tak, chociaż nie sądzę, jest bardziej zwięzły sposób liczenia dni roboczych niż niż metoda proponujecie, jest znacznie bardziej wydajnych sposobów: Konwersja do datetime64[D] „S zamiast Pythonie datetime.date obiektów:

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) 

to 100x szybciej powyższym przykładzie (gdzie len(drg) blisko 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 konwertuje dane wejściowe na datetime64[D] s, tak więc unikanie dodatkowej konwersji do i od datetime.date s jest znacznie bardziej wydajne.

+0

Dzięki, chociaż moja aplikacja nie jest tak intensywna, moje rozwiązanie było zdecydowanie na tyle wolne, aby mnie denerwować, więc ta szybkość jest bardzo cenna. Dobrze wiedzieć o tym, co się dzieje pod maską. – mgilbert

+0

Jestem trochę zdezorientowany. Jeśli próbujemy policzyć liczbę dni roboczych, nie "pd.date_range (start, end, freq =" B "). Size" daj nam to od razu? Nie ma potrzeby używania numpy w ogóle. –

+1

@JohnTyree: Problem polega na znalezieniu liczby dni roboczych między DatetimeIndex i Timestamp. 'pd.date_range (start, end, freq = 'B'). size' znajduje liczbę dni roboczych między dwiema datami. Będziesz musiał wywołać to w pętli na każdy dzień w DatetimeIndex. Jeśli masz czas '[pd.date_range (DRG [i], znacznik czasu, freq = 'B'). Size - 1 dla i w zakresie (len (drg.))]" Przekonasz się, że jest bardzo wolny. – unutbu