活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

深入解析Pandas时间函数 从基础时间戳创建到高级时间序列分析全面掌握数据处理时间技巧提升数据分析效率解决实际工作中的时间问题

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-2 01:10:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在数据分析领域,时间序列数据是一种常见且重要的数据类型。无论是金融市场的股票价格、气象数据中的温度变化,还是网站访问量的日波动,时间序列数据都无处不在。Pandas作为Python数据分析的核心库,提供了强大而灵活的时间函数工具集,使我们能够高效地处理和分析时间序列数据。

本文将深入探讨Pandas中的时间函数,从基础的时间戳创建到高级的时间序列分析技术,帮助读者全面掌握数据处理中的时间技巧,提升数据分析效率,并解决实际工作中遇到的时间相关问题。

基础时间戳创建

什么是时间戳

在Pandas中,Timestamp对象是时间数据的基本单位,它表示一个特定的时间点。Timestamp是Python标准库中datetime.datetime的子类,但提供了更多的功能和更好的性能。

创建时间戳

最简单的创建时间戳的方法是使用字符串:
  1. import pandas as pd
  2. # 从字符串创建时间戳
  3. ts1 = pd.Timestamp('2023-01-01')
  4. print(ts1)  # 输出: 2023-01-01 00:00:00
  5. ts2 = pd.Timestamp('2023/01/01 10:30:45')
  6. print(ts2)  # 输出: 2023-01-01 10:30:45
  7. ts3 = pd.Timestamp('Jan 01, 2023')
  8. print(ts3)  # 输出: 2023-01-01 00:00:00
复制代码

也可以使用数值(Unix时间戳)来创建时间戳:
  1. # 使用Unix时间戳创建时间戳(秒)
  2. ts4 = pd.Timestamp(1672531200)  # 2023-01-01 00:00:00的Unix时间戳
  3. print(ts4)  # 输出: 2023-01-01 00:00:00
  4. # 使用Unix时间戳创建时间戳(毫秒)
  5. ts5 = pd.Timestamp(1672531200000, unit='ms')
  6. print(ts5)  # 输出: 2023-01-01 00:00:00
复制代码
  1. from datetime import datetime
  2. # 使用datetime对象创建时间戳
  3. dt = datetime(2023, 1, 1, 10, 30, 45)
  4. ts6 = pd.Timestamp(dt)
  5. print(ts6)  # 输出: 2023-01-01 10:30:45
复制代码

时间戳的属性和方法

Timestamp对象有许多有用的属性和方法:
  1. ts = pd.Timestamp('2023-01-01 10:30:45')
  2. # 基本属性
  3. print(ts.year)       # 输出: 2023
  4. print(ts.month)      # 输出: 1
  5. print(ts.day)        # 输出: 1
  6. print(ts.hour)       # 输出: 10
  7. print(ts.minute)     # 输出: 30
  8. print(ts.second)     # 输出: 45
  9. # 星期相关
  10. print(ts.dayofweek)  # 输出: 6 (星期日,0=星期一,6=星期日)
  11. print(ts.day_name()) # 输出: Sunday
  12. # 时间格式化
  13. print(ts.strftime('%Y-%m-%d %H:%M:%S'))  # 输出: 2023-01-01 10:30:45
  14. # 时间戳转换
  15. print(ts.to_pydatetime())  # 转换为Python的datetime对象
  16. print(ts.to_datetime64())  # 转换为numpy的datetime64对象
复制代码

时间索引和日期范围

创建日期范围

Pandas提供了date_range()函数,用于创建固定频率的日期范围:
  1. # 创建日期范围
  2. dates = pd.date_range('2023-01-01', '2023-01-10')
  3. print(dates)
  4. """
  5. 输出:
  6. DatetimeIndex(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04',
  7.                '2023-01-05', '2023-01-06', '2023-01-07', '2023-01-08',
  8.                '2023-01-09', '2023-01-10'],
  9.               dtype='datetime64[ns]', freq='D')
  10. """
  11. # 指定频率
  12. dates = pd.date_range('2023-01-01', periods=10, freq='D')  # 10天
  13. print(dates)
  14. dates = pd.date_range('2023-01-01', periods=5, freq='H')  # 5小时
  15. print(dates)
  16. dates = pd.date_range('2023-01-01', periods=5, freq='M')  # 5个月
  17. print(dates)
