Дата и время недели панд не так, как ожидалось - PullRequest
2 голосов
/ 28 апреля 2019

При работе с датами Pandas я пытаюсь сгруппировать данные по неделям и годам.Однако я заметил несколько лет, когда последний день года сгруппировался с первой неделей того же года.

import pandas as pd
day_df = pd.DataFrame(index=pd.date_range('2016-01-01', '2020-12-31'))

for (week, year), subset in day_df.groupby([day_df.index.week, day_df.index.year]):
     if week == 1:
         print('Week:', subset.index.min(), subset.index.max())

Week: 1 2016-01-04 00:00:00 2016-01-10 00:00:00
Week: 1 2017-01-02 00:00:00 2017-01-08 00:00:00
Week: 1 2018-01-01 00:00:00 2018-12-31 00:00:00
Week: 1 2019-01-01 00:00:00 2019-12-31 00:00:00
Week: 1 2020-01-01 00:00:00 2020-01-05 00:00:00

Для 2018 и 2019 годов первый день года сгруппирован с последним днем ​​года!Ожидается ли такое поведение?Почему последним днем ​​года будет неделя 1?

Я получил желаемый результат с базовым оператором if, но такое поведение week может вызвать проблемы, потому что оно неожиданно.

Это делает то, что я хотелс группировкой:

for (week, year), subset in day_df.groupby([day_df.index.week, day_df.index.year]):
    # Prevent first week of year from including final days of same year
    if set(subset.index.month.unique()) == set([1, 12]):
        subset = subset.loc[subset.index.month == 1]
    if week == 1:
        print('Week:', week, subset.index.min(), subset.index.max())

Week: 1 2016-01-04 00:00:00 2016-01-10 00:00:00
Week: 1 2017-01-02 00:00:00 2017-01-08 00:00:00
Week: 1 2018-01-01 00:00:00 2018-01-07 00:00:00
Week: 1 2019-01-01 00:00:00 2019-01-06 00:00:00
Week: 1 2020-01-01 00:00:00 2020-01-05 00:00:00

1 Ответ

2 голосов
/ 28 апреля 2019

Ответ на этот вопрос заключается в том, что .week () - это порядковый номер недели. Метод .week () минимально определен в документации как:

DatetimeIndex.week

Порядковый номер недели

Порядковый номер недели формально известен как дата недели ISO. Дальнейшие замечания по этому поводу в python можно найти в date.isocalendar () в документации по python 3.7.3 datetime. Для общего объяснения того, как работает порядковый номер недели, вы можете найти полную информацию в википедии на Дата недели ISO .

Порядковый номер недели 2019 года можно найти на EpochConverter.com , где он четко показывает первый день года 31 декабря. 2018.

Если мы посмотрим на 1-ю неделю 2019 года, то увидим, что 31 декабря - первый день и начинается 1-я неделя 2019 года. Таким образом, это на самом деле соответствует вашим критериям включения в ваш фильтр на начало года. ,

Ниже мы фильтруем конец 2018 года и начало 2019 года, чтобы увидеть, что делает .week.

day_df["ordinal"] = day_df.index.week
day_df["day_of_week"] = day_df.index.weekday
print(day_df.loc["2018-12-28":"2019-01-08"])



             ordinal  day_of_week
2018-12-28       52            4
2018-12-29       52            5
2018-12-30       52            6
2018-12-31        1            0
2019-01-01        1            1
2019-01-02        1            2
2019-01-03        1            3
2019-01-04        1            4
2019-01-05        1            5
2019-01-06        1            6
2019-01-07        2            0
2019-01-08        2            1

Вам нужно будет добавить критерии месяца, чтобы убедиться, что это январь, как вы обнаружили в своем вопросе выше. Это тоже работает.

for (week, month, year), subset in day_df.groupby(
    [day_df.index.week, day_df.index.month, day_df.index.year]
):
    if week == 1 and month == 1:
        print("Week:", subset.index.min(), subset.index.max())

Если вы хотите, чтобы первая неделя начиналась в тот же день, используйте [pandas.period.strftime ()] 5

% U определяется как

Номер недели в году (воскресенье как первый день недели) в виде десятичного числа [00,53]. Все дни в новом году, предшествующем первому Воскресенье считается на неделе 0.

Для вашего фрейма данных это будет выглядеть так:

day_df['date'] = day_df.index
day_df["day_name"] = day_df['date'].dt.day_name()
day_df['str_from_time'] = day_df['date'].apply(lambda x: x.strftime("%U"))
day_df.loc["2018-12-28":"2019-01-08",['ordinal', 'str_from_time', 'day_of_week', 'day_name']]

            ordinal str_from_time  day_of_week   day_name
2018-12-28       52            51            4     Friday
2018-12-29       52            51            5   Saturday
2018-12-30       52            52            6     Sunday
2018-12-31        1            52            0     Monday
2019-01-01        1            00            1    Tuesday
2019-01-02        1            00            2  Wednesday
2019-01-03        1            00            3   Thursday
2019-01-04        1            00            4     Friday
2019-01-05        1            00            5   Saturday
2019-01-06        1            01            6     Sunday
2019-01-07        2            01            0     Monday
2019-01-08        2            01            1    Tuesday
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...