Разница в количестве недель между датой и временем - PullRequest
0 голосов
/ 08 февраля 2019

У меня большая проблема с datetime и timestamp, работающими с моим DataFrame.Я хочу указать номер недели даты, но обнаружил некоторые несоответствия.Вот случай:

df = pd.DataFrame(['2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', 
                    '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04'], 
                   columns=['datestr'])
df.date = pd.to_datetime(ddf.datestr, format='%Y-%m-%d')
df['week'] = ddf.date.apply(lambda x: x.week)
df['m'] = ddf.date.apply(lambda x: (x.year, x.week))
df['weekpy'] = ddf.m.apply(lambda d: datetime.strptime(str(d)+'-1', "(%Y, %W)-%w"))

дает мне

    datestr    week    m          weekpy
0   2018-12-28  52  (2018, 52)  2018-12-24
1   2018-12-29  52  (2018, 52)  2018-12-24
2   2018-12-30  52  (2018, 52)  2018-12-24
3   2018-12-31  1   (2018, 1)   2018-01-01
4   2019-01-01  1   (2019, 1)   2019-01-07
5   2019-01-02  1   (2019, 1)   2019-01-07
6   2019-01-03  1   (2019, 1)   2019-01-07
7   2019-01-04  1   (2019, 1)   2019-01-07

Как вы можете видеть, дата 2018-12-31 для timestamp находится на первой неделе года (понедельник) 2019, но все еще в 2018. Кроме того, для datetime первый день первой недели 2019 года - это 2019-01-07.

Как мы можем справиться с этим?Цель этого - сгруппировать по неделям

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

Используйте isocalendar(), который возвращает tuple из (year, week, day):

df['m'] = df['date'].apply(lambda x: x.isocalendar()[:2])  # only need the year and week

# 0    (2018, 52)
# 1    (2018, 52)
# 2    (2018, 52)
# 3     (2019, 1)
# 4     (2019, 1)
# 5     (2019, 1)
# 6     (2019, 1)
# 7     (2019, 1)

Чтобы вычислить начало недели, вычтите dayofweek:

df['weekpy'] = df['date'].apply(lambda x: x - pd.Timedelta(days=x.dayofweek))

# 0   2018-12-24
# 1   2018-12-24
# 2   2018-12-24
# 3   2018-12-31
# 4   2018-12-31
# 5   2018-12-31
# 6   2018-12-31
# 7   2018-12-31

Finalрезультаты:

         date  week           m     weekpy
0  2018-12-28    52  (2018, 52) 2018-12-24
1  2018-12-29    52  (2018, 52) 2018-12-24
2  2018-12-30    52  (2018, 52) 2018-12-24
3  2018-12-31     1   (2019, 1) 2018-12-31
4  2019-01-01     1   (2019, 1) 2018-12-31
5  2019-01-02     1   (2019, 1) 2018-12-31
6  2019-01-03     1   (2019, 1) 2018-12-31
7  2019-01-04     1   (2019, 1) 2018-12-31
0 голосов
/ 08 февраля 2019

Pandas Timestamp s и Python datetime.date s сообщают ISO 8601 номера недели :

import datetime as DT
import pandas as pd
df = pd.DataFrame(['2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31', 
                    '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04'], 
                   columns=['date'])

df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
df['datenum'] = df['date'].dt.week
df['py-ios-weeknum'] = [d.isocalendar()[1] for d in df['date'].dt.date]
df['py-iso-year'] = [d.isocalendar()[0] for d in df['date'].dt.date]
df['week'] = df.date.apply(lambda x: x.week)
df['m'] = df.date.apply(lambda x: (x.isocalendar()[0], x.isocalendar()[1]))
df['weekpy'] = df.m.apply(lambda d: DT.datetime.strptime(str(d)+'-1', "(%Y, %W)-%w"))
print(df)

выходы

        date  datenum  py-ios-weeknum  py-iso-year  week           m     weekpy
0 2018-12-28       52              52         2018    52  (2018, 52) 2018-12-24
1 2018-12-29       52              52         2018    52  (2018, 52) 2018-12-24
2 2018-12-30       52              52         2018    52  (2018, 52) 2018-12-24
3 2018-12-31        1               1         2019     1   (2019, 1) 2019-01-07
4 2019-01-01        1               1         2019     1   (2019, 1) 2019-01-07
5 2019-01-02        1               1         2019     1   (2019, 1) 2019-01-07
6 2019-01-03        1               1         2019     1   (2019, 1) 2019-01-07
7 2019-01-04        1               1         2019     1   (2019, 1) 2019-01-07

df['datenum'] = df['date'].dt.weekэквивалентно df['week'] = df.date.apply(lambda x: x.week), но использование аксессора Series.dt быстрее (с точки зрения как записи, так и производительности), чем вызов лямбда-функции для каждого элемента в df.date, что и делает apply.

Учитывая Python datetime.date (или datetime.datetime), самый простой способ получить номер недели ISO - вызвать его isocalendar метод :

In [76]: d = DT.datetime(2018,12,31)
In [87]: iso_year, iso_week_number, iso_weekday = d.isocalendar()
In [88]: print(iso_year, iso_week_number, iso_weekday)
2019 1 1

Обратите внимание, что 2018-12-31 соответствует году ISO 2019. Чтобы df['weekpy'] возвратил первый день недели ISO, вы должны указать год ISO , d.isocalendar()[0], а не фактический год,d.year.

In [93]: print(DT.datetime.strptime('({}, {})-1'.format(d.year, pd.Timestamp(d).week), "(%Y, %W)-%w"))  # WRONG
2018-01-01 00:00:00

In [94]: print(DT.datetime.strptime('({}, {})-1'.format(d.isocalendar()[0], d.isocalendar()[1]), "(%Y, %W)-%w")) # OK
2019-01-07 00:00:00
0 голосов
/ 08 февраля 2019

В свете того, как установлено свойство .week для тех недель, которые охватывают два разных календарных года, нам понадобится функция группировки, которая немного более независима от нового года.Самое простое решение - предположить, что в ваших данных нет пропусков (у вас есть строки на каждый день), и разбить их на куски по 7.

Но это кажется действительно хрупким.Вместо этого вот реализация, которая спрашивает: «Какой был понедельник этой недели?»и групп по этому.

df.date.apply(lambda t: t - (t.dayofweek * pd.Timedelta('1 day')))

Это работает, потому что точное значение datetime понедельника данной недели будет уникальным от недели к неделе.Вот демоверсия .

Это, конечно, предполагает, что вы хотите, чтобы 31 декабря 2018 года было на той же неделе, что и 1 января 2019 года (что, вероятно, так и происходит, посколькуто же самое с понедельника по воскресенье, но, как указал Idlehands, это вопрос семантики, который вам решать).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...