复制代码

时间索引

使用日期范围作为索引创建Series或DataFrame:
  1. # 创建带有时间索引的Series
  2. dates = pd.date_range('2023-01-01', periods=10, freq='D')
  3. ts = pd.Series(range(10), index=dates)
  4. print(ts)
  5. """
  6. 输出:
  7. 2023-01-01    0
  8. 2023-01-02    1
  9. 2023-01-03    2
  10. 2023-01-04    3
  11. 2023-01-05    4
  12. 2023-01-06    5
  13. 2023-01-07    6
  14. 2023-01-08    7
  15. 2023-01-09    8
  16. 2023-01-10    9
  17. Freq: D, dtype: int64
  18. """
  19. # 创建带有时间索引的DataFrame
  20. df = pd.DataFrame({
  21.     'value': range(10),
  22.     'category': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B']
  23. }, index=dates)
  24. print(df)
  25. """
  26. 输出:
  27.             value category
  28. 2023-01-01      0        A
  29. 2023-01-02      1        B
  30. 2023-01-03      2        A
  31. 2023-01-04      3        B
  32. 2023-01-05      4        A
  33. 2023-01-06      5        B
  34. 2023-01-07      6        A
  35. 2023-01-08      7        B
  36. 2023-01-09      8        A
  37. 2023-01-10      9        B
  38. """
复制代码

时间索引的操作
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=30, freq='D')
  3. ts = pd.Series(range(30), index=dates)
  4. # 通过日期字符串索引
  5. print(ts['2023-01-05'])  # 输出: 4
  6. # 通过年份和月份索引
  7. print(ts['2023-01'])  # 选择2023年1月的数据
  8. # 切片
  9. print(ts['2023-01-05':'2023-01-10'])
  10. """
  11. 输出:
  12. 2023-01-05    4
  13. 2023-01-06    5
  14. 2023-01-07    6
  15. 2023-01-08    7
  16. 2023-01-09    8
  17. 2023-01-10    9
  18. Freq: D, dtype: int64
  19. """
复制代码
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=30, freq='D')
  3. ts = pd.Series(range(30), index=dates)
  4. # 时间索引的属性
  5. print(ts.index.year)      # 获取年份
  6. print(ts.index.month)     # 获取月份
  7. print(ts.index.day)       # 获取日
  8. print(ts.index.dayofweek) # 获取星期几 (0=星期一,6=星期日)
  9. print(ts.index.day_name()) # 获取星期名称
复制代码

时间序列数据操作

时间序列的创建和转换
  1. # 创建包含日期字符串的DataFrame
  2. df = pd.DataFrame({
  3.     'date': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05'],
  4.     'value': [10, 20, 30, 40, 50]
  5. })
  6. # 将日期字符串转换为时间戳
  7. df['date'] = pd.to_datetime(df['date'])
  8. print(df.dtypes)
  9. # 将日期列设置为索引
  10. df = df.set_index('date')
  11. print(df)
  12. """
  13. 输出:
  14.             value
  15. date            
  16. 2023-01-01     10
  17. 2023-01-02     20
  18. 2023-01-03     30
  19. 2023-01-04     40
  20. 2023-01-05     50
  21. """
复制代码
  1. # 创建包含不同格式日期的DataFrame
  2. df = pd.DataFrame({
  3.     'date': ['01/01/2023', '2023-01-02', 'Jan 03, 2023', '20230104', '05-Jan-2023'],
  4.     'value': [10, 20, 30, 40, 50]
  5. })
  6. # 转换日期
  7. df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)
  8. print(df)
  9. """
  10. 输出:
  11.         date  value
  12. 0 2023-01-01     10
  13. 1 2023-01-02     20
  14. 2 2023-01-03     30
  15. 3 2023-01-04     40
  16. 4 2023-01-05     50
  17. """
复制代码

