Дата потолка (аналогично дате потолка R) в Python - PullRequest
2 голосов
/ 19 февраля 2020

Предположим, у меня есть следующий pandas фрейм данных,

import pandas as pd
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta

df = pd.DataFrame([[201901, 'Value1'], [201902, 'Value2'], [201707, 'Value3], columns=['Col1', 'Col2'])
╔════════╦═════════╗
║  Col1  ║  Col2   ║
╠════════╬═════════╣ 
║ 201901 ║ Value 1 ║
║ 201902 ║ Value 2 ║
║ 201707 ║ Value 3 ║
╚════════╩═════════╝

И я хочу, чтобы первый столбец был таким (я хочу последний день каждого месяца):

╔════════════╦═════════╗
║    Col1    ║  Col2   ║
╠════════════╬═════════╣
║ 2019-01-31 ║ Value 1 ║
║ 2019-02-28 ║ Value 2 ║
║ 2017-07-31 ║ Value 3 ║
╚════════════╩═════════╝

Итак, чтобы добиться того, что я пробовал следующее:

next_month = {'01':'02', '02':'03', 
              '03':'04', '04':'05', 
              '05':'06', '06':'07', 
              '07':'08', '08':'09', 
              '09':'10', '10':'11', 
              '11':'12', '12':'01'}

df = df['Col1'].apply(lambda x: str(int(str(x)[:4])+1) + next_month[str(x)[-2:] 
                      if str(x)[-2:] else str(x)[:4] + next_month[str(x)[-2:]])

df['Col1'] = pd.to_datetime(df['Col1'], format='%Y%m') - timedelta(days=1)

В этой последней части кода я заменяю месяц строки на следующий месяц и проверяю, декабрь ли он, добавляя один год.

Есть ли способ добиться этого эффективно? Я пробовал и это, но это заняло НАМНОГО времени, даже больше, чем показывал предыдущий код.

df['Col1'] = df['Col1'].apply(lambda x: (x + relativedelta(months=1)) - relativedelta(days=1))

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Я думаю tseries.offsets.MonthEnd это то, что вам нужно?

pd.to_datetime(df['Col1'], format='%Y%m') + pd.tseries.offsets.MonthEnd(1)

Вывод:

0   2019-01-31
1   2019-02-28
2   2017-07-31
Name: Col1, dtype: datetime64[ns]
1 голос
/ 19 февраля 2020

Используйте ту же идею в numpy для повышения производительности:

s = pd.to_datetime(df['Col1'], format='%Y%m')

df['Col11'] = (s.to_numpy().astype('datetime64[M]') +
              np.array([1], dtype='timedelta64[M]') - 
              np.array([1], dtype='timedelta64[D]'))

Другая идея - создать словарь и Series.map:

d = dict(zip(pd.date_range('1900', '2100', freq='MS')[:-1],
             pd.date_range('1900', '2100', freq='M')))

df['Col12'] = pd.to_datetime(df['Col1'], format='%Y%m').map(d)
print (df)
     Col1    Col2      Col11      Col12
0  201901  Value1 2019-01-31 2019-01-31
1  201902  Value2 2019-02-28 2019-02-28
2  201707  Value3 2017-07-31 2017-07-31
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...