Получить начальную дату недели (понедельник) из столбца даты в Python (pandas)?

Я видел много сообщений о том, как вы можете это сделать с помощью строки даты, но я пытаюсь что-то сделать для столбца dataframe и до сих пор не повезло. Мой текущий метод: получить день недели с "myday", а затем смещаться, чтобы получить понедельник.

df['myday'] is column of dates. 
mydays = pd.DatetimeIndex(df['myday']).weekday
df['week_start'] = pd.DatetimeIndex(df['myday']) - pd.DateOffset(days=mydays)

Но я получаю ТипError: неподдерживаемый тип для компонента timedelta days: numpy.ndarray

Как я могу получить дату начала недели из столбца df?

Ответ 1

это терпит неудачу, потому что pd.DateOffset ожидает единственное целое число в качестве параметра (и вы передаете ему массив). Вы можете использовать DateOffset только для изменения столбца даты с тем же смещением.

попробуйте это:

import datetime as dt
# Change 'myday' to contains dates as datetime objects
df['myday'] = pd.to_datetime(df['myday'])  
# 'daysoffset' will container the weekday, as integers
df['daysoffset'] = df['myday'].apply(lambda x: x.weekday())
# We apply, row by row (axis=1) a timedelta operation
df['week_start'] = df.apply(lambda x: x['myday'] - dt.TimeDelta(days=x['daysoffset']), axis=1)

Я на самом деле не тестировал этот код (там не было примеров данных), но это должно работать для того, что вы описали.

Однако вы можете посмотреть на pandas.Resample, который может обеспечить лучшее решение - в зависимости от того, что именно вы ищете.

Ответ 2

Другая альтернатива:

df['week_start'] = df['myday'].dt.to_period('W').apply(lambda r: r.start_time)

Это установит 'week_start' в первый понедельник перед временем в 'myday'.

Ответ 3

Хотя решения @knightofni и @Paul работают, я стараюсь избегать применения apply в Pandas, потому что оно обычно довольно медленное по сравнению с методами на основе массива. Чтобы избежать этого, мы можем изменить метод, основанный на днях недели, и просто преобразовать день недели в numpy timedelta64 [D].

df['week_start'] = df['myday'] - df['myday'].dt.weekday.astype('timedelta64[D]')

Используя мои тестовые данные с 60000 датами, я получал следующие два раза, используя два других предложенных ответа и метод на основе приведения.

%timeit df.apply(lambda x: x['myday'] - datetime.timedelta(days=x['myday'].weekday()), axis=1)
>>> 1 loop, best of 3: 7.43 s per loop
%timeit df['myday'].dt.to_period('W').apply(lambda r: r.start_time)
>>> 1 loop, best of 3: 2.38 s per loop
%timeit df['myday'] - df['myday'].dt.weekday.astype('timedelta64[D]')
>>> 100 loops, best of 3: 12.3 ms per loop

или почти в 200 раз быстрее на моем наборе данных.

Ответ 4

(просто добавив в n8yoder ответ)

Использование .astype('timedelta64[D]') кажется мне не таким читаемым - нашла альтернативу, используя только функциональность pandas:

df['myday'] - pd.to_timedelta(arg=df['myday'].dt.weekday, unit='D')