时间序列的移动和偏移
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=5, freq='D')
  3. ts = pd.Series(range(5), index=dates)
  4. # 向前移动1天
  5. print(ts.shift(1))
  6. """
  7. 输出:
  8. 2023-01-01    NaN
  9. 2023-01-02    0.0
  10. 2023-01-03    1.0
  11. 2023-01-04    2.0
  12. 2023-01-05    3.0
  13. Freq: D, dtype: float64
  14. """
  15. # 向后移动1天
  16. print(ts.shift(-1))
  17. """
  18. 输出:
  19. 2023-01-01    1.0
  20. 2023-01-02    2.0
  21. 2023-01-03    3.0
  22. 2023-01-04    4.0
  23. 2023-01-05    NaN
  24. Freq: D, dtype: float64
  25. """
  26. # 使用时间频率进行移动
  27. print(ts.shift(1, freq='D'))  # 向后移动1天
  28. print(ts.shift(1, freq='W'))  # 向后移动1周
复制代码
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=5, freq='D')
  3. ts = pd.Series(range(5), index=dates)
  4. # 计算时间差值
  5. diff = ts.diff()
  6. print(diff)
  7. """
  8. 输出:
  9. 2023-01-01    NaN
  10. 2023-01-02    1.0
  11. 2023-01-03    1.0
  12. 2023-01-04    1.0
  13. 2023-01-05    1.0
  14. Freq: D, dtype: float64
  15. """
  16. # 计算百分比变化
  17. pct_change = ts.pct_change()
  18. print(pct_change)
  19. """
  20. 输出:
  21. 2023-01-01         NaN
  22. 2023-01-02         inf
  23. 2023-01-03    1.000000
  24. 2023-01-04    0.500000
  25. 2023-01-05    0.333333
  26. Freq: D, dtype: float64
  27. """
复制代码

时间序列的重采样和频率转换

重采样是指将时间序列从一个频率转换到另一个频率的过程。这包括降采样(从高频率到低频率,如从日到月)和升采样(从低频率到高频率,如从月到日)。
  1. # 创建示例时间序列(日频率)
  2. dates = pd.date_range('2023-01-01', periods=30, freq='D')
  3. ts = pd.Series(range(30), index=dates)
  4. # 降采样:从日到周,计算每周的平均值
  5. weekly_mean = ts.resample('W').mean()
  6. print(weekly_mean)
  7. """
  8. 输出:
  9. 2023-01-01     3.0
  10. 2023-01-08    10.5
  11. 2023-01-15    17.5
  12. 2023-01-22    24.5
  13. 2023-01-29    28.0
  14. Freq: W-SUN, dtype: float64
  15. """
  16. # 降采样:从日到月,计算每月的总和
  17. monthly_sum = ts.resample('M').sum()
  18. print(monthly_sum)
  19. """
  20. 输出:
  21. 2023-01-31    435
  22. Freq: M, dtype: int64
  23. """
  24. # 升采样:从日到小时,使用前向填充
  25. hourly = ts.resample('H').ffill()
  26. print(hourly.head(10))
  27. """
  28. 输出:
  29. 2023-01-01 00:00:00    0
  30. 2023-01-01 01:00:00    0
  31. 2023-01-01 02:00:00    0
  32. 2023-01-01 03:00:00    0
  33. 2023-01-01 04:00:00    0
  34. 2023-01-01 05:00:00    0
  35. 2023-01-01 06:00:00    0
  36. 2023-01-01 07:00:00    0
  37. 2023-01-01 08:00:00    0
  38. 2023-01-01 09:00:00    0
  39. Freq: H, dtype: int64
  40. """
复制代码
  1. # 创建示例时间序列(日频率)
  2. dates = pd.date_range('2023-01-01', periods=5, freq='D')
  3. ts = pd.Series(range(5), index=dates)
  4. # 转换为工作日频率
  5. ts_business = ts.asfreq('B')
  6. print(ts_business)
  7. """
  8. 输出:
  9. 2023-01-02    1.0  # 2023-01-01是星期日,不是工作日
  10. 2023-01-03    2.0
  11. 2023-01-04    3.0
  12. 2023-01-05    4.0
  13. 2023-01-06    NaN
  14. Freq: B, dtype: float64
  15. """
  16. # 转换为小时频率,使用前向填充
  17. ts_hourly = ts.asfreq('H', method='ffill')
  18. print(ts_hourly.head(10))
  19. """
  20. 输出:
  21. 2023-01-01 00:00:00    0
  22. 2023-01-01 01:00:00    0
  23. 2023-01-01 02:00:00    0
  24. 2023-01-01 03:00:00    0
  25. 2023-01-01 04:00:00    0
  26. 2023-01-01 05:00:00    0
  27. 2023-01-01 06:00:00    0
  28. 2023-01-01 07:00:00    0
  29. 2023-01-01 08:00:00    0
  30. 2023-01-01 09:00:00    0
  31. Freq: H, dtype: int64
  32. """
