2015-04-18 17 views
9

Mam dostęp do niektórych danych za pośrednictwem interfejsu API, gdzie muszę podać zakres dat dla mojego żądania, np. start = '20100101', end = '20150415'. Sądziłem, że przyspieszy to, dzieląc zakres dat na nie nakładające się interwały i wykorzystując proces wieloprocesowy w każdym interwale.Biorąc pod uwagę zakres dat, w jaki sposób możemy podzielić go na N przyległych pod-interwałów?

Mój problem polega na tym, że sposób dzielenia zakresu dat nie zapewnia konsekwentnie oczekiwanego rezultatu. Oto, co zrobiłem:

from datetime import date 

begin = '20100101' 
end = '201' 

Załóżmy, że chcemy podzielić to na ćwiartki. Najpierw zmienić ciąg znaków w terminach:

def get_yyyy_mm_dd(yyyymmdd): 
    # given string 'yyyymmdd' return (yyyy, mm, dd) 
    year = yyyymmdd[0:4] 
    month = yyyymmdd[4:6] 
    day = yyyymmdd[6:] 
    return int(year), int(month), int(day) 

y1, m1, d1 = get_yyyy_mm_dd(begin) 
d1 = date(y1, m1, d1) 
y2, m2, d2 = get_yyyy_mm_dd(end) 
d2 = date(y2, m2, d2) 

następnie podzielić ten zakres na podprzedziały:

def remove_tack(dates_list): 
    # given a list of dates in form YYYY-MM-DD return a list of strings in form 'YYYYMMDD' 
    tackless = [] 
    for d in dates_list: 
     s = str(d) 
     tackless.append(s[0:4]+s[5:7]+s[8:]) 
    return tackless 

def divide_date(date1, date2, intervals): 
    dates = [date1] 
    for i in range(0, intervals): 
     dates.append(dates[i] + (date2 - date1)/intervals) 
    return remove_tack(dates) 

Korzystanie zaczynają się i kończą z góry otrzymujemy:

listdates = divide_date(d1, d2, 4) 
print listdates # ['20100101', '20100402', '20100702', '20101001', '201'] looks correct 

Ale jeśli zamiast Używam dat:

begin = '20150101' 
end = '20150228' 

...

listdates = divide_date(d1, d2, 4) 
print listdates # ['20150101', '20150115', '20150129', '20150212', '20150226'] 

Brak mi dwa dni pod koniec lutego. Nie potrzebuję czasu ani strefy czasowej dla mojej aplikacji i nie mam nic przeciwko instalacji innej biblioteki.

Odpowiedz

12

bym faktycznie śledzić innego podejścia i polegać na timedelta i data oprócz określenia non-nakładających się zakresów

Realizacja

def date_range(start, end, intv): 
    from datetime import datetime 
    start = datetime.strptime(start,"%Y%m%d") 
    end = datetime.strptime(end,"%Y%m%d") 
    diff = (end - start)/intv 
    for i in range(intv): 
     yield (start + diff * i).strftime("%Y%m%d") 
    yield end.strftime("%Y%m%d") 

Wykonanie

>>> begin = '20150101' 
>>> end = '20150228' 
>>> list(date_range(begin, end, 4)) 
['20150101', '20150115', '20150130', '20150213', '20150228'] 
+0

Działa doskonale! Zwięzłe i pozbawione wszystkich moich pośrednich funkcji. Dzięki! – Scott

+1

Właśnie zauważyłem coś, co być może chciałbyś edytować.W twojej odpowiedzi: yield (d1 + diff * i) .strftime ("% Y% m% d"), d1 jest globalna i działa z moim kodem, ale ogólnie d1 powinno się zaczynać. – Scott

+0

@Scott: Dziękuję. Mój oryginalny kod był ze zmiennymi d1, d2, ale później zmieniono go na coś znaczącego w tym poście, ale z pozoru pominięto kilka zmian. – Abhijit

1

Could zamiast tego używasz obiektów datetime.date?

Jeśli zrobić:

import datetime 
begin = datetime.date(2001, 1, 1) 
end = datetime.date(2010, 12, 31) 

intervals = 4 

date_list = [] 

delta = (end - begin)/4 
for i in range(1, intervals + 1): 
    date_list.append((begin+i*delta).strftime('%Y%m%d')) 

i date_list powinny mieć datę zakończenia dla każdego inteval.

2

należy zmienić datę datetime

from datetime import date, datetime, timedelta 

begin = '20150101' 
end = '20150228' 

def get_yyyy_mm_dd(yyyymmdd): 
    # given string 'yyyymmdd' return (yyyy, mm, dd) 
    year = yyyymmdd[0:4] 
    month = yyyymmdd[4:6] 
    day = yyyymmdd[6:] 
    return int(year), int(month), int(day) 

y1, m1, d1 = get_yyyy_mm_dd(begin) 
d1 = datetime(y1, m1, d1) 
y2, m2, d2 = get_yyyy_mm_dd(end) 
d2 = datetime(y2, m2, d2) 

def remove_tack(dates_list): 
    # given a list of dates in form YYYY-MM-DD return a list of strings in form 'YYYYMMDD' 
    tackless = [] 
    for d in dates_list: 
    s = str(d) 
    tackless.append(s[0:4]+s[5:7]+s[8:]) 
    return tackless 

def divide_date(date1, date2, intervals): 
    dates = [date1] 
    delta = (date2-date1).total_seconds()/4 
    for i in range(0, intervals): 
    dates.append(dates[i] + timedelta(0,delta)) 
    return remove_tack(dates) 

listdates = divide_date(d1, d2, 4) 
print listdates 

wynik:

[ '20150101 00:00:00', '20150115 12:00:00', „20150130 00:00: 00' , '20150213 12:00:00', '20150228 0:00:00']

+0

Dzięki za wskazanie tego. Przyjąłem odpowiedź @ Abhijita, ponieważ to trochę oczyszcza mój kod. – Scott

+0

@ But oczywiście odpowiedź od Abhijita jest lepsza, ja też głosuję na nią;) –

1

Stosując Datetimeindex i okresy z Panda wraz ze słownika zrozumienia:

import pandas as pd 

begin = '20100101' 
end = '201' 

start = dt.datetime.strptime(begin, '%Y%m%d') 
finish = dt.datetime.strptime(end, '%Y%m%d') 

dates = pd.DatetimeIndex(start=start, end=finish, freq='D').tolist() 
quarters = [d.to_period('Q') for d in dates] 
df = pd.DataFrame([quarters, dates], index=['Quarter', 'Date']).T 

quarterly_dates = {str(q): [ts.strftime('%Y%m%d') 
          for ts in df[df.Quarter == q].Date.values.tolist()] 
          for q in quarters} 

>>> quarterly_dates 
{'2010Q1': ['20100101', 
    '20100102', 
    '20100103', 
    '20100104', 
    '20100105', 
... 
    '20101227', 
    '20101228', 
    '20101229', 
    '201', 
    '201']} 

>>> quarterly_dates.keys() 
['2010Q1', '2010Q2', '2010Q3', '2010Q4'] 
Powiązane problemy