Pandas:更改日期
Pandas: Change day
我有一个 datetime
系列,需要将每个条目的日期更改为 1
。我想过很多简单的解决方案,但 none 对我有用。目前,唯一真正有效的是
- 设置系列为索引
- 从索引中查询月份和年份
- 使用年、月和 1 重建一个新的时间序列
真的不会那么复杂吧?有月开始,但不幸的是 offset
,这在这里没有用。该方法似乎没有 set()
功能,当系列是一列而不是索引本身(的一部分)时,功能甚至更少。
唯一相关的问题是 this,但此处使用的技巧不适用于此处。
您可以使用.apply
和datetime.replace
,例如:
import pandas as pd
from datetime import datetime
ps = pd.Series([datetime(2014, 1, 7), datetime(2014, 3, 13), datetime(2014, 6, 12)])
new = ps.apply(lambda dt: dt.replace(day=1))
给出:
0 2014-01-01
1 2014-03-01
2 2014-06-01
dtype: datetime64[ns]
另一个答案有效,但任何时候您使用 apply
,您的代码都会变慢 很多。通过为系列编写快速矢量化日期时间替换,我能够获得 8.5 倍的加速。
def vec_dt_replace(series, year=None, month=None, day=None):
return pd.to_datetime(
{'year': series.dt.year if year is None else year,
'month': series.dt.month if month is None else month,
'day': series.dt.day if day is None else day})
申请:
%timeit dtseries.apply(lambda dt: dt.replace(day=1))
# 4.17 s ± 38.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
矢量化:
%timeit vec_dt_replace(dtseries, day=1)
# 491 ms ± 6.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
请注意,尝试将日期更改为不存在的日期可能会遇到错误,例如尝试将 2012-02-29 更改为 2013-02-29。使用 pd.to_datetime
的 errors
参数来忽略或强制它们。
数据生成:生成具有 100 万个随机日期的序列:
import pandas as pd
import numpy as np
# Generate random dates. Modified from:
def pp(start, end, n):
start_u = start.value // 10 ** 9
end_u = end.value // 10 ** 9
return pd.Series(
(10 ** 9 * np.random.randint(start_u, end_u, n)).view('M8[ns]'))
start = pd.to_datetime('2015-01-01')
end = pd.to_datetime('2018-01-01')
dtseries = pp(start, end, 1000000)
# Remove time component
dtseries = dtseries.dt.normalize()
其他两个答案有效,但既不优雅也不符合 pandas
库的精神。相反,请考虑这个,在我的测试中,它也比 Kyle Barron 的矢量化答案快一点。它是一个不需要定义任何外部函数的单行代码,经过矢量化处理,并保持在 pandas
生态系统中:
import pandas as pd
dtseries.dt.to_period('M').dt.to_timestamp()
此方法的额外好处是支持许多其他频率下限,例如每周 ('W'
) 或工作日 ('B'
),使用矢量化方法实施起来会比较棘手以上。
您可以找到其他各种频率的缩写 in the relevant doc page。
这当然假设dtseries
是一个日期时间系列,如果不是,你可以很容易地用pd.to_datetime(my_series)
转换它。
该解决方案还允许在使用各种偏移量方面具有极大的灵活性。例如,要使用该月的第十天:
from pandas.tseries.offsets import DateOffset
dtseries.dt.to_period('M').dt.to_timestamp() + DateOffset(days=10)
我建议您查看 doc for pandas offsets。偏移量 pandas 提供了很多相当复杂的偏移量支持,例如工作日、假期、营业时间等......正如@KyleBarron 和@JonClements 的回答所建议的那样,手动实现这些将非常麻烦.例如,考虑这个例子,让日期从月初开始偏移 5 个工作日:
from pandas.tseries.offsets import BusinessDay
dtseries.dt.to_period('M').dt.to_timestamp() + BusinessDay(n=5)
我有一个 datetime
系列,需要将每个条目的日期更改为 1
。我想过很多简单的解决方案,但 none 对我有用。目前,唯一真正有效的是
- 设置系列为索引
- 从索引中查询月份和年份
- 使用年、月和 1 重建一个新的时间序列
真的不会那么复杂吧?有月开始,但不幸的是 offset
,这在这里没有用。该方法似乎没有 set()
功能,当系列是一列而不是索引本身(的一部分)时,功能甚至更少。
唯一相关的问题是 this,但此处使用的技巧不适用于此处。
您可以使用.apply
和datetime.replace
,例如:
import pandas as pd
from datetime import datetime
ps = pd.Series([datetime(2014, 1, 7), datetime(2014, 3, 13), datetime(2014, 6, 12)])
new = ps.apply(lambda dt: dt.replace(day=1))
给出:
0 2014-01-01
1 2014-03-01
2 2014-06-01
dtype: datetime64[ns]
另一个答案有效,但任何时候您使用 apply
,您的代码都会变慢 很多。通过为系列编写快速矢量化日期时间替换,我能够获得 8.5 倍的加速。
def vec_dt_replace(series, year=None, month=None, day=None):
return pd.to_datetime(
{'year': series.dt.year if year is None else year,
'month': series.dt.month if month is None else month,
'day': series.dt.day if day is None else day})
申请:
%timeit dtseries.apply(lambda dt: dt.replace(day=1))
# 4.17 s ± 38.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
矢量化:
%timeit vec_dt_replace(dtseries, day=1)
# 491 ms ± 6.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
请注意,尝试将日期更改为不存在的日期可能会遇到错误,例如尝试将 2012-02-29 更改为 2013-02-29。使用 pd.to_datetime
的 errors
参数来忽略或强制它们。
数据生成:生成具有 100 万个随机日期的序列:
import pandas as pd
import numpy as np
# Generate random dates. Modified from:
def pp(start, end, n):
start_u = start.value // 10 ** 9
end_u = end.value // 10 ** 9
return pd.Series(
(10 ** 9 * np.random.randint(start_u, end_u, n)).view('M8[ns]'))
start = pd.to_datetime('2015-01-01')
end = pd.to_datetime('2018-01-01')
dtseries = pp(start, end, 1000000)
# Remove time component
dtseries = dtseries.dt.normalize()
其他两个答案有效,但既不优雅也不符合 pandas
库的精神。相反,请考虑这个,在我的测试中,它也比 Kyle Barron 的矢量化答案快一点。它是一个不需要定义任何外部函数的单行代码,经过矢量化处理,并保持在 pandas
生态系统中:
import pandas as pd
dtseries.dt.to_period('M').dt.to_timestamp()
此方法的额外好处是支持许多其他频率下限,例如每周 ('W'
) 或工作日 ('B'
),使用矢量化方法实施起来会比较棘手以上。
您可以找到其他各种频率的缩写 in the relevant doc page。
这当然假设dtseries
是一个日期时间系列,如果不是,你可以很容易地用pd.to_datetime(my_series)
转换它。
该解决方案还允许在使用各种偏移量方面具有极大的灵活性。例如,要使用该月的第十天:
from pandas.tseries.offsets import DateOffset
dtseries.dt.to_period('M').dt.to_timestamp() + DateOffset(days=10)
我建议您查看 doc for pandas offsets。偏移量 pandas 提供了很多相当复杂的偏移量支持,例如工作日、假期、营业时间等......正如@KyleBarron 和@JonClements 的回答所建议的那样,手动实现这些将非常麻烦.例如,考虑这个例子,让日期从月初开始偏移 5 个工作日:
from pandas.tseries.offsets import BusinessDay
dtseries.dt.to_period('M').dt.to_timestamp() + BusinessDay(n=5)