目录
[2.1 pandas读取时的自动解析](#2.1 pandas读取时的自动解析)
[2.2 万能解析器:pd.to_datetime()](#2.2 万能解析器:pd.to_datetime())
[2.3 处理时区------别让夏令时坑了你](#2.3 处理时区——别让夏令时坑了你)
[3.1 核心概念:降采样 vs 升采样](#3.1 核心概念:降采样 vs 升采样)
[3.2 降采样实战:聚合为王](#3.2 降采样实战:聚合为王)
[3.3 升采样与缺失值填充](#3.3 升采样与缺失值填充)
[3.4 进阶技巧:偏移量与闭环控制](#3.4 进阶技巧:偏移量与闭环控制)
[4.1 问题描述](#4.1 问题描述)
[4.2 完整代码实现](#4.2 完整代码实现)
[5.1 5个常见错误及解决方案](#5.1 5个常见错误及解决方案)
[5.2 性能提升技巧](#5.2 性能提升技巧)
一、为什么时间序列处理如此重要?
在数据科学领域,时间序列数据无处不在------股票价格、电商销量、气象数据、用户行为日志......80%的真实数据分析任务都涉及时间序列。而日期解析与重采样,正是处理这类数据的"基本功"。
如果你还在手动处理日期格式、用循环做数据聚合,那么这篇文章或许会对你有所帮助。读完它,你将学会:一键解析各种乱七八糟的日期字符串、用3行代码完成按小时/天/月的数据聚合、处理缺失时间戳和异常值的高级技巧、性能优化的最佳实践。
二、日期解析:从混乱到规范
2.1 pandas读取时的自动解析
绝大多数时间序列问题,都始于读取CSV/Excel文件。pandas.read_csv()自带日期解析功能:
python
python
import pandas as pd
# 最基础用法:指定日期列
df = pd.read_csv('sales.csv', parse_dates=['order_date'])
# 高级用法:合并多列为日期
df = pd.read_csv('data.csv', parse_dates=[['year', 'month', 'day']])
真实案例:某电商的订单文件,日期分散在year、month、day三列,一行代码即可合并成year_month_day时间列。
2.2 万能解析器:pd.to_datetime()
这是处理日期字符串的瑞士军刀:
python
python
# 各种格式统统拿下
dates = ['2024-01-15', '2024/01/16', '01-17-2024', '2024.01.18']
pd.to_datetime(dates) # 全部转为Timestamp
# 处理带时间的字符串
pd.to_datetime('2024-01-15 14:30:00')
# 处理UNIX时间戳(秒/毫秒)
pd.to_datetime(1705300000, unit='s')
pd.to_datetime(1705300000000, unit='ms')
3个必知的参数
|--------|--------------------------|-----------------------|
| 参数 | 作用 | 示例 |
| format | 指定格式,速度提升5-10倍 | format='%Y-%m-%d' |
| errors | 处理错误:raise/coerce/ignore | errors='coerce'→转为NaT |
| utc | 转为UTC时区 | utc=True |
实战代码:
python
python
# 处理脏数据:将无法解析的转为缺失值
df['date_clean'] = pd.to_datetime(df['raw_date'],
format='%Y%m%d',
errors='coerce')
df = df.dropna(subset=['date_clean']) # 删除无效行
2.3 处理时区------别让夏令时坑了你
python
python
# 本地化无时区的时间戳
df['timestamp'] = df['timestamp'].dt.tz_localize('Asia/Shanghai')
# 转换时区
df['timestamp_utc'] = df['timestamp'].dt.tz_convert('UTC')
# 移除时区(转为naive)
df['timestamp_naive'] = df['timestamp'].dt.tz_localize(None)
三、重采样:改变时间的粒度
3.1 核心概念:降采样 vs 升采样
|-----|---------|-------|-------------|
| 类型 | 方向 | 数据量变化 | 典型场景 |
| 降采样 | 细粒度→粗粒度 | 减少 | 分钟级→日级,压缩存储 |
| 升采样 | 粗粒度→细粒度 | 增加 | 日级→小时级,填充缺失 |
3.2 降采样实战:聚合为王
假设我们有每分钟的传感器数据,要聚合成小时均值:
python
python
# 创建示例数据
import numpy as np
rng = pd.date_range('2024-01-01', periods=10080, freq='T') # 10080分钟 = 7天
df = pd.DataFrame({'value': np.random.randn(10080)}, index=rng)
# 降采样到小时(聚合方式:均值)
df_hourly = df.resample('H').mean()
# 多种聚合一次搞定
df_hourly = df.resample('H').agg(['mean', 'max', 'min', 'std'])
# 不同列用不同聚合方法
df.resample('H').agg({
'temperature': 'mean',
'humidity': 'max',
'wind_speed': 'median'
})
常用的重采样频率代码
|-------|-----|------|-----|
| 频率代码 | 含义 | 频率代码 | 含义 |
| T或min | 分钟 | H | 小时 |
| D | 日历日 | W | 周 |
| M | 月末 | Q | 季末 |
| A或Y | 年末 | B | 工作日 |
3.3 升采样与缺失值填充
将日数据升采样到小时,必然产生空缺,需要填充策略:
python
python
# 创建日数据
daily = pd.DataFrame({'sales': [100, 200, 150]},
index=pd.date_range('2024-01-01', periods=3, freq='D'))
# 升采样到小时
hourly = daily.resample('H').asfreq() # 全是NaN
# 各种填充方法
methods = {
'ffill': hourly.ffill(), # 用前一值填充(前向填充)
'bfill': hourly.bfill(), # 用后一值填充(后向填充)
'interpolate': hourly.interpolate(), # 线性插值
'fillna(0)': hourly.fillna(0) # 固定值填充
}
实际业务场景:销量数据升采样,用ffill假设价格不变;气温升采样用interpolate更合理。
3.4 进阶技巧:偏移量与闭环控制
python
python
# 重采样时指定标签位置
df.resample('W', label='left').mean() # 用周一作为标签
df.resample('W', label='right').mean() # 用周日作为标签
# 闭环:左闭右开 vs 双闭
df.resample('H', closed='left').mean() # [00:00, 01:00)
df.resample('H', closed='right').mean() # (00:00, 01:00]
四、实战案例:电商销售数据分析
4.1 问题描述
某店铺有3个月的订单明细(精确到秒),需要输出:
-
每日销售额趋势
-
每周的订单量波动
-
小时级别的流量高峰时段
4.2 完整代码实现
python
python
# 模拟数据
import pandas as pd
import numpy as np
np.random.seed(42)
dates = pd.date_range('2024-01-01', '2024-03-31 23:59:59', freq='min')
orders = pd.DataFrame({
'order_time': np.random.choice(dates, size=5000),
'amount': np.random.uniform(10, 500, 5000).round(2)
})
# 解析日期(这一步通常读数据时完成)
orders['order_time'] = pd.to_datetime(orders['order_time'])
orders.set_index('order_time', inplace=True)
# 任务1:每日销售额
daily_sales = orders.resample('D')['amount'].sum()
print("日均销售额:", daily_sales.mean().round(2))
# 任务2:每周订单量
weekly_orders = orders.resample('W-MON').size() # 周一开始
print("周订单量波动(标准差):", weekly_orders.std().round(2))
# 任务3:小时级别高峰时段
hourly_volume = orders.resample('H').size()
peak_hour = hourly_volume.groupby(hourly_volume.index.hour).mean().idxmax()
print(f"高峰时段:{peak_hour}:00")
# 可视化(简略)
import matplotlib.pyplot as plt
daily_sales.plot(title='每日销售额趋势', figsize=(12,4))
plt.show()
五、避坑指南与性能优化
5.1 5个常见错误及解决方案
|------------------------------------------|----------------|-------------------------------------|
| 错误现象 | 根本原因 | 解决方案 |
| TypeError: Only valid with DatetimeIndex | 索引不是datetime类型 | df.index = pd.to_datetime(df.index) |
| 重采样结果全是NaN | 时间索引不连续 | 检查是否有大量缺失时间段 |
| 时区转换后时间错乱 | 忽略了夏令时 | 统一用UTC,展示时转换 |
| format指定后解析失败 | 格式字符串与数据不匹配 | 用%Y(四位数年)而非%y(两位数) |
| 内存爆炸 | 升采样产生天文数字行 | 先过滤时间范围,或改用xarray |
5.2 性能提升技巧
python
python
# 慢:循环处理每一天
for date in df.index:
do_something(df.loc[date])
# 快:向量化 + 重采样聚合
df.resample('D').apply(lambda x: custom_func(x))
# 解析日期时指定format,速度提升5-10倍
pd.to_datetime(df['date_str'], format='%Y%m%d') # 快
pd.to_datetime(df['date_str']) # 慢
# 大量数据使用engine='pyarrow'(pandas 2.0+)
pd.read_csv('big_file.csv', parse_dates=['date'], engine='pyarrow')
六、总结
-
日期解析:pd.to_datetime() + errors=coerce+ 指定format = 稳定高效
-
重采样:df.resample(freq).agg(func) ------ 降采样聚合,升采样填充
-
时区:存储用UTC,展示用本地时区
-
性能:向量化操作 > 循环,指定格式 > 自动推断
如果这篇文章对你有所收获,欢迎点赞、收藏、关注哦 !