![]()
18. 日期时间处理
1. 概述
日期和时间数据在数据分析中非常常见,如订单时间、用户注册时间、日志时间戳等。Pandas 提供了强大的日期时间处理功能,支持日期解析、时间范围生成、日期提取、时间差计算等操作。
importpandasaspdimportnumpyasnp# 创建包含日期时间的示例数据df=pd.DataFrame({'订单号':['ORD001','ORD002','ORD003','ORD004','ORD005'],'订单日期':['2024-01-15','2024/02/20','2024年03月10日','15-04-2024','2024-05-25'],'下单时间':['2024-01-15 09:30:00','2024-02-20 14:15:00','2024-03-10 10:45:00','2024-04-15 16:20:00','2024-05-25 11:00:00'],'发货时间':['2024-01-16 10:00:00','2024-02-21 09:30:00','2024-03-12 14:00:00','2024-04-17 08:30:00','2024-05-26 15:00:00']})print("原始数据:")print(df)print("\n数据类型:")print(df.dtypes)
2. 日期时间类型转换
2.1 pd.to_datetime() 基础
# 单列转换df['订单日期_转换']=pd.to_datetime(df['订单日期'])print("订单日期转换结果:")print(df[['订单日期','订单日期_转换']])print(f"\n转换后类型:{df['订单日期_转换'].dtype}")# 处理多种格式df['下单时间_转换']=pd.to_datetime(df['下单时间'])print(f"\n下单时间类型:{df['下单时间_转换'].dtype}")
2.2 处理转换错误
# 创建包含无效日期的数据df_bad=pd.DataFrame({'日期':['2024-01-01','invalid','2024-01-03','not a date','2024-01-05']})print("原始数据:")print(df_bad)# errors='coerce' 将无效值转为 NaTdf_bad['日期_转换']=pd.to_datetime(df_bad['日期'],errors='coerce')print("\n转换结果(无效值变为 NaT):")print(df_bad)# 查看转换失败的记录invalid_dates=df_bad[df_bad['日期_转换'].isna()]print(f"\n转换失败的记录:{len(invalid_dates)}条")
2.3 指定日期格式
# 使用 format 参数指定格式,提高转换速度df_format=pd.DataFrame({'日期':['2024-01-15','2024-02-20','2024-03-10']})df_format['日期_转换']=pd.to_datetime(df_format['日期'],format='%Y-%m-%d')print("指定格式转换:")print(df_format)# 常见日期格式对照# %Y: 4位年, %y: 2位年# %m: 月, %d: 日# %H: 24小时, %I: 12小时, %p: AM/PM# %M: 分钟, %S: 秒
3. 日期时间属性提取
# 转换日期列df['订单日期_dt']=pd.to_datetime(df['订单日期'])df['下单时间_dt']=pd.to_datetime(df['下单时间'])# 提取日期各部分print("日期各部分:")print(f"年:{df['订单日期_dt'].dt.year}")print(f"月:{df['订单日期_dt'].dt.month}")print(f"日:{df['订单日期_dt'].dt.day}")print(f"星期几(数字):{df['订单日期_dt'].dt.dayofweek}")print(f"星期几(名称):{df['订单日期_dt'].dt.day_name()}")print(f"年中的第几天:{df['订单日期_dt'].dt.dayofyear}")print(f"季度:{df['订单日期_dt'].dt.quarter}")print(f"是否月末:{df['订单日期_dt'].dt.is_month_end}")# 提取时间各部分print("\n时间各部分:")print(f"小时:{df['下单时间_dt'].dt.hour}")print(f"分钟:{df['下单时间_dt'].dt.minute}")print(f"秒:{df['下单时间_dt'].dt.second}")
4. 时间差计算
# 计算发货时长df['发货时长']=df['发货时间_dt']-df['下单时间_dt']print("发货时长:")print(df[['订单号','下单时间','发货时间','发货时长']])# 提取时间差各部分print("\n时间差详情:")print(f"天数:{df['发货时长'].dt.days}")print(f"秒数部分:{df['发货时长'].dt.seconds}")print(f"总秒数:{df['发货时长'].dt.total_seconds()}")print(f"小时数:{df['发货时长'].dt.total_seconds()/3600:.1f}")
5. 日期偏移与滚动
5.1 日期加减
frompandas.tseries.offsetsimportDateOffset# 使用 DateOffsetdf['预计送达']=df['订单日期_dt']+pd.DateOffset(days=3)print("预计送达日期:")print(df[['订单日期_dt','预计送达']])# 使用 timedeltafromdatetimeimporttimedelta df['一周后']=df['订单日期_dt']+timedelta(days=7)print("\n一周后:")print(df[['订单日期_dt','一周后']])# 月份加减(处理月末边界)df['下个月']=df['订单日期_dt']+pd.DateOffset(months=1)print("\n下个月:")print(df[['订单日期_dt','下个月']])
5.2 日期移动(shift)
# 创建时间序列数据np.random.seed(42)ts=pd.DataFrame({'日期':pd.date_range('2024-01-01',periods=10,freq='D'),'销售额':np.random.randint(100,500,10)})# 计算环比ts['前一日销售额']=ts['销售额'].shift(1)ts['环比变化']=ts['销售额']-ts['前一日销售额']ts['环比增长率']=(ts['环比变化']/ts['前一日销售额']*100).round(2)print("销售环比分析:")print(ts)
6. 时间范围与重采样
6.1 生成日期范围
# 生成日期范围date_range=pd.date_range(start='2024-01-01',end='2024-01-10',freq='D')print("每日范围:")print(date_range)# 按小时生成date_range_hour=pd.date_range(start='2024-01-01',periods=10,freq='H')print("\n小时范围:")print(date_range_hour)# 按工作日生成date_range_business=pd.date_range(start='2024-01-01',periods=10,freq='B')print("\n工作日范围:")print(date_range_business)# 频率代码# D: 天, H: 小时, T: 分钟, S: 秒# B: 工作日, W: 周, M: 月末, MS: 月初# Q: 季末, QS: 季初, A: 年末, AS: 年初
6.2 重采样(resample)
# 创建分钟级数据np.random.seed(42)minutes_data=pd.DataFrame({'时间':pd.date_range('2024-01-01 09:00:00',periods=60,freq='T'),'值':np.random.randn(60).cumsum()})minutes_data.set_index('时间',inplace=True)print("原始分钟数据(前5行):")print(minutes_data.head())# 重采样为小时(取平均值)hourly_mean=minutes_data.resample('H').mean()print("\n小时均值:")print(hourly_mean)# 重采样为小时(取总和)hourly_sum=minutes_data.resample('H').sum()print("\n小时总和:")print(hourly_sum)# 多种聚合hourly_agg=minutes_data.resample('H').agg(['mean','max','min','std'])print("\n多种统计:")print(hourly_agg.head())
7. 滑动窗口计算
# 创建时间序列df_ts=pd.DataFrame({'日期':pd.date_range('2024-01-01',periods=30,freq='D'),'销售额':np.random.randint(100,300,30)})df_ts.set_index('日期',inplace=True)# 7日移动平均df_ts['MA7']=df_ts['销售额'].rolling(window=7).mean()# 7日移动总和df_ts['SUM7']=df_ts['销售额'].rolling(window=7).sum()# 扩展窗口(从开始到当前)df_ts['累计平均']=df_ts['销售额'].expanding().mean()print("滑动窗口计算:")print(df_ts.head(15))
8. 完整示例:电商订单分析
# 创建订单数据np.random.seed(42)orders=pd.DataFrame({'订单号':[f'ORD{i:05d}'foriinrange(1,101)],'下单时间':pd.date_range('2024-01-01 00:00:00',periods=100,freq='H'),'金额':np.random.uniform(50,1000,100).round(2),'状态':np.random.choice(['已完成','已取消','处理中'],100,p=[0.7,0.1,0.2])})# 添加随机发货时间orders['发货时间']=orders['下单时间']+pd.to_timedelta(np.random.randint(1,72,100),unit='h')orders.loc[orders['状态']=='已取消','发货时间']=pd.NaTprint("="*60)print("电商订单时间分析")print("="*60)# 1. 提取时间特征print("\n1. 时间特征提取:")orders['下单日期']=orders['下单时间'].dt.date orders['下单小时']=orders['下单时间'].dt.hour orders['下单星期']=orders['下单时间'].dt.day_name()orders['下单月份']=orders['下单时间'].dt.monthprint(orders[['订单号','下单时间','下单小时','下单星期']].head())# 2. 计算发货时长orders['发货时长(小时)']=(orders['发货时间']-orders['下单时间']).dt.total_seconds()/3600print("\n2. 发货时长统计:")print(orders[orders['状态']=='已完成']['发货时长(小时)'].describe())# 3. 按小时统计订单量print("\n3. 各小时订单量分布:")hourly_orders=orders.groupby('下单小时').size().sort_index()print(hourly_orders)# 4. 按星期统计销售额print("\n4. 各星期销售额:")weekday_sales=orders.groupby('下单星期')['金额'].sum().sort_values(ascending=False)print(weekday_sales)# 5. 日销售额趋势print("\n5. 日销售额趋势:")daily_sales=orders.set_index('下单时间').resample('D')['金额'].sum()print(daily_sales.head(10))# 6. 7日移动平均ma7=daily_sales.rolling(window=7).mean()print("\n6. 7日移动平均(前10天):")print(ma7.head(10))
9. 常见日期格式代码
| 代码 | 说明 | 示例 |
|---|
%Y | 4位年 | 2024 |
%y | 2位年 | 24 |
%m | 2位月 | 01 |
%d | 2位日 | 15 |
%H | 24小时制 | 14 |
%I | 12小时制 | 02 |
%p | AM/PM | PM |
%M | 分钟 | 30 |
%S | 秒 | 00 |
%f | 微秒 | 123456 |
%a | 缩写星期 | Mon |
%A | 完整星期 | Monday |
%b | 缩写月份 | Jan |
%B | 完整月份 | January |
10. 总结
| 方法 | 用途 | 示例 |
|---|
pd.to_datetime() | 转换为日期时间 | pd.to_datetime(df['col']) |
dt.year/month/day | 提取日期部分 | df['date'].dt.year |
dt.hour/minute/second | 提取时间部分 | df['time'].dt.hour |
dt.day_name() | 星期名称 | df['date'].dt.day_name() |
dt.quarter | 季度 | df['date'].dt.quarter |
date1 - date2 | 计算时间差 | df['end'] - df['start'] |
pd.DateOffset() | 日期偏移 | df['date'] + pd.DateOffset(days=7) |
shift() | 数据移动 | df['value'].shift(1) |
pd.date_range() | 生成日期范围 | pd.date_range('2024-01-01', periods=10) |
resample() | 重采样 | df.resample('D').mean() |
rolling() | 滚动窗口 | df.rolling(window=7).mean() |