这是几年前提出的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)真的是最好的方法吗?我很惊讶没有简单的方法来使用偏移完成同样的事情。
答案 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_datetime64
,using_to_period
和using_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