Группировать произвольные объекты даты, которые находятся в пределах временного интервала друг друга - PullRequest
4 голосов
/ 07 августа 2010

Я хочу разделить календарь на двухнедельные интервалы, начинающиеся с 2008-May-5 или любой произвольной начальной точки.

Итак, я начинаю с нескольких объектов даты:

import datetime as DT

raw = ("2010-08-01",
       "2010-06-25",
       "2010-07-01",
       "2010-07-08")

transactions = [(DT.datetime.strptime(datestring, "%Y-%m-%d").date(),
                 "Some data here") for datestring in raw]
transactions.sort()

Byанализируя даты вручную, я вполне могу выяснить, какие даты попадают в тот же двухнедельный интервал.Я хочу получить группировку, похожую на эту:

# Fortnight interval 1
(datetime.date(2010, 6, 25), 'Some data here')
(datetime.date(2010, 7, 1), 'Some data here')
(datetime.date(2010, 7, 8), 'Some data here')

# Fortnight interval 2
(datetime.date(2010, 8, 1), 'Some data here')

Ответы [ 3 ]

12 голосов
/ 07 августа 2010
import datetime as DT
import itertools

start_date=DT.date(2008,5,5)

def mkdate(datestring):
    return DT.datetime.strptime(datestring, "%Y-%m-%d").date()

def fortnight(date):
    return (date-start_date).days //14

raw = ("2010-08-01",
       "2010-06-25",
       "2010-07-01",
       "2010-07-08")
transactions=[(date,"Some data") for date in map(mkdate,raw)]
transactions.sort(key=lambda (date,data):date)

for key,grp in itertools.groupby(transactions,key=lambda (date,data):fortnight(date)):
    print(key,list(grp))

выходы

# (55, [(datetime.date(2010, 6, 25), 'Some data')])
# (56, [(datetime.date(2010, 7, 1), 'Some data'), (datetime.date(2010, 7, 8), 'Some data')])
# (58, [(datetime.date(2010, 8, 1), 'Some data')])

Обратите внимание, что 2010-6-25 находится на 55-й неделе, начиная с 2008-5-5, а 2010-7-1 на 56-м. Если вы хотите, чтобы они сгруппировались, просто измените start_date (на что-то вроде 2008-5-16).

PS. Ключевым инструментом, использованным выше, является itertools.groupby, что подробно объясняется здесь .

Редактировать: lambda просто способ сделать "анонимными" функциями . (Они являются анонимными в том смысле, что им не дают имена, подобные функциям, определенным def). Везде, где вы видите лямбду, также можно использовать def для создания эквивалентной функции. Например, вы можете сделать это:

import operator
transactions.sort(key=operator.itemgetter(0))

def transaction_fortnight(transaction):
    date,data=transaction
    return fortnight(date)

for key,grp in itertools.groupby(transactions,key=transaction_fortnight):
    print(key,list(grp))
4 голосов
/ 07 августа 2010

Используйте itertools groupby с функцией лямбда, чтобы разделить на длину периода расстояние от начальной точки.

>>> for i, group in groupby(range(30), lambda x: x // 7):
    print list(group)


[0, 1, 2, 3, 4, 5, 6]
[7, 8, 9, 10, 11, 12, 13]
[14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27]
[28, 29]

То же самое с датами:

import itertools as it
start = DT.date(2008,5,5)
lenperiod = 14

for fnight,info in it.groupby(transactions,lambda data: (data[0]-start).days // lenperiod):
    print list(info)

Вы также можете использовать номера недель от strftime и lenperiod в количестве недель:

for fnight,info in it.groupby(transactions,lambda data: int (data[0].strftime('%W')) // lenperiod):
    print list(info)
1 голос
/ 26 марта 2016

Использование панд DataFrame с resample также работает.Учитывая данные OP, но измените «некоторые данные здесь» на «abcd».

>>> import datetime as DT
>>> raw = ("2010-08-01",
...        "2010-06-25",
...        "2010-07-01",
...        "2010-07-08")
>>> transactions = [(DT.datetime.strptime(datestring, "%Y-%m-%d"), data) for
...                 datestring, data in zip(raw,'abcd')]
[(datetime.datetime(2010, 8, 1, 0, 0), 'a'),
 (datetime.datetime(2010, 6, 25, 0, 0), 'b'),
 (datetime.datetime(2010, 7, 1, 0, 0), 'c'),
 (datetime.datetime(2010, 7, 8, 0, 0), 'd')]

Теперь попробуйте использовать панд.Сначала создайте DataFrame с именами столбцов и настройкой индексов на даты.

>>> import pandas as pd
>>> df = pd.DataFrame(transactions,
...                   columns=['date','data']).set_index('date')
           data
date
2010-08-01    a
2010-06-25    b
2010-07-01    c
2010-07-08    d

Теперь используйте псевдонимы Series Offset каждые 2 недели, начиная с воскресенья, и объединяйте результаты.

>>> fortnight = df.resample('2W-SUN').sum()
           data
date
2010-06-27    b
2010-07-11   cd
2010-07-25    0
2010-08-08    a

Теперь просмотрите данные по мере необходимости по недельному пуску

>>> fortnight.loc['2010-06-27']['data']
b

или по индексу

>>> fortnight.iloc[0]['data']
b

или по индексам

>>> data = fortnight.iloc[:2]['data']
b
date
2010-06-27     b
2010-07-11    cd
Freq: 2W-SUN, Name: data, dtype: object
>>> data[0]
b
>>> data[1]
cd
...