复制代码

时间窗口操作

滚动窗口

滚动窗口计算是指在一个固定大小的窗口上应用统计函数,然后沿着时间轴移动窗口。这对于计算移动平均值、移动标准差等非常有用。
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=30, freq='D')
  3. ts = pd.Series(range(30), index=dates)
  4. # 计算滚动平均值(窗口大小为3)
  5. rolling_mean = ts.rolling(window=3).mean()
  6. print(rolling_mean.head(10))
  7. """
  8. 输出:
  9. 2023-01-01    NaN
  10. 2023-01-02    NaN
  11. 2023-01-03    1.0
  12. 2023-01-04    2.0
  13. 2023-01-05    3.0
  14. 2023-01-06    4.0
  15. 2023-01-07    5.0
  16. 2023-01-08    6.0
  17. 2023-01-09    7.0
  18. 2023-01-10    8.0
  19. Freq: D, dtype: float64
  20. """
  21. # 计算滚动标准差(窗口大小为5)
  22. rolling_std = ts.rolling(window=5).std()
  23. print(rolling_std.head(10))
  24. """
  25. 输出:
  26. 2023-01-01    NaN
  27. 2023-01-02    NaN
  28. 2023-01-03    NaN
  29. 2023-01-04    NaN
  30. 2023-01-05    1.581139
  31. 2023-01-06    1.581139
  32. 2023-01-07    1.581139
  33. 2023-01-08    1.581139
  34. 2023-01-09    1.581139
  35. 2023-01-10    1.581139
  36. Freq: D, dtype: float64
  37. """
  38. # 计算滚动最大值(窗口大小为7)
  39. rolling_max = ts.rolling(window=7).max()
  40. print(rolling_max.head(10))
  41. """
  42. 输出:
  43. 2023-01-01    NaN
  44. 2023-01-02    NaN
  45. 2023-01-03    NaN
  46. 2023-01-04    NaN
  47. 2023-01-05    NaN
  48. 2023-01-06    NaN
  49. 2023-01-07    6.0
  50. 2023-01-08    7.0
  51. 2023-01-09    8.0
  52. 2023-01-10    9.0
  53. Freq: D, dtype: float64
  54. """
复制代码

扩展窗口

扩展窗口是从序列的开始到当前点的窗口,窗口大小随着时间增长。
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=10, freq='D')
  3. ts = pd.Series(range(10), index=dates)
  4. # 计算扩展平均值
  5. expanding_mean = ts.expanding().mean()
  6. print(expanding_mean)
  7. """
  8. 输出:
  9. 2023-01-01    0.0
  10. 2023-01-02    0.5
  11. 2023-01-03    1.0
  12. 2023-01-04    1.5
  13. 2023-01-05    2.0
  14. 2023-01-06    2.5
  15. 2023-01-07    3.0
  16. 2023-01-08    3.5
  17. 2023-01-09    4.0
  18. 2023-01-10    4.5
  19. Freq: D, dtype: float64
  20. """
  21. # 计算扩展最大值
  22. expanding_max = ts.expanding().max()
  23. print(expanding_max)
  24. """
  25. 输出:
  26. 2023-01-01    0.0
  27. 2023-01-02    1.0
  28. 2023-01-03    2.0
  29. 2023-01-04    3.0
  30. 2023-01-05    4.0
  31. 2023-01-06    5.0
  32. 2023-01-07    6.0
  33. 2023-01-08    7.0
  34. 2023-01-09    8.0
  35. 2023-01-10    9.0
  36. Freq: D, dtype: float64
  37. """
复制代码

指数加权窗口

