活动公告

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

Pandas日期输出技巧详解 让你的时间数据分析更加高效精准

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

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

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

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

x
1. 引言

在数据分析和处理过程中,时间序列数据是非常常见的数据类型。无论是金融数据分析、销售趋势分析、网站流量分析还是传感器数据处理,时间序列数据都扮演着重要角色。Pandas作为Python数据分析的核心库,提供了强大而灵活的日期时间处理功能,掌握这些技巧可以大大提高时间数据分析的效率和准确性。

本文将详细介绍Pandas中日期时间的处理技巧,从基础的数据类型介绍到高级的时间序列操作,帮助读者全面掌握Pandas日期时间处理的精髓。

2. Pandas中日期时间数据类型

在Pandas中,主要有四种与日期时间相关的数据类型:

• datetime64[ns]: 精确到纳秒的时间戳数据类型
• timedelta[ns]: 时间差数据类型,表示两个时间点之间的差值
• period: 表示时间段的数据类型,如某天、某月、某季度等
• offset: 表示日期偏移量的数据类型

让我们首先了解如何创建这些类型的对象:
  1. import pandas as pd
  2. import numpy as np
  3. # 创建datetime64[ns]类型
  4. dates = pd.Series(pd.date_range('20230101', periods=5))
  5. print(dates)
  6. print(dates.dtype)
  7. # 创建timedelta类型
  8. timedeltas = pd.Series(pd.timedelta_range(start='1 day', periods=5, freq='D'))
  9. print(timedeltas)
  10. print(timedeltas.dtype)
  11. # 创建period类型
  12. periods = pd.Series(pd.period_range('2023-01-01', periods=5, freq='M'))
  13. print(periods)
  14. print(periods.dtype)
复制代码

3. 日期数据的创建和转换

3.1 从字符串创建日期时间对象

在实际数据处理中,我们经常需要将字符串格式的日期转换为Pandas的日期时间对象。Pandas提供了to_datetime()函数来完成这个任务:
  1. # 基本转换
  2. date_str = '2023-01-01'
  3. date_obj = pd.to_datetime(date_str)
  4. print(f"字符串 '{date_str}' 转换为日期时间对象: {date_obj}")
  5. # 处理不同格式的日期字符串
  6. date_formats = [
  7.     '01/01/2023',  # 月/日/年
  8.     '2023.01.01',  # 年.月.日
  9.     '01-Jan-2023', # 日-月-年
  10.     '20230101'     # 纯数字
  11. ]
  12. for fmt in date_formats:
  13.     date_obj = pd.to_datetime(fmt)
  14.     print(f"字符串 '{fmt}' 转换为日期时间对象: {date_obj}")
复制代码

3.2 批量转换日期数据

当处理包含日期字符串的DataFrame或Series时,我们可以批量转换:
  1. # 创建包含日期字符串的DataFrame
  2. df = pd.DataFrame({
  3.     'date_str': ['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_str'])
  8. print(df)
  9. print(df.dtypes)
  10. # 指定日期格式
  11. df['date_custom'] = pd.to_datetime(df['date_str'], format='%Y-%m-%d')
  12. print(df[['date_str', 'date', 'date_custom']])
复制代码

3.3 处理缺失值和错误日期

在转换日期时,我们经常会遇到缺失值或格式错误的日期:
  1. # 包含缺失值和错误日期的数据
  2. date_series = pd.Series(['2023-01-01', '2023-02-30', None, 'invalid_date', '2023-01-05'])
  3. # 默认情况下,错误日期会引发异常
  4. try:
  5.     pd.to_datetime(date_series)
  6. except ValueError as e:
  7.     print(f"错误: {e}")
  8. # 使用errors参数处理错误日期
  9. date_series_clean = pd.to_datetime(date_series, errors='coerce')  # 将错误日期转为NaT
  10. print(date_series_clean)
  11. # 使用errors='ignore'保留原始值
  12. date_series_ignore = pd.to_datetime(date_series, errors='ignore')
  13. print(date_series_ignore)
复制代码

4. 日期数据的格式化输出

4.1 基本日期格式化

Pandas提供了多种方法来格式化日期输出:
  1. # 创建日期Series
  2. dates = pd.Series(pd.date_range('20230101', periods=5))
  3. # 使用strftime方法格式化日期
  4. dates_formatted = dates.dt.strftime('%Y-%m-%d')
  5. print("基本日期格式化:")
  6. print(dates_formatted)
  7. # 不同格式的日期输出
  8. formats = {
  9.     'YYYY-MM-DD': '%Y-%m-%d',
  10.     'DD/MM/YYYY': '%d/%m/%Y',
  11.     'Month Day, Year': '%B %d, %Y',
  12.     'Weekday, Month Day, Year': '%A, %B %d, %Y',
  13.     'YYYYMMDD': '%Y%m%d'
  14. }
  15. for name, fmt in formats.items():
  16.     print(f"{name}: {dates.dt.strftime(fmt).tolist()}")
复制代码

4.2 提取日期组件

我们可以从日期对象中提取各种组件:
  1. # 创建日期Series
  2. dates = pd.Series(pd.date_range('20230101', periods=5))
  3. # 提取日期组件
  4. date_components = pd.DataFrame({
  5.     'year': dates.dt.year,
  6.     'month': dates.dt.month,
  7.     'day': dates.dt.day,
  8.     'hour': dates.dt.hour,
  9.     'minute': dates.dt.minute,
  10.     'second': dates.dt.second,
  11.     'weekday': dates.dt.dayofweek,  # 0=Monday, 6=Sunday
  12.     'day_name': dates.dt.day_name(),
  13.     'month_name': dates.dt.month_name(),
  14.     'quarter': dates.dt.quarter,
  15.     'is_month_start': dates.dt.is_month_start,
  16.     'is_month_end': dates.dt.is_month_end,
  17.     'is_quarter_start': dates.dt.is_quarter_start,
  18.     'is_quarter_end': dates.dt.is_quarter_end,
  19.     'is_year_start': dates.dt.is_year_start,
  20.     'is_year_end': dates.dt.is_year_end,
  21.     'is_leap_year': dates.dt.is_leap_year
  22. })
  23. print("日期组件:")
  24. print(date_components)
复制代码

4.3 自定义日期格式

有时候我们需要更灵活的日期格式化方式:
  1. # 创建日期Series
  2. dates = pd.Series(pd.date_range('20230101', periods=5))
  3. # 自定义格式化函数
  4. def custom_date_format(dt):
  5.     """自定义日期格式化函数"""
  6.     return f"{dt.day_name()[:3]}, {dt.month_name()[:3]} {dt.day}, {dt.year}"
  7. # 应用自定义格式化
  8. custom_formatted = dates.apply(custom_date_format)
  9. print("自定义日期格式:")
  10. print(custom_formatted)
  11. # 使用lambda函数进行自定义格式化
  12. lambda_formatted = dates.apply(lambda x: f"{x.year}年{x.month}月{x.day}日")
  13. print("中文日期格式:")
  14. print(lambda_formatted)
复制代码

5. 时间序列数据的筛选和操作

5.1 基于日期的筛选

处理时间序列数据时,经常需要根据日期范围筛选数据:
  1. # 创建时间序列DataFrame
  2. date_rng = pd.date_range(start='2023-01-01', end='2023-01-31', freq='D')
  3. df = pd.DataFrame({
  4.     'date': date_rng,
  5.     'value': np.random.randint(0, 100, size=(len(date_rng)))
  6. })
  7. # 设置日期为索引
  8. df.set_index('date', inplace=True)
  9. # 筛选特定日期的数据
  10. specific_date = df.loc['2023-01-15']
  11. print("特定日期的数据:")
  12. print(specific_date)
  13. # 筛选日期范围的数据
  14. date_range_data = df.loc['2023-01-10':'2023-01-20']
  15. print("\n日期范围的数据:")
  16. print(date_range_data)
  17. # 使用between_time筛选特定时间范围内的数据
  18. df_with_time = df.copy()
  19. df_with_time.index = pd.date_range(start='2023-01-01', periods=len(df), freq='H')
  20. morning_data = df_with_time.between_time('06:00', '12:00')
  21. print("\n早上6点到12点的数据:")
  22. print(morning_data.head())
复制代码

5.2 日期运算

Pandas支持对日期进行各种运算:
  1. # 创建日期Series
  2. dates = pd.Series(pd.date_range('20230101', periods=5))
  3. # 日期加减
  4. dates_plus_1_day = dates + pd.Timedelta(days=1)
  5. dates_minus_1_week = dates - pd.Timedelta(weeks=1)
  6. print("原始日期:")
  7. print(dates)
  8. print("\n加1天:")
  9. print(dates_plus_1_day)
  10. print("\n减1周:")
  11. print(dates_minus_1_week)
  12. # 日期之间的差值
  13. date_diff = dates.diff()
  14. print("\n日期之间的差值:")
  15. print(date_diff)
  16. # 计算两个日期之间的工作日
  17. from pandas.tseries.offsets import BDay
  18. dates_plus_5_business_days = dates + BDay(5)
  19. print("\n加5个工作日:")
  20. print(dates_plus_5_business_days)
复制代码

5.3 日期偏移和滚动

Pandas提供了丰富的日期偏移和滚动功能:
  1. # 创建日期Series
  2. dates = pd.Series(pd.date_range('20230101', periods=5))
  3. # 使用DateOffset进行日期偏移
  4. dates_month_start = dates + pd.DateOffset(months=1, day=1)
  5. print("下个月的第一天:")
  6. print(dates_month_start)
  7. # 使用MonthEnd获取月末
  8. from pandas.tseries.offsets import MonthEnd
  9. dates_month_end = dates + MonthEnd()
  10. print("当月的最后一天:")
  11. print(dates_month_end)
  12. # 使用YearBegin获取年初
  13. from pandas.tseries.offsets import YearBegin
  14. dates_year_begin = dates + YearBegin()
  15. print("当年的第一天:")
  16. print(dates_year_begin)
  17. # 使用QuarterEnd获取季度末
  18. from pandas.tseries.offsets import QuarterEnd
  19. dates_quarter_end = dates + QuarterEnd()
  20. print("当季的最后一天:")
  21. print(dates_quarter_end)
复制代码

6. 日期范围生成和操作

6.1 生成日期范围

Pandas的date_range()函数可以灵活地生成日期范围:
  1. # 基本日期范围
  2. basic_range = pd.date_range(start='2023-01-01', end='2023-01-10')
  3. print("基本日期范围:")
  4. print(basic_range)
  5. # 指定周期数
  6. period_range = pd.date_range(start='2023-01-01', periods=10)
  7. print("\n指定周期数的日期范围:")
  8. print(period_range)
  9. # 指定频率
  10. freq_range = pd.date_range(start='2023-01-01', periods=10, freq='D')  # 日频率
  11. print("\n日频率日期范围:")
  12. print(freq_range)
  13. # 不同频率的日期范围
  14. freq_ranges = {
  15.     '小时': pd.date_range(start='2023-01-01', periods=10, freq='H'),
  16.     '工作日': pd.date_range(start='2023-01-01', periods=10, freq='B'),
  17.     '周': pd.date_range(start='2023-01-01', periods=10, freq='W'),
  18.     '月': pd.date_range(start='2023-01-01', periods=10, freq='M'),
  19.     '季度': pd.date_range(start='2023-01-01', periods=10, freq='Q'),
  20.     '年': pd.date_range(start='2023-01-01', periods=10, freq='Y')
  21. }
  22. for name, rng in freq_ranges.items():
  23.     print(f"\n{name}频率日期范围:")
  24.     print(rng)
复制代码

6.2 自定义频率

Pandas允许我们使用自定义的频率生成日期范围:
  1. # 自定义频率
  2. custom_freq_range = pd.date_range(start='2023-01-01', periods=10, freq='2D')  # 每2天
  3. print("每2天的日期范围:")
  4. print(custom_freq_range)
  5. # 使用字符串别名
  6. custom_freq_range_2 = pd.date_range(start='2023-01-01', periods=10, freq='W-MON')  # 每周一
  7. print("\n每周一的日期范围:")
  8. print(custom_freq_range_2)
  9. # 使用DateOffset对象
  10. from pandas.tseries.offsets import Day, WeekOfMonth
  11. custom_freq_range_3 = pd.date_range(start='2023-01-01', periods=10, freq=WeekOfMonth(week=0, weekday=0))  # 每月第一个周一
  12. print("\n每月第一个周一的日期范围:")
  13. print(custom_freq_range_3)
复制代码

6.3 日期范围操作

我们可以对日期范围进行各种操作:
  1. # 创建日期范围
  2. date_range = pd.date_range(start='2023-01-01', end='2023-01-31', freq='D')
  3. # 转换为PeriodIndex
  4. period_index = date_range.to_period()
  5. print("日期范围转换为PeriodIndex:")
  6. print(period_index[:5])
  7. # 转换为DatetimeIndex
  8. datetime_index = period_index.to_timestamp()
  9. print("\nPeriodIndex转换为DatetimeIndex:")
  10. print(datetime_index[:5])
  11. # 日期范围交集
  12. date_range_1 = pd.date_range(start='2023-01-01', end='2023-01-15', freq='D')
  13. date_range_2 = pd.date_range(start='2023-01-10', end='2023-01-31', freq='D')
  14. intersection = date_range_1.intersection(date_range_2)
  15. print("\n两个日期范围的交集:")
  16. print(intersection)
  17. # 日期范围并集
  18. union = date_range_1.union(date_range_2)
  19. print("\n两个日期范围的并集:")
  20. print(union)
复制代码

7. 时区处理

7.1 时区转换

处理全球数据时,时区转换是一个重要问题:
  1. # 创建无时区的日期时间
  2. dates_no_tz = pd.date_range('2023-01-01', periods=5)
  3. print("无时区的日期时间:")
  4. print(dates_no_tz)
  5. # 本地化时区
  6. dates_with_tz = dates_no_tz.tz_localize('UTC')
  7. print("\nUTC时区的日期时间:")
  8. print(dates_with_tz)
  9. # 转换时区
  10. dates_est = dates_with_tz.tz_convert('US/Eastern')
  11. print("\n美国东部时区的日期时间:")
  12. print(dates_est)
  13. # 转换为其他时区
  14. dates_china = dates_with_tz.tz_convert('Asia/Shanghai')
  15. print("\n中国时区的日期时间:")
  16. print(dates_china)
复制代码

7.2 处理夏令时

夏令时转换可能会导致一些特殊情况:
  1. # 创建包含夏令时转换的日期范围
  2. dst_dates = pd.date_range('2023-03-10', '2023-03-13', freq='H', tz='US/Eastern')
  3. print("包含夏令时转换的日期时间:")
  4. print(dst_dates)
  5. # 处理不存在的时间(由于夏令时转换)
  6. try:
  7.     # 2023年美国夏令时开始于3月12日凌晨2点,时钟直接跳到3点
  8.     # 所以2023-03-12 02:30:00这个时间不存在
  9.     non_existent_time = pd.Timestamp('2023-03-12 02:30:00', tz='US/Eastern')
  10. except Exception as e:
  11.     print(f"\n错误: {e}")
  12. # 处理不明确的时间(由于夏令时结束)
  13. try:
  14.     # 2023年美国夏令时结束于11月5日凌晨2点,时钟回到1点
  15.     # 所以2023-11-05 01:30:00这个时间可能出现两次
  16.     ambiguous_time = pd.Timestamp('2023-11-05 01:30:00', tz='US/Eastern')
  17. except Exception as e:
  18.     print(f"\n错误: {e}")
  19. # 正确处理不明确的时间
  20. ambiguous_time_handled = pd.Timestamp('2023-11-05 01:30:00', tz='US/Eastern', ambiguous=True)
  21. print("\n正确处理的不明确时间:")
  22. print(ambiguous_time_handled)
复制代码

8. 时间重采样和滚动窗口计算

8.1 重采样技术

重采样是将时间序列数据从一个频率转换到另一个频率的过程:
  1. # 创建高频数据
  2. high_freq_data = pd.DataFrame(
  3.     {'value': np.random.randint(0, 100, size=90)},
  4.     index=pd.date_range('2023-01-01', periods=90, freq='D')
  5. )
  6. # 降采样(从高频率到低频率)
  7. daily_to_monthly = high_freq_data.resample('M').mean()  # 按月采样,计算每月平均值
  8. print("日数据降采样为月数据:")
  9. print(daily_to_monthly)
  10. # 升采样(从低频率到高频率)
  11. monthly_to_daily = daily_to_monthly.resample('D').asfreq()  # 按日采样,填充NaN
  12. print("\n月数据升采样为日数据:")
  13. print(monthly_to_daily.head(10))
  14. # 使用不同的聚合方法
  15. resample_methods = {
  16.     'sum': high_freq_data.resample('M').sum(),
  17.     'mean': high_freq_data.resample('M').mean(),
  18.     'median': high_freq_data.resample('M').median(),
  19.     'min': high_freq_data.resample('M').min(),
  20.     'max': high_freq_data.resample('M').max(),
  21.     'first': high_freq_data.resample('M').first(),
  22.     'last': high_freq_data.resample('M').last()
  23. }
  24. for method, data in resample_methods.items():
  25.     print(f"\n按月{method}采样:")
  26.     print(data)
复制代码

8.2 滚动窗口计算

滚动窗口计算是时间序列分析中常用的技术:
  1. # 创建时间序列数据
  2. ts_data = pd.DataFrame(
  3.     {'value': np.random.randn(100).cumsum()},
  4.     index=pd.date_range('2023-01-01', periods=100, freq='D')
  5. )
  6. # 计算滚动平均值
  7. rolling_mean = ts_data['value'].rolling(window=7).mean()  # 7日滚动平均
  8. print("7日滚动平均:")
  9. print(rolling_mean.head(10))
  10. # 计算滚动标准差
  11. rolling_std = ts_data['value'].rolling(window=7).std()  # 7日滚动标准差
  12. print("\n7日滚动标准差:")
  13. print(rolling_std.head(10))
  14. # 计算滚动最大值和最小值
  15. rolling_max = ts_data['value'].rolling(window=7).max()  # 7日滚动最大值
  16. rolling_min = ts_data['value'].rolling(window=7).min()  # 7日滚动最小值
  17. # 可视化滚动统计量
  18. import matplotlib.pyplot as plt
  19. plt.figure(figsize=(12, 6))
  20. plt.plot(ts_data.index, ts_data['value'], label='原始数据')
  21. plt.plot(rolling_mean.index, rolling_mean, label='7日滚动平均')
  22. plt.fill_between(rolling_std.index, rolling_mean - rolling_std, rolling_mean + rolling_std,
  23.                  color='gray', alpha=0.2, label='±1标准差')
  24. plt.legend()
  25. plt.title('滚动统计量')
  26. plt.xlabel('日期')
  27. plt.ylabel('值')
  28. plt.grid(True)
  29. plt.show()
复制代码

8.3 扩展窗口和指数加权窗口

除了固定大小的滚动窗口,Pandas还支持扩展窗口和指数加权窗口:
  1. # 创建时间序列数据
  2. ts_data = pd.DataFrame(
  3.     {'value': np.random.randn(100).cumsum()},
  4.     index=pd.date_range('2023-01-01', periods=100, freq='D')
  5. )
  6. # 扩展窗口计算
  7. expanding_mean = ts_data['value'].expanding().mean()  # 扩展窗口平均
  8. expanding_max = ts_data['value'].expanding().max()    # 扩展窗口最大值
  9. expanding_min = ts_data['value'].expanding().min()    # 扩展窗口最小值
  10. # 指数加权窗口
  11. ewm_mean = ts_data['value'].ewm(span=20).mean()  # 20日指数加权平均
  12. # 可视化不同窗口计算结果
  13. plt.figure(figsize=(12, 6))
  14. plt.plot(ts_data.index, ts_data['value'], label='原始数据', alpha=0.5)
  15. plt.plot(expanding_mean.index, expanding_mean, label='扩展窗口平均')
  16. plt.plot(ewm_mean.index, ewm_mean, label='指数加权平均')
  17. plt.legend()
  18. plt.title('扩展窗口和指数加权窗口')
  19. plt.xlabel('日期')
  20. plt.ylabel('值')
  21. plt.grid(True)
  22. plt.show()
复制代码

9. 实际应用案例

9.1 股票数据分析

让我们使用Pandas的日期时间功能来分析股票数据:
  1. # 假设我们有一段时间的股票数据
  2. np.random.seed(42)
  3. date_rng = pd.date_range(start='2022-01-01', end='2022-12-31', freq='D')
  4. # 排除周末
  5. date_rng = date_rng[date_rng.dayofweek < 5]
  6. # 生成模拟股票数据
  7. prices = 100 + np.cumsum(np.random.randn(len(date_rng)) * 0.5)
  8. volume = np.random.randint(100000, 500000, size=len(date_rng))
  9. stock_data = pd.DataFrame({
  10.     'Date': date_rng,
  11.     'Price': prices,
  12.     'Volume': volume
  13. })
  14. # 设置日期为索引
  15. stock_data.set_index('Date', inplace=True)
  16. # 计算移动平均线
  17. stock_data['MA_5'] = stock_data['Price'].rolling(window=5).mean()
  18. stock_data['MA_20'] = stock_data['Price'].rolling(window=20).mean()
  19. stock_data['MA_60'] = stock_data['Price'].rolling(window=60).mean()
  20. # 计算日收益率
  21. stock_data['Daily_Return'] = stock_data['Price'].pct_change() * 100
  22. # 计算波动率(20日滚动标准差)
  23. stock_data['Volatility'] = stock_data['Daily_Return'].rolling(window=20).std()
  24. # 按月份重采样
  25. monthly_data = stock_data.resample('M').agg({
  26.     'Price': ['first', 'last', 'max', 'min'],
  27.     'Volume': 'sum',
  28.     'Daily_Return': 'mean',
  29.     'Volatility': 'mean'
  30. })
  31. print("月度股票数据统计:")
  32. print(monthly_data)
  33. # 可视化股票价格和移动平均线
  34. plt.figure(figsize=(12, 6))
  35. plt.plot(stock_data.index, stock_data['Price'], label='股价')
  36. plt.plot(stock_data.index, stock_data['MA_5'], label='5日均线')
  37. plt.plot(stock_data.index, stock_data['MA_20'], label='20日均线')
  38. plt.plot(stock_data.index, stock_data['MA_60'], label='60日均线')
  39. plt.legend()
  40. plt.title('股价与移动平均线')
  41. plt.xlabel('日期')
  42. plt.ylabel('价格')
  43. plt.grid(True)
  44. plt.show()
复制代码

9.2 网站流量分析

接下来,我们使用Pandas分析网站流量数据:
  1. # 创建模拟网站流量数据
  2. np.random.seed(42)
  3. date_rng = pd.date_range(start='2023-01-01', end='2023-03-31', freq='H')
  4. # 生成模拟流量数据,考虑日内和周内模式
  5. base_traffic = 1000
  6. hour_pattern = np.array([0.5, 0.3, 0.2, 0.2, 0.3, 0.6, 1.2, 2.0, 2.5, 2.3, 2.0, 1.8,
  7.                         1.7, 1.8, 1.9, 2.0, 2.5, 3.0, 3.5, 3.2, 2.5, 2.0, 1.5, 1.0])
  8. weekday_pattern = np.array([0.8, 0.9, 1.0, 1.0, 1.0, 1.2, 0.7])
  9. traffic = []
  10. for date in date_rng:
  11.     hour_factor = hour_pattern[date.hour]
  12.     weekday_factor = weekday_pattern[date.dayofweek]
  13.     random_factor = np.random.normal(1, 0.1)
  14.     traffic_value = base_traffic * hour_factor * weekday_factor * random_factor
  15.     traffic.append(max(0, int(traffic_value)))
  16. web_traffic = pd.DataFrame({
  17.     'DateTime': date_rng,
  18.     'Visitors': traffic
  19. })
  20. # 设置日期时间为索引
  21. web_traffic.set_index('DateTime', inplace=True)
  22. # 提取时间组件
  23. web_traffic['Hour'] = web_traffic.index.hour
  24. web_traffic['DayOfWeek'] = web_traffic.index.dayofweek
  25. web_traffic['Date'] = web_traffic.index.date
  26. web_traffic['Month'] = web_traffic.index.month
  27. # 按小时分析流量
  28. hourly_traffic = web_traffic.groupby('Hour')['Visitors'].mean()
  29. # 按星期分析流量
  30. weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
  31. weekly_traffic = web_traffic.groupby('DayOfWeek')['Visitors'].mean()
  32. weekly_traffic.index = [weekday_names[i] for i in weekly_traffic.index]
  33. # 按日期分析流量
  34. daily_traffic = web_traffic.groupby('Date')['Visitors'].sum()
  35. # 按月分析流量
  36. monthly_traffic = web_traffic.groupby('Month')['Visitors'].sum()
  37. # 可视化不同时间维度的流量
  38. fig, axes = plt.subplots(2, 2, figsize=(15, 10))
  39. # 按小时流量
  40. hourly_traffic.plot(ax=axes[0, 0], kind='bar')
  41. axes[0, 0].set_title('按小时平均流量')
  42. axes[0, 0].set_xlabel('小时')
  43. axes[0, 0].set_ylabel('平均访客数')
  44. # 按星期流量
  45. weekly_traffic.plot(ax=axes[0, 1], kind='bar')
  46. axes[0, 1].set_title('按星期平均流量')
  47. axes[0, 1].set_xlabel('星期')
  48. axes[0, 1].set_ylabel('平均访客数')
  49. # 按日期流量
  50. daily_traffic.plot(ax=axes[1, 0])
  51. axes[1, 0].set_title('每日流量趋势')
  52. axes[1, 0].set_xlabel('日期')
  53. axes[1, 0].set_ylabel('访客数')
  54. # 按月流量
  55. monthly_traffic.plot(ax=axes[1, 1], kind='bar')
  56. axes[1, 1].set_title('按月流量')
  57. axes[1, 1].set_xlabel('月份')
  58. axes[1, 1].set_ylabel('访客数')
  59. plt.tight_layout()
  60. plt.show()
  61. # 检测异常流量
  62. # 计算Z分数来检测异常值
  63. daily_traffic_df = daily_traffic.reset_index()
  64. daily_traffic_df.columns = ['Date', 'Visitors']
  65. daily_traffic_df['Z_Score'] = (daily_traffic_df['Visitors'] - daily_traffic_df['Visitors'].mean()) / daily_traffic_df['Visitors'].std()
  66. anomalies = daily_traffic_df[abs(daily_traffic_df['Z_Score']) > 2]
  67. print("流量异常日期:")
  68. print(anomalies)
复制代码

9.3 销售数据分析

最后,我们使用Pandas分析销售数据:
  1. # 创建模拟销售数据
  2. np.random.seed(42)
  3. date_rng = pd.date_range(start='2022-01-01', end='2022-12-31', freq='D')
  4. # 排除周末
  5. date_rng = date_rng[date_rng.dayofweek < 5]
  6. # 生成模拟销售数据,考虑季节性和趋势
  7. base_sales = 1000
  8. trend = np.linspace(0, 500, len(date_rng))
  9. seasonality = 200 * np.sin(2 * np.pi * np.arange(len(date_rng)) / 365.25)
  10. random_factor = np.random.normal(0, 100, len(date_rng))
  11. sales = base_sales + trend + seasonality + random_factor
  12. sales = np.maximum(0, sales).astype(int)
  13. sales_data = pd.DataFrame({
  14.     'Date': date_rng,
  15.     'Sales': sales
  16. })
  17. # 设置日期为索引
  18. sales_data.set_index('Date', inplace=True)
  19. # 提取时间组件
  20. sales_data['Year'] = sales_data.index.year
  21. sales_data['Month'] = sales_data.index.month
  22. sales_data['Day'] = sales_data.index.day
  23. sales_data['Quarter'] = sales_data.index.quarter
  24. sales_data['Weekday'] = sales_data.index.dayofweek
  25. sales_data['WeekOfYear'] = sales_data.index.isocalendar().week
  26. # 按不同时间维度聚合销售数据
  27. monthly_sales = sales_data.groupby(['Year', 'Month'])['Sales'].sum()
  28. quarterly_sales = sales_data.groupby(['Year', 'Quarter'])['Sales'].sum()
  29. weekday_sales = sales_data.groupby('Weekday')['Sales'].mean()
  30. # 计算同比和环比增长
  31. # 环比增长
  32. monthly_sales_df = monthly_sales.reset_index()
  33. monthly_sales_df.columns = ['Year', 'Month', 'Sales']
  34. monthly_sales_df['MoM_Growth'] = monthly_sales_df['Sales'].pct_change() * 100
  35. # 同比增长
  36. yearly_comparison = pd.DataFrame()
  37. for year in monthly_sales_df['Year'].unique():
  38.     year_data = monthly_sales_df[monthly_sales_df['Year'] == year].copy()
  39.     year_data.set_index('Month', inplace=True)
  40.     yearly_comparison[year] = year_data['Sales']
  41. yearly_comparison['YoY_Growth'] = yearly_comparison.pct_change(axis=1)[2022] * 100
  42. print("月度销售数据:")
  43. print(monthly_sales_df.head(10))
  44. print("\n同比增长:")
  45. print(yearly_comparison.head(10))
  46. # 可视化销售数据
  47. fig, axes = plt.subplots(2, 2, figsize=(15, 10))
  48. # 每日销售趋势
  49. sales_data['Sales'].plot(ax=axes[0, 0])
  50. axes[0, 0].set_title('每日销售趋势')
  51. axes[0, 0].set_xlabel('日期')
  52. axes[0, 0].set_ylabel('销售额')
  53. # 月度销售
  54. monthly_sales.plot(ax=axes[0, 1], kind='bar')
  55. axes[0, 1].set_title('月度销售')
  56. axes[0, 1].set_xlabel('年-月')
  57. axes[0, 1].set_ylabel('销售额')
  58. # 季度销售
  59. quarterly_sales.plot(ax=axes[1, 0], kind='bar')
  60. axes[1, 0].set_title('季度销售')
  61. axes[1, 0].set_xlabel('年-季度')
  62. axes[1, 0].set_ylabel('销售额')
  63. # 星期销售
  64. weekday_names = ['周一', '周二', '周三', '周四', '周五']
  65. weekday_sales.index = [weekday_names[i] for i in weekday_sales.index]
  66. weekday_sales.plot(ax=axes[1, 1], kind='bar')
  67. axes[1, 1].set_title('星期平均销售')
  68. axes[1, 1].set_xlabel('星期')
  69. axes[1, 1].set_ylabel('平均销售额')
  70. plt.tight_layout()
  71. plt.show()
  72. # 预测未来销售(简单移动平均法)
  73. window = 30  # 30天移动平均
  74. sales_data['MA_30'] = sales_data['Sales'].rolling(window=window).mean()
  75. # 获取最后一个移动平均值
  76. last_ma = sales_data['MA_30'].iloc[-1]
  77. # 预测未来30天的销售
  78. future_dates = pd.date_range(start=sales_data.index[-1] + pd.Timedelta(days=1), periods=30, freq='D')
  79. # 排除周末
  80. future_dates = future_dates[future_dates.dayofweek < 5]
  81. # 简单预测:使用最后一个移动平均值加上随机波动
  82. future_sales = last_ma + np.random.normal(0, 50, len(future_dates))
  83. future_sales = np.maximum(0, future_sales).astype(int)
  84. future_sales_df = pd.DataFrame({
  85.     'Date': future_dates,
  86.     'Predicted_Sales': future_sales
  87. })
  88. print("\n未来销售预测:")
  89. print(future_sales_df)
  90. # 可视化历史销售和预测
  91. plt.figure(figsize=(12, 6))
  92. plt.plot(sales_data.index, sales_data['Sales'], label='历史销售')
  93. plt.plot(sales_data.index, sales_data['MA_30'], label='30日移动平均')
  94. plt.plot(future_sales_df['Date'], future_sales_df['Predicted_Sales'], 'ro-', label='预测销售')
  95. plt.axvline(x=sales_data.index[-1], color='gray', linestyle='--')
  96. plt.legend()
  97. plt.title('销售预测')
  98. plt.xlabel('日期')
  99. plt.ylabel('销售额')
  100. plt.grid(True)
  101. plt.show()
复制代码

10. 总结

本文详细介绍了Pandas中日期时间处理的各个方面,包括:

1. 日期时间数据类型的基础知识
2. 日期数据的创建和转换方法
3. 日期数据的格式化输出技巧
4. 时间序列数据的筛选和操作
5. 日期范围生成和操作
6. 时区处理
7. 时间重采样和滚动窗口计算
8. 实际应用案例

通过掌握这些技巧,你可以更加高效精准地处理时间序列数据,从而更好地进行数据分析和决策。无论是金融数据分析、网站流量分析还是销售数据分析,Pandas的日期时间功能都能为你提供强大的支持。

希望本文能帮助你更好地理解和应用Pandas的日期时间处理功能,提高你的数据分析效率和准确性。如果你有任何问题或建议,欢迎留言讨论。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

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

本版积分规则