从 Python(熊猫)中的日期列获取周开始日期(星期一)?
Posted
技术标签:
【中文标题】从 Python(熊猫)中的日期列获取周开始日期(星期一)?【英文标题】:Get week start date (Monday) from a date column in Python (pandas)? 【发布时间】:2015-03-15 08:42:00 【问题描述】:我已经看过很多关于如何使用日期字符串进行操作的帖子,但我正在为数据框列尝试一些东西,但到目前为止还没有任何运气。 我目前的方法是:从'myday'获取工作日,然后偏移到星期一。
df['myday'] is column of dates.
mydays = pd.DatetimeIndex(df['myday']).weekday
df['week_start'] = pd.DatetimeIndex(df['myday']) - pd.DateOffset(days=mydays)
但我明白了 TypeError:timedelta days 组件不支持的类型:numpy.ndarray
如何从 df 列获取周开始日期?
【问题讨论】:
【参考方案1】:from datetime import datetime, timedelta
# Convert column to pandas datetime equivalent
df['myday'] = pd.to_datetime(df['myday'])
# Create function to calculate Start Week date
week_start_date = lambda date: date - timedelta(days=date.weekday())
# Apply above function on DataFrame column
df['week_start_date'] = df['myday'].apply(week_start_date)
【讨论】:
【参考方案2】:虽然@knightofni's 和@Paul's 解决方案都有效,但我倾向于尽量避免在 Pandas 中使用 apply,因为与基于数组的方法相比,它通常非常慢。为了避免这种情况,在转换为日期时间列(通过pd.to_datetime
)后,我们可以修改基于工作日的方法,并通过直接转换将星期几转换为numpy timedelta64[D]:
df['week_start'] = df['myday'] - df['myday'].dt.weekday.astype('timedelta64[D]')
或将to_timedelta 用作@ribitskiyb suggested:
df['week_start'] = df['myday'] - pd.to_timedelta(df['myday'].dt.weekday, unit='D').
使用包含 60,000 个日期时间的测试数据,我使用新发布的 Pandas 1.0.1 的建议答案得到了以下时间。
%timeit df.apply(lambda x: x['myday'] - datetime.timedelta(days=x['myday'].weekday()), axis=1)
>>> 1.33 s ± 28.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df['myday'].dt.to_period('W').apply(lambda r: r.start_time)
>>> 5.59 ms ± 138 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['myday'] - df['myday'].dt.weekday.astype('timedelta64[D]')
>>> 3.44 ms ± 106 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['myday'] - pd.to_timedelta(df['myday'].dt.weekday, unit='D')
>>> 3.47 ms ± 170 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
这些结果表明,Pandas 1.0.1 显着提高了基于 to_period 应用方法的速度(与 Pandas .astype('timedelta64[D]') 或使用 @ 987654331@ 仍然更胜一筹。基于这些结果,我建议继续使用pd.to_timedelta
。
【讨论】:
这是如何工作的?我的数据集中的 df['myday'].dt.weekday.astype('timedelta64[D]') 返回一系列全零。为什么或如何从 df['myday'] 中减去 0 起作用?这似乎是最好的解决方案。 澄清上面的帖子,我理解发生了什么的方式基本上是说取日期,然后从中减去星期几。但我不明白为什么 .astype('timedelta64[D]') 会导致全为零。 @DonQuixote 可能您的“我的一天”频率小于“1D”。那时这行不通。您必须修改它以减去小时、分钟等。【参考方案3】:它失败是因为 pd.DateOffset 需要一个整数作为参数(并且您正在为其提供一个数组)。您只能使用 DateOffset 将日期列更改相同的偏移量。
试试这个:
import datetime as dt
# Change 'myday' to contains dates as datetime objects
df['myday'] = pd.to_datetime(df['myday'])
# 'daysoffset' will container the weekday, as integers
df['daysoffset'] = df['myday'].apply(lambda x: x.weekday())
# We apply, row by row (axis=1) a timedelta operation
df['week_start'] = df.apply(lambda x: x['myday'] - dt.TimeDelta(days=x['daysoffset']), axis=1)
我还没有实际测试过这段代码(没有示例数据),但这应该适用于您所描述的内容。
但是,您可能想查看 pandas.Resample,它可能会提供更好的解决方案 - 取决于您正在寻找的确切内容。
【讨论】:
谢谢您的解释。这个解决方案正是我想要的!TimeDelta
不应该引用df['daysoffset']
吗?
使用 lambda 会导致速度变慢【参考方案4】:
(只是添加到n8yoder的答案)
使用.astype('timedelta64[D]')
对我来说似乎不太可读——找到了只使用 pandas 功能的替代方法:
df['myday'] - pd.to_timedelta(arg=df['myday'].dt.weekday, unit='D')
【讨论】:
我喜欢@Paul 的 lambda 表达式,但这个答案要快得多,而且同样“精练”。感谢您的解决方案。【参考方案5】:另一种选择:
df['week_start'] = df['myday'].dt.to_period('W').apply(lambda r: r.start_time)
这会将“week_start”设置为“myday”时间之前的第一个星期一。
【讨论】:
谢谢。df['myday'].dt.to_period('W').dt.start_time
可能比使用 apply
更快(不确定何时引入,可能不适用于旧版 pandas)以上是关于从 Python(熊猫)中的日期列获取周开始日期(星期一)?的主要内容,如果未能解决你的问题,请参考以下文章