指数加权窗口是一种给予近期数据更高权重的窗口方法。
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=10, freq='D')
  3. ts = pd.Series(range(10), index=dates)
  4. # 计算指数加权移动平均值
  5. ewm_mean = ts.ewm(span=3).mean()
  6. print(ewm_mean)
  7. """
  8. 输出:
  9. 2023-01-01    0.000000
  10. 2023-01-02    0.750000
  11. 2023-01-03    1.615385
  12. 2023-01-04    2.550000
  13. 2023-01-05    3.520661
  14. 2023-01-06    4.508197
  15. 2023-01-07    5.504098
  16. 2023-01-08    6.502049
  17. 2023-01-09    7.501024
  18. 2023-01-10    8.500512
  19. Freq: D, dtype: float64
  20. """
复制代码

时间序列可视化

可视化是理解时间序列数据的重要工具。Pandas与Matplotlib和Seaborn等可视化库集成良好,使我们能够轻松创建时间序列图表。

基本时间序列图
  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. # 创建示例时间序列
  4. dates = pd.date_range('2023-01-01', periods=100, freq='D')
  5. ts = pd.Series(np.random.randn(100).cumsum(), index=dates)
  6. # 绘制时间序列图
  7. plt.figure(figsize=(12, 6))
  8. ts.plot()
  9. plt.title('Time Series Plot')
  10. plt.xlabel('Date')
  11. plt.ylabel('Value')
  12. plt.grid(True)
  13. plt.show()
复制代码

多个时间序列的比较
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=100, freq='D')
  3. ts1 = pd.Series(np.random.randn(100).cumsum(), index=dates, name='Series 1')
  4. ts2 = pd.Series(np.random.randn(100).cumsum(), index=dates, name='Series 2')
  5. ts3 = pd.Series(np.random.randn(100).cumsum(), index=dates, name='Series 3')
  6. # 合并为DataFrame
  7. df = pd.concat([ts1, ts2, ts3], axis=1)
  8. # 绘制多个时间序列
  9. plt.figure(figsize=(12, 6))
  10. df.plot()
  11. plt.title('Multiple Time Series')
  12. plt.xlabel('Date')
  13. plt.ylabel('Value')
  14. plt.grid(True)
  15. plt.legend()
  16. plt.show()
复制代码

季节性分解图
  1. from statsmodels.tsa.seasonal import seasonal_decompose
  2. # 创建示例时间序列(带有趋势和季节性)
  3. dates = pd.date_range('2023-01-01', periods=365, freq='D')
  4. trend = np.linspace(0, 10, 365)
  5. seasonality = 5 * np.sin(np.linspace(0, 4*np.pi, 365))
  6. noise = np.random.randn(365) * 0.5
  7. ts = pd.Series(trend + seasonality + noise, index=dates)
  8. # 季节性分解
  9. decomposition = seasonal_decompose(ts, model='additive', period=7)
  10. # 绘制分解结果
  11. plt.figure(figsize=(12, 10))
  12. plt.subplot(411)
  13. plt.plot(ts, label='Original')
  14. plt.legend()
  15. plt.subplot(412)
  16. plt.plot(decomposition.trend, label='Trend')
  17. plt.legend()
  18. plt.subplot(413)
  19. plt.plot(decomposition.seasonal, label='Seasonality')
  20. plt.legend()
  21. plt.subplot(414)
  22. plt.plot(decomposition.resid, label='Residuals')
  23. plt.legend()
  24. plt.tight_layout()
  25. plt.show()
复制代码

滚动统计量图
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=100, freq='D')
  3. ts = pd.Series(np.random.randn(100).cumsum(), index=dates)
  4. # 计算滚动统计量
  5. rolling_mean = ts.rolling(window=10).mean()
  6. rolling_std = ts.rolling(window=10).std()
  7. # 绘制原始数据和滚动统计量
  8. plt.figure(figsize=(12, 6))
  9. plt.plot(ts, label='Original')
  10. plt.plot(rolling_mean, label='Rolling Mean (window=10)')
  11. plt.plot(rolling_std, label='Rolling Std (window=10)')
  12. plt.title('Rolling Statistics')
  13. plt.xlabel('Date')
  14. plt.ylabel('Value')
  15. plt.grid(True)
  16. plt.legend()
  17. plt.show()
复制代码

实际案例分析

