Python案例如何用Pandas做数据平滑

wen python案例 1

本文目录导读:

Python案例如何用Pandas做数据平滑

  1. 数据平滑的常用方法
  2. 选择平滑方法的建议

我来为你详细介绍使用Pandas进行数据平滑的几种常用方法,并给出完整案例。

数据平滑的常用方法

移动平均法

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 创建示例数据(带噪声的正弦波)
np.random.seed(42)
t = np.linspace(0, 10, 100)
data = np.sin(t) + np.random.normal(0, 0.3, 100)
df = pd.DataFrame({'time': t, 'value': data})
# 移动平均平滑
df['sma_3'] = df['value'].rolling(window=3, center=True).mean()  # 3点移动平均
df['sma_5'] = df['value'].rolling(window=5, center=True).mean()  # 5点移动平均
df['sma_10'] = df['value'].rolling(window=10, center=True).mean()  # 10点移动平均
# 可视化
plt.figure(figsize=(12, 6))
plt.plot(df['time'], df['value'], 'o-', label='原始数据', alpha=0.5)
plt.plot(df['time'], df['sma_3'], label='3点移动平均', linewidth=2)
plt.plot(df['time'], df['sma_5'], label='5点移动平均', linewidth=2)
plt.plot(df['time'], df['sma_10'], label='10点移动平均', linewidth=2)
plt.legend()'移动平均平滑效果对比')
plt.grid(True, alpha=0.3)
plt.show()

指数加权移动平均

# 指数加权移动平均(对近期数据给予更高权重)
df['ewm_01'] = df['value'].ewm(alpha=0.1, adjust=False).mean()  # 平滑系数0.1
df['ewm_03'] = df['value'].ewm(alpha=0.3, adjust=False).mean()  # 平滑系数0.3
df['ewm_05'] = df['value'].ewm(alpha=0.5, adjust=False).mean()  # 平滑系数0.5
# 可视化
plt.figure(figsize=(12, 6))
plt.plot(df['time'], df['value'], 'o-', label='原始数据', alpha=0.5)
plt.plot(df['time'], df['ewm_01'], label='alpha=0.1', linewidth=2)
plt.plot(df['time'], df['ewm_03'], label='alpha=0.3', linewidth=2)
plt.plot(df['time'], df['ewm_05'], label='alpha=0.5', linewidth=2)
plt.legend()'指数加权移动平均平滑效果对比')
plt.grid(True, alpha=0.3)
plt.show()

中值滤波

# 中值滤波(对异常值具有很好的鲁棒性)
df['median_3'] = df['value'].rolling(window=3, center=True).median()
df['median_5'] = df['value'].rolling(window=5, center=True).median()
# 可视化
plt.figure(figsize=(12, 6))
plt.plot(df['time'], df['value'], 'o-', label='原始数据', alpha=0.5)
plt.plot(df['time'], df['median_3'], label='3点中值滤波', linewidth=2)
plt.plot(df['time'], df['median_5'], label='5点中值滤波', linewidth=2)
plt.legend()'中值滤波平滑效果对比')
plt.grid(True, alpha=0.3)
plt.show()

实战案例:股票价格平滑

# 模拟股票价格数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100, freq='D')
price = 100 + np.cumsum(np.random.normal(0, 2, 100)) + np.random.normal(0, 1, 100)
stock_df = pd.DataFrame({'date': dates, 'price': price})
stock_df.set_index('date', inplace=True)
# 多种平滑方法
stock_df['SMA_5'] = stock_df['price'].rolling(window=5).mean()
stock_df['SMA_10'] = stock_df['price'].rolling(window=10).mean()
stock_df['EWMA'] = stock_df['price'].ewm(span=10, adjust=False).mean()
stock_df['HMA'] = stock_df['price'].rolling(window=10).mean().rolling(window=5).mean()
# 可视化
plt.figure(figsize=(14, 7))
plt.plot(stock_df['price'], label='原始价格', alpha=0.6, linewidth=1)
plt.plot(stock_df['SMA_5'], label='5日移动平均', linewidth=2)
plt.plot(stock_df['SMA_10'], label='10日移动平均', linewidth=2)
plt.plot(stock_df['EWMA'], label='指数加权平均(span=10)', linewidth=2, linestyle='--')
plt.plot(stock_df['HMA'], label='双移动平均', linewidth=2, linestyle=':')
plt.legend(loc='best')'股票价格平滑分析')
plt.xlabel('日期')
plt.ylabel('价格')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

批量处理多个数据列

# 创建多列数据
multi_df = pd.DataFrame({
    'A': np.sin(np.linspace(0, 10, 100)) + np.random.normal(0, 0.2, 100),
    'B': np.cos(np.linspace(0, 10, 100)) + np.random.normal(0, 0.2, 100),
    'C': np.sin(np.linspace(0, 10, 100)) * 2 + np.random.normal(0, 0.2, 100)
})
def smooth_data(df, window=5, method='mean'):
    """批量平滑数据的函数"""
    if method == 'mean':
        return df.rolling(window=window, center=True).mean()
    elif method == 'median':
        return df.rolling(window=window, center=True).median()
    elif method == 'ewm':
        return df.ewm(span=window, adjust=False).mean()
# 应用平滑
window = 5
smooth_mean = smooth_data(multi_df, window, 'mean')
smooth_median = smooth_data(multi_df, window, 'median')
smooth_ewm = smooth_data(multi_df, window, 'ewm')
# 可视化
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
for i, col in enumerate(multi_df.columns):
    axes[i].plot(multi_df[col], 'o-', label='原始数据', alpha=0.5, markersize=3)
    axes[i].plot(smooth_mean[col], label=f'{window}点移动平均', linewidth=2)
    axes[i].plot(smooth_median[col], label=f'{window}点中值滤波', linewidth=2)
    axes[i].plot(smooth_ewm[col], label=f'EWM(span={window})', linewidth=2, linestyle='--')
    axes[i].set_title(f'列 {col}')
    axes[i].legend()
    axes[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

平滑效果评估

# 评估平滑效果
def evaluate_smoothing(original, smoothed, name):
    """评估平滑效果"""
    # 计算平滑前后的变化
    original_variance = original.var()
    smoothed_variance = smoothed.var()
    reduction = (1 - smoothed_variance / original_variance) * 100
    # 计算均方误差(MSE)
    mse = ((original - smoothed) ** 2).mean()
    return {
        '方法': name,
        '原始方差': f'{original_variance:.4f}',
        '平滑后方差': f'{smoothed_variance:.4f}',
        '方差减少(%)': f'{reduction:.2f}%',
        'MSE': f'{mse:.4f}'
    }
# 评估不同平滑方法
results = []
for col in ['value']:
    results.append(evaluate_smoothing(
        df[col].dropna(), 
        df['sma_5'].dropna(), 
        '5点移动平均'
    ))
    results.append(evaluate_smoothing(
        df[col].dropna(), 
        df['ewm_03'].dropna(), 
        '指数平滑(alpha=0.3)'
    ))
    results.append(evaluate_smoothing(
        df[col].dropna(), 
        df['median_5'].dropna(), 
        '5点中值滤波'
    ))
# 创建评估结果DataFrame
evaluation_df = pd.DataFrame(results)
print("平滑效果评估:")
print(evaluation_df.to_string(index=False))

选择平滑方法的建议

  1. 移动平均:适用平稳序列,计算简单
  2. 指数加权移动平均:需要更多关注近期数据时使用
  3. 中值滤波:数据有较多异常值时效果最好
  4. 组合方法:可以先用中值滤波去异常,再用移动平均平滑

根据你的具体数据和需求选择合适的方法,通常需要尝试不同的窗口大小和参数来得到最佳效果。

抱歉,评论功能暂时关闭!