将pandas时间戳转换为当月结束

时间:2015-12-19 02:23:50

标签: python pandas

这是几年前提出的this question的后续行动。我得到的输出让我觉得大熊猫的日期偏移在那段时间发生了变化。

我有约会,我想将它们移到他们所在月份的末尾。例如:

df = pd.DataFrame([pd.Timestamp('2014-01-15'), pd.Timestamp('2014-01-31')],
                    columns=['orig'])

我想将这两个转换为2014-01-31。我想知道做这件事的pandamic方法。

另一个问题中接受的答案提供了两种解决方案:

1)pd.Index(df.orig).to_period('M').to_timestamp('M')

2)pd.Index(df.orig) + pd.offsets.MonthEnd(0)

但是,在pandas 0.17.1中,这些都没有给出相同的答案。第一种方法有效,但第二种做法有所不同:

df[0] = df['orig'] + pd.offsets.MonthEnd(0)
df[1] = df['orig'] + pd.offsets.MonthEnd(1)

    orig        0           1
0   2014-01-15  2013-12-31  2014-01-31
1   2014-01-31  2013-12-31  2014-02-28

因此MonthEnd(0)将所有日期移至上个月末,而MonthEnd(1)将日期移至当前月末之外,如果它已经是最后一天这个月,在这种情况下,它将它移动到下个月的末尾。这看起来很奇怪。

那么,(1)真的是最好的方法吗?我很惊讶没有简单的方法来使用偏移完成同样的事情。

2 个答案:

答案 0 :(得分:3)

以下是一些替代方案:

import numpy as np
import pandas as pd
import pandas.tseries.offsets as offsets

ONE_MONTH = np.array([1], dtype='timedelta64[M]')
ONE_DAY = np.array([1], dtype='timedelta64[D]')

df = pd.DataFrame(pd.to_datetime(['2014-01-15', '2014-01-31', '2014-02-01']),
                    columns=['orig'])

df['using_datetime64'] = df['orig'].values.astype('datetime64[M]') + ONE_MONTH - ONE_DAY
df['using_to_period'] = pd.Index(df['orig']).to_period('M').to_timestamp('M')
df['using_dateoffset'] = df['orig'] + offsets.DateOffset(day=31)
df['using_rollforward'] = df['orig'].apply(lambda x: offsets.MonthEnd().rollforward(x))

其中,

df['orig'].values.astype('datetime64[M]') + ONE_MONTH - ONE_DAY

是最快的

In [108]: df = pd.DataFrame({'orig': np.arange(10000).astype('<i8').view('<datetime64[D]')})

In [109]: %timeit df['using_datetime64'] = df['orig'].values.astype('datetime64[M]') + ONE_MONTH - ONE_DAY
1000 loops, best of 3: 913 µs per loop

In [110]: %timeit df['using_to_period'] = pd.Index(df['orig']).to_period('M').to_timestamp('M')
1000 loops, best of 3: 1.95 ms per loop

In [111]: %timeit df['using_dateoffset'] = df['orig'] + offsets.DateOffset(day=31)
1 loops, best of 3: 240 ms per loop

In [112]: %timeit df['using_rollforward'] = df['orig'].apply(lambda x: offsets.MonthEnd().rollforward(x))
1 loops, best of 3: 813 ms per loop

请注意,using_datetime64using_to_periodusing_dateoffset即使df['orig']包含NaT值也能正常工作。 using_rollforward提出了ValueError: cannot convert float NaN to integer

答案 1 :(得分:2)

它使用ndk-build确实有效 - 但是@unutbu提供了更好的替代方案和时间安排:

.rollforward()

因为该功能非常智能,可以检查日期是否位于from pandas.tseries.offsets import * df = pd.DataFrame([pd.Timestamp('2014-01-15'), pd.Timestamp('2014-01-31')], columns=['orig']) df['month_end'] = df.orig.apply(lambda x: MonthEnd().rollforward(x)) orig month_end 0 2014-01-15 2014-01-31 1 2014-01-31 2014-01-31

offset