案例1:股票价格分析
  1. # 假设我们有一只股票的日交易数据
  2. dates = pd.date_range('2023-01-01', periods=100, freq='D')
  3. prices = np.random.normal(100, 5, 100).cumsum()
  4. volumes = np.random.randint(1000, 10000, 100)
  5. # 创建DataFrame
  6. stock_data = pd.DataFrame({
  7.     'Price': prices,
  8.     'Volume': volumes
  9. }, index=dates)
  10. # 计算移动平均线
  11. stock_data['MA5'] = stock_data['Price'].rolling(window=5).mean()
  12. stock_data['MA20'] = stock_data['Price'].rolling(window=20).mean()
  13. # 计算每日收益率
  14. stock_data['Daily_Return'] = stock_data['Price'].pct_change()
  15. # 计算波动率(滚动标准差)
  16. stock_data['Volatility'] = stock_data['Daily_Return'].rolling(window=20).std()
  17. # 绘制价格和移动平均线
  18. plt.figure(figsize=(12, 6))
  19. plt.plot(stock_data['Price'], label='Price')
  20. plt.plot(stock_data['MA5'], label='MA5')
  21. plt.plot(stock_data['MA20'], label='MA20')
  22. plt.title('Stock Price with Moving Averages')
  23. plt.xlabel('Date')
  24. plt.ylabel('Price')
  25. plt.grid(True)
  26. plt.legend()
  27. plt.show()
  28. # 绘制波动率
  29. plt.figure(figsize=(12, 6))
  30. plt.plot(stock_data['Volatility'])
  31. plt.title('Stock Price Volatility (20-day rolling)')
  32. plt.xlabel('Date')
  33. plt.ylabel('Volatility')
  34. plt.grid(True)
  35. plt.show()
复制代码

案例2:网站流量分析
  1. # 假设我们有网站的每小时访问量数据
  2. dates = pd.date_range('2023-01-01', periods=24*30, freq='H')  # 30天的小时数据
  3. # 模拟流量数据:工作日流量高,周末流量低;白天流量高,夜间流量低
  4. hourly_pattern = np.sin(np.linspace(0, 2*np.pi, 24)) * 50 + 100  # 一天内的流量模式
  5. daily_pattern = np.tile(hourly_pattern, 30)  # 重复30天
  6. weekend_effect = np.zeros(24*30)
  7. for i in range(30):
  8.     if i % 7 >= 5:  # 周末
  9.         weekend_effect[i*24:(i+1)*24] = -30  # 周末流量减少
  10. traffic = daily_pattern + weekend_effect + np.random.randn(24*30) * 10  # 添加噪声
  11. traffic = np.maximum(traffic, 0)  # 确保流量非负
  12. # 创建DataFrame
  13. traffic_data = pd.DataFrame({
  14.     'Traffic': traffic
  15. }, index=dates)
  16. # 按天重采样,计算每日总流量
  17. daily_traffic = traffic_data.resample('D').sum()
  18. # 按周重采样,计算每周平均流量
  19. weekly_traffic = traffic_data.resample('W').mean()
  20. # 计算滚动平均值(24小时窗口)
  21. rolling_traffic = traffic_data['Traffic'].rolling(window=24).mean()
  22. # 绘制原始流量数据(前7天)
  23. plt.figure(figsize=(12, 6))
  24. traffic_data['Traffic'][:24*7].plot()
  25. plt.title('Hourly Website Traffic (First Week)')
  26. plt.xlabel('Date')
  27. plt.ylabel('Traffic')
  28. plt.grid(True)
  29. plt.show()
  30. # 绘制每日总流量
  31. plt.figure(figsize=(12, 6))
  32. daily_traffic.plot()
  33. plt.title('Daily Website Traffic')
  34. plt.xlabel('Date')
  35. plt.ylabel('Traffic')
  36. plt.grid(True)
  37. plt.show()
  38. # 绘制滚动平均值
  39. plt.figure(figsize=(12, 6))
  40. rolling_traffic.plot()
  41. plt.title('24-hour Rolling Average of Website Traffic')
  42. plt.xlabel('Date')
  43. plt.ylabel('Traffic')
  44. plt.grid(True)
  45. plt.show()
复制代码

案例3:销售数据分析
  1. # 假设我们有产品的日销售数据
  2. dates = pd.date_range('2022-01-01', periods=365*2, freq='D')  # 2年的日数据
  3. # 模拟销售数据:有年度增长趋势,有季节性(年末销售高),有周效应(周末销售高)
  4. trend = np.linspace(100, 300, 365*2)  # 年度增长趋势
  5. seasonality = 50 * np.sin(np.linspace(0, 4*np.pi, 365*2))  # 年度季节性
  6. weekly_effect = np.zeros(365*2)
  7. for i in range(365*2):
  8.     if i % 7 >= 5:  # 周末
  9.         weekly_effect[i] = 30  # 周末销售增加
  10. sales = trend + seasonality + weekly_effect + np.random.randn(365*2) * 20  # 添加噪声
  11. sales = np.maximum(sales, 0)  # 确保销售量非负
  12. # 创建DataFrame
  13. sales_data = pd.DataFrame({
  14.     'Sales': sales
  15. }, index=dates)
  16. # 按月重采样,计算每月总销售量
  17. monthly_sales = sales_data.resample('M').sum()
  18. # 按年重采样,计算每年总销售量
  19. yearly_sales = sales_data.resample('Y').sum()
  20. # 计算同比增长率(与去年同期相比)
  21. year_over_year = monthly_sales / monthly_sales.shift(12) - 1
  22. # 计算滚动平均值(30天窗口)
  23. rolling_sales = sales_data['Sales'].rolling(window=30).mean()
  24. # 绘制原始销售数据
  25. plt.figure(figsize=(12, 6))
  26. sales_data['Sales'].plot()
  27. plt.title('Daily Sales')
  28. plt.xlabel('Date')
  29. plt.ylabel('Sales')
  30. plt.grid(True)
  31. plt.show()
  32. # 绘制月度销售量
  33. plt.figure(figsize=(12, 6))
  34. monthly_sales.plot(kind='bar')
  35. plt.title('Monthly Sales')
  36. plt.xlabel('Date')
  37. plt.ylabel('Sales')
  38. plt.grid(True)
  39. plt.show()
  40. # 绘制同比增长率
  41. plt.figure(figsize=(12, 6))
  42. year_over_year.plot()
  43. plt.title('Year-over-Year Growth Rate')
  44. plt.xlabel('Date')
  45. plt.ylabel('Growth Rate')
  46. plt.grid(True)
  47. plt.axhline(y=0, color='r', linestyle='-')
  48. plt.show()
复制代码

性能优化和最佳实践

使用适当的数据类型

Pandas提供了专门的时间数据类型,使用它们可以提高性能:
  1. # 创建大型时间序列数据集
  2. dates = pd.date_range('2000-01-01', periods=1000000, freq='H')
  3. values = np.random.randn(1000000)
  4. # 使用datetime64[ns]类型(默认)
  5. df_default = pd.DataFrame({'value': values}, index=dates)
  6. print(df_default.index.dtype)  # 输出: datetime64[ns]
  7. # 使用datetime64[s]类型(秒精度)
  8. df_seconds = df_default.copy()
  9. df_seconds.index = df_seconds.index.astype('datetime64[s]')
  10. print(df_seconds.index.dtype)  # 输出: datetime64[s]
  11. # 使用datetime64[ms]类型(毫秒精度)
  12. df_milliseconds = df_default.copy()
  13. df_milliseconds.index = df_milliseconds.index.astype('datetime64[ms]')
  14. print(df_milliseconds.index.dtype)  # 输出: datetime64[ms]
  15. # 比较内存使用
  16. print(f"Default: {df_default.index.memory_usage() / 1024 / 1024:.2f} MB")
  17. print(f"Seconds: {df_seconds.index.memory_usage() / 1024 / 1024:.2f} MB")
  18. print(f"Milliseconds: {df_milliseconds.index.memory_usage() / 1024 / 1024:.2f} MB")
复制代码

避免循环,使用向量化操作

在处理时间序列数据时,应尽量避免使用循环,而是使用Pandas提供的向量化操作:
  1. # 创建示例时间序列
  2. dates = pd.date_range('2023-01-01', periods=10000, freq='D')
  3. ts = pd.Series(range(10000), index=dates)
  4. # 不好的方法:使用循环计算移动平均
  5. def rolling_mean_loop(ts, window):
  6.     result = pd.Series(index=ts.index, dtype=float)
  7.     for i in range(window-1, len(ts)):
  8.         result.iloc[i] = ts.iloc[i-window+1:i+1].mean()
  9.     return result
  10. %timeit rolling_mean_loop(ts, 10)  # 测量执行时间
  11. # 好的方法:使用内置的rolling函数
  12. %timeit ts.rolling(window=10).mean()  # 测量执行时间
复制代码

使用分类数据类型处理重复的时间属性

当处理时间序列数据时,年、月、日、星期等属性经常重复出现,使用分类数据类型可以节省内存:
  1. # 创建大型时间序列数据集
  2. dates = pd.date_range('2000-01-01', periods=1000000, freq='D')
  3. df = pd.DataFrame({'value': np.random.randn(1000000)}, index=dates)
  4. # 提取时间属性
  5. df['year'] = df.index.year
  6. df['month'] = df.index.month
  7. df['day'] = df.index.day
  8. df['weekday'] = df.index.day_name()
  9. # 检查内存使用
  10. print(f"Before: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB")
  11. # 转换为分类数据类型
  12. df['year'] = df['year'].astype('category')
  13. df['month'] = df['month'].astype('category')
  14. df['day'] = df['day'].astype('category')
  15. df['weekday'] = df['weekday'].astype('category')
  16. # 检查内存使用
  17. print(f"After: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB")
复制代码

使用适当的索引和排序

对于时间序列数据,确保时间索引是排序的可以提高查询和操作的性能:
  1. # 创建大型时间序列数据集
  2. dates = pd.date_range('2000-01-01', periods=1000000, freq='D')
  3. values = np.random.randn(1000000)
  4. df = pd.DataFrame({'value': values}, index=dates)
  5. # 打乱索引
  6. df_shuffled = df.sample(frac=1)
  7. # 测量查询性能
  8. %timeit df.loc['2010-01-01':'2010-01-31']  # 排序后的数据
  9. %timeit df_shuffled.loc['2010-01-01':'2010-01-31']  # 未排序的数据
  10. # 对未排序的数据进行排序
  11. df_shuffled_sorted = df_shuffled.sort_index()
  12. # 再次测量查询性能
  13. %timeit df_shuffled_sorted.loc['2010-01-01':'2010-01-31']  # 排序后的数据
复制代码

使用并行处理加速大型时间序列操作

对于非常大的时间序列数据集,可以考虑使用并行处理来加速操作:
  1. from multiprocessing import Pool
  2. import numpy as np
  3. # 创建大型时间序列数据集
  4. dates = pd.date_range('2000-01-01', periods=1000000, freq='D')
  5. ts = pd.Series(np.random.randn(1000000), index=dates)
  6. # 定义一个函数,用于处理时间序列的一部分
  7. def process_chunk(chunk):
  8.     return chunk.rolling(window=30).mean()
  9. # 将时间序列分成多个块
  10. n_chunks = 4
  11. chunks = np.array_split(ts, n_chunks)
  12. # 使用并行处理
  13. with Pool(n_chunks) as p:
  14.     results = p.map(process_chunk, chunks)
  15. # 合并结果
  16. result_parallel = pd.concat(results)
  17. # 比较串行处理
  18. %timeit ts.rolling(window=30).mean()
  19. # 比较并行处理
  20. %timeit with Pool(n_chunks) as p: results = p.map(process_chunk, chunks); result_parallel = pd.concat(results)
复制代码

总结

本文深入探讨了Pandas中的时间函数,从基础的时间戳创建到高级的时间序列分析技术。我们学习了如何创建和操作时间戳,如何使用时间索引和日期范围,如何对时间序列数据进行各种操作,如何进行时间重采样和频率转换,以及如何使用时间窗口操作。我们还探讨了时间序列的可视化方法,并通过实际案例展示了如何解决工作中的时间问题。最后,我们讨论了性能优化和最佳实践,以帮助我们更高效地处理时间序列数据。

通过掌握这些技术,我们可以更有效地处理和分析时间序列数据,从中提取有价值的信息,并做出更好的决策。无论是金融分析、销售预测、网站流量分析还是其他领域的时间序列问题,Pandas的时间函数都能提供强大的支持。

希望本文能够帮助读者全面掌握Pandas中的时间函数,提升数据分析效率,解决实际工作中的时间问题。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则