生生不息

生生不息

AI添加时间特征并训练模型

2025-06-27
AI添加时间特征并训练模型

提示词

以日期为index的DataFrame,包含每日的收盘价,现在需要将index中的月份提取出来,并转换为哑变量,作为新的特征保存到DataFrame中,然后检查添加的结果,请给出示例代码。

答案

import pandas as pd
import numpy as np

# 创建示例数据(假设df是包含日期索引和收盘价的DataFrame)
# dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
# prices = np.random.uniform(1800, 2000, len(dates)).round(2)
# df = pd.DataFrame({'收盘价': prices}, index=dates)

df = pd.read_excel('黄金连续.xlsx')

#将日期设置为index,并只保留收盘价
df.set_index('日期', inplace=True)
df = df[['收盘价']]

# 1. 从日期索引中提取月份 [1,2,3](@ref)
print("原始数据前5行:")
print(df.head(), end='\n\n')

# 2. 提取月份(1-12)
df['月份'] = df.index.month  # 直接使用datetime索引的month属性[2,3](@ref)

# 3. 将月份转换为哑变量 [3,5](@ref)
month_dummies = pd.get_dummies(
    df['月份'], 
    prefix='month', 
    prefix_sep='_',
    dtype=int  # 指定为整数类型节省内存
)

# 4. 将哑变量添加到原始DataFrame
df = pd.concat([df, month_dummies], axis=1)

# 5. 检查添加结果
print("添加月份特征后的数据:")
print(df.head(), end='\n\n')

print("月份统计分布:")
print(df['月份'].value_counts().sort_index(), end='\n\n')

print("哑变量特征示例:")
print(df[['月份'] + list(month_dummies.columns)].head(10), end='\n\n')

# 6. 可视化月份分布
import matplotlib.pyplot as plt

plt.figure(figsize=(14, 6))

# 月度收盘价分布
plt.subplot(1, 2, 1)
df.groupby('月份')['收盘价'].mean().plot(kind='bar', color='skyblue')
plt.title('各月平均收盘价')
plt.xlabel('月份')
plt.ylabel('平均价格')

# 月份频数分布
plt.subplot(1, 2, 2)
df['月份'].value_counts().sort_index().plot(kind='pie', autopct='%1.1f%%')
plt.title('月份分布比例')
plt.ylabel('')

plt.tight_layout()
plt.show()

代码都是ai写的。

结果:

建模

提示词

简化代码再描述

# Python代码
# df是黄金期货行情DataFrame
df = pd.read_excel('黄金连续.xlsx')

#将日期设置为index,并只保留收盘价
df.set_index('日期', inplace=True)
df = df[['收盘价']]

# 特征工程
df['Month'] = df.index.month
dummies = pd.get_dummies(df['Month'], prefix='Month', dtype='int')
df = pd.concat([df, dummies], axis=1)

#为了使大家可以看到数据处理结果,我们检查下
df.tail()

现在我们使用上面添加了时间特征的DataFrame创建线性回归模型,并用滚动时间序列交叉验证法评估模型的MAPE,最后将结果进行可视化,请给出示例代码。

答案

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import mean_absolute_error

# 1. 特征工程扩展(添加滞后特征)
for lag in [1, 3, 5, 7]:
    df[f'Lag_{lag}'] = df['收盘价'].shift(lag)

# 添加技术指标特征
df['MA5'] = df['收盘价'].rolling(5).mean().shift(1)  # 5日移动平均(避免泄露)
df['MA20'] = df['收盘价'].rolling(20).mean().shift(1)  # 20日移动平均
df['Volatility'] = df['收盘价'].rolling(10).std().shift(1)  # 波动率
df['Price_Change'] = df['收盘价'].pct_change().shift(1) * 100  # 价格变化率

# 目标变量(预测次日收盘价)
df['Target'] = df['收盘价'].shift(-1)

# 删除含NaN的行
df_clean = df.dropna().copy()

# 2. 定义特征和目标变量
features = [col for col in df_clean.columns if col not in ['收盘价', 'Target', 'Month']]
target = 'Target'

# 3. 滚动时间序列交叉验证
tscv = TimeSeriesSplit(n_splits=5)
predictions = []
actuals = []
dates = []
mape_values = []

print("开始滚动交叉验证...")
for train_index, test_index in tscv.split(df_clean):
    # 数据分割
    train = df_clean.iloc[train_index]
    test = df_clean.iloc[test_index]
  
    # 训练模型
    model = LinearRegression()
    model.fit(train[features], train[target])
  
    # 预测
    test_pred = model.predict(test[features])
  
    # 存储结果
    predictions.extend(test_pred)
    actuals.extend(test[target].values)
    dates.extend(test.index)
  
    # 计算MAPE(过滤零值)
    mask = test[target] != 0
    mape = mean_absolute_error(
        test.loc[mask, target], 
        test_pred[mask]
    ) / np.mean(test.loc[mask, target]) * 100
    mape_values.append(mape)
    print(f"子集MAPE: {mape:.2f}%")

# 4. 结果汇总
results = pd.DataFrame({
    'Date': dates,
    'Actual': actuals,
    'Predicted': predictions
}).set_index('Date').sort_index()

# 整体MAPE计算
mask = results['Actual'] != 0
overall_mape = mean_absolute_error(
    results.loc[mask, 'Actual'],
    results.loc[mask, 'Predicted']
) / np.mean(results.loc[mask, 'Actual']) * 100
print(f"\n整体MAPE: {overall_mape:.2f}%")

# 5. 可视化分析
plt.figure(figsize=(16, 10))

# 5.1 价格曲线对比
plt.subplot(2, 1, 1)
plt.plot(results.index, results['Actual'], 'b-', label='实际价格', alpha=0.8, lw=1.5)
plt.plot(results.index, results['Predicted'], 'r--', label='预测价格', lw=1.2)
plt.fill_between(results.index, 
                 results['Predicted'] * 0.97,
                 results['Predicted'] * 1.03,
                 color='pink', alpha=0.3, label='±3%误差带')
plt.title(f'黄金期货价格预测 (MAPE={overall_mape:.2f}%)', fontsize=14)
plt.ylabel('价格', fontsize=12)
plt.legend()
plt.grid(alpha=0.2)

# 5.2 误差分布分析
plt.subplot(2, 1, 2)
errors = (results['Predicted'] - results['Actual']) / results['Actual'] * 100
plt.bar(results.index, errors, 
        color=np.where(errors >= 0, 'coral', 'seagreen'), 
        alpha=0.7, width=0.8)
plt.axhline(0, color='black', ls='--', lw=0.8)
plt.title('每日预测误差分布', fontsize=12)
plt.ylabel('百分比误差(%)', fontsize=10)
plt.ylim(-15, 15)
plt.grid(alpha=0.2)

plt.tight_layout()
plt.savefig('gold_price_forecast.png', dpi=300)
plt.show()

# 6. 模型系数分析
coef_df = pd.DataFrame({
    'Feature': features,
    'Coefficient': model.coef_
}).sort_values('Coefficient', key=abs, ascending=False)

print("\n特征重要性Top 10:")
print(coef_df.head(10))

# 可视化系数
plt.figure(figsize=(10, 6))
top_features = coef_df.head(10).sort_values('Coefficient', ascending=True)
plt.barh(top_features['Feature'], top_features['Coefficient'], color='teal')
plt.title('线性回归模型特征系数Top 10', fontsize=14)
plt.xlabel('系数值', fontsize=12)
plt.grid(axis='x', alpha=0.3)
plt.tight_layout()
plt.show()

结果: