18. 日期时间处理 1. 概述 日期和时间数据在数据分析中非常常见,如订单时间、用户注册时间、日志时间戳等。Pandas 提供了强大的日期时间处理功能,支持日期解析、时间范围生成、日期提取、时间差计算等操作。
import pandasas pdimport numpyas np# 创建包含日期时间的示例数据 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' 将无效值转为 NaT df_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 日期加减 from pandas. tseries. offsetsimport DateOffset# 使用 DateOffset df[ '预计送达' ] = df[ '订单日期_dt' ] + pd. DateOffset( days= 3 ) print ( "预计送达日期:" ) print ( df[ [ '订单日期_dt' , '预计送达' ] ] ) # 使用 timedelta from datetimeimport timedelta 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 } ' for iin range ( 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( ) / 3600 print ( "\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. 常见日期格式代码 代码 说明 示例 %Y4位年 2024 %y2位年 24 %m2位月 01 %d2位日 15 %H24小时制 14 %I12小时制 02 %pAM/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.yeardt.hour/minute/second提取时间部分 df['time'].dt.hourdt.day_name()星期名称 df['date'].dt.day_name()dt.quarter季度 df['date'].dt.quarterdate1 - 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()