Pandas: конвертировать datetime в конец месяца

Я написал функцию для преобразования дат datetime pandas в конец месяца:

import pandas
import numpy
import datetime
from pandas.tseries.offsets import Day, MonthEnd

def get_month_end(d):
    month_end = d - Day() + MonthEnd() 
    if month_end.month == d.month:
        return month_end # 31/March + MonthEnd() returns 30/April
    else:
        print "Something went wrong while converting dates to EOM: " + d + " was converted to " + month_end
        raise

Эта функция кажется довольно медленной, и мне было интересно, есть ли более быстрая альтернатива? Причина, по которой я заметил это медленно, заключается в том, что я запускаю это в столбце dataframe с 50'000 датами, и я вижу, что с момента введения этой функции код намного медленнее (до того, как я преобразовал даты в конец месяца).

df = pandas.read_csv(inpath, na_values = nas, converters = {open_date: read_as_date})
df[open_date] = df[open_date].apply(get_month_end)

Я не уверен, что это актуально, но я читаю даты следующим образом:

def read_as_date(x):
    return datetime.datetime.strptime(x, fmt)

Ответы

Ответ 1

Пересмотренный, преобразованный в период, а затем обратно в метку времени делает трюк

In [104]: df = DataFrame(dict(date = [Timestamp('20130101'),Timestamp('20130131'),Timestamp('20130331'),Timestamp('20130330')],value=randn(4))).set_index('date')

In [105]: df
Out[105]: 
               value
date                
2013-01-01 -0.346980
2013-01-31  1.954909
2013-03-31 -0.505037
2013-03-30  2.545073

In [106]: df.index = df.index.to_period('M').to_timestamp('M')

In [107]: df
Out[107]: 
               value
2013-01-31 -0.346980
2013-01-31  1.954909
2013-03-31 -0.505037
2013-03-31  2.545073

Обратите внимание, что этот тип преобразования также можно сделать так, но выше было бы немного быстрее.

In [85]: df.index + pd.offsets.MonthEnd(0) 
Out[85]: DatetimeIndex(['2013-01-31', '2013-01-31', '2013-03-31', '2013-03-31'], dtype='datetime64[ns]', name=u'date', freq=None, tz=None)

Ответ 2

import pandas as pd
import numpy as np
import datetime as dt    

df0['Calendar day'] = pd.to_datetime(df0['Calendar day'], format='%m/%d/%Y')
df0['Calendar day'] = df0['Calendar day'].apply(pd.datetools.normalize_date)    
df0['Month Start Date'] = df0['Calendar day'].dt.to_period('M').apply(lambda r: r.start_time)

Этот код должен работать. День календаря - это столбец, в котором дана дата в формате% m/% d/% Y. Например: 12/28/2014 - 28 декабря 2014. Выходной результат составляет 2014-12-01 в классе 'pandas.tslib.Timestamp'.

Ответ 3

вы также можете использовать numpy, чтобы сделать это быстрее:

import numpy as np
date_array = np.array(['2013-01-01', '2013-01-15', '2013-01-30']).astype('datetime64[ns]')
month_start_date = date_array.astype('datetime64[M]')