注:该内容由“数模加油站”原创,无偿分享,可以领取参考但不要利用该内容倒卖,谢谢!
B 题 黄金价格的预测与数据分析
问题1 数据基本统计与可视化
黄金价格的统计特征与时间波动分析
1.1 数据导入与预处理:建模前的关键准备
在建模与预测之前,数据的预处理是确保分析有效性与模型精度的基础。由于本次赛题提供的数据包含多项黄金价格相关变量及多种宏观经济指标,我们首先选取分析的核心对象,即黄金的每日收盘价(Close)或复权收盘价(Adj Close)作为价格研究主线,并围绕时间维度进行一系列转换和清洗。
为此,我们对数据集执行如下操作:
- 时间标准化处理:将 Date 字段统一转换为 datetime 格式,便于后续按年、季度、月份等周期进行聚合;
- 数据排序与重复检查:按照时间升序对数据排序,同时剔除重复记录,保证时间序列单调性;
- 构建辅助字段:通过 dt.year、dt.month、dt.quarter 派生出新的年份、月份、季度字段,便于时间窗分析;
- 缺失值处理:通过 isnull().sum() 检查缺失数据,针对缺失少量的字段采用线性插值或删除策略,以防模型异常;
- 数据类型转换:将所有价格、交易量类字段统一为浮点数格式(float64),确保数值计算无误差传播。
这些处理步骤不仅提升了数据的可用性,也使得后续统计分析与可视化更加准确和高效。良好的数据结构设计是后续建模成功的重要保障。
1.2 描述性统计量分析:价格分布的数理画像
在数据初步整理完成后,我们首先对黄金的收盘价 进行基础统计分析,全面刻画其分布特性。
我们定义如下指标:
- 均值
:衡量价格的平均水平,是长期价格走势的“平衡点”;
- 中位数 M:反映价格在样本中的中间位置,能够抗干扰、代表主流价格水平;
- 标准差
:衡量价格的波动幅度,代表风险强度;
- 极值范围:
- 最小值:
- 最大值:
- 最小值:
- 偏度
:揭示价格分布是否偏离对称中心,S > 0 表示右偏(上涨快、下跌慢);
- 峰度
:反映分布是否尖峰集中,K > 0 表示具有“重尾效应”,存在极端风险事件。
通过这些统计量的计算,我们可对黄金价格的稳定性、中心趋势与极端波动情况形成直观判断。例如,若标准差较大且峰度偏高,表明黄金价格历史上经历过剧烈波动,模型预测时需考虑鲁棒性与抗极端干扰能力。
此外,偏度可辅助识别价格上涨或下跌的不对称特征,为判断投资风险提供行为金融学角度的参考。
1.3 黄金价格的时间序列可视化分析
进一步地,为了直观展现黄金价格的历史演变趋势,我们对其每日收盘价绘制时间序列图,并叠加短期与中期的滑动平均线,以平滑局部波动并提取潜在趋势结构。
设 p_t 表示第 t 天的收盘价,则滑动平均定义为:
其中 k = 7 表示一周平均,k = 30 代表一个交易月平均。滑动平均线能够过滤掉高频市场噪声,更好地揭示价格的真实趋势。
同时,我们引入滚动标准差衡量局部价格的波动强度:
该指标越大,说明市场当前越不稳定,投资者信心可能受挫。
在图像上,我们构造:
- 黄金价格原始曲线;
- 7日与30日移动平均线;
- 滚动标准差阴影区域或双轴波动率线。
黄金价格随时间变化的折线图
这种“价格+趋势+波动”的组合图,能够清晰刻画市场走势,识别价格是否处于趋势突破、剧烈震荡或稳态区间。
例如,在疫情初期的2020年第一季度,金价走势陡峭上升,配合高波动率,恰恰说明了市场避险需求的剧烈增长。
1.4 年度与季度价格结构分析:周期性与稳定性的揭示
金融市场数据通常存在显著的周期结构。为了分析黄金价格在不同周期下的统计特征,我们将数据按年度、季度与月份分别进行聚合,构建结构性指标。
设第 y 年内黄金价格为,我们定义:
年均价:
年波动范围:
年标准差:
季度与月份统计类似,便于发现是否存在“季度效应”或“月份效应”。
年度箱型图
季度平均价柱状图
月度波动热力图
经济解读示例:
若发现在第二季度黄金波动率显著上升,可能与财政政策、全球避险情绪变化有关;如果年底价格均值偏高,则可能是年度结算、央行购金的集中时点所致。
这种时间结构分析不仅揭示了市场行为模式,还可指导模型构建时的窗口选择与周期输入变量设计。
1.5 结论
通过对黄金价格的统计特征与时间波动的系统分析,我们得出以下关键结论:
- 黄金价格整体呈现上升趋势,中长期表现出强烈的通胀对冲属性;
- 其波动性具有阶段性特征,如在2020年出现剧烈上涨与波动,并伴随交易量异常变化;
- 季度与月份的价格波动具有规律性,为预测建模提供了窗口优化与季节性因素的依据;
- 高峰度与偏态性提示模型需具备识别与抗击极端值扰动的能力。
Python代码:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
sns.set(style="whitegrid")
# 设置中文字体为 SimHei(黑体)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为SimHei显示中文
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# -----------------------------
# 1. 数据读取与预处理
# -----------------------------
df = pd.read_csv('data.csv') # 请替换为你的路径
df['Date'] = pd.to_datetime(df['Date'], errors='coerce') # 转换为标准时间格式
df = df.dropna(subset=['Date']).drop_duplicates().sort_values(by='Date')
df.set_index('Date', inplace=True)
# 时间字段扩展
df['Year'] = df.index.year
df['Month'] = df.index.month
df['Quarter'] = df.index.to_period('Q')
# -----------------------------
# 2. 描述性统计量计算
# -----------------------------
gold_price = df['Close'].dropna()
# 计算均值 $\mu = \frac{1}{n} \sum_{i=1}^{n} p_i$
mu = gold_price.mean()
# 计算中位数 $M$
median = gold_price.median()
# 计算标准差 $\sigma = \sqrt{\frac{1}{n} \sum_{i=1}^{n}(p_i - \mu)^2}$
sigma = gold_price.std()
# 极值
p_min = gold_price.min()
p_max = gold_price.max()
# 偏度 $S = \frac{1}{n} \sum_{i=1}^{n} \left( \frac{p_i - \mu}{\sigma} \right)^3$
skewness = gold_price.skew()
# 峰度 $K = \frac{1}{n} \sum_{i=1}^{n} \left( \frac{p_i - \mu}{\sigma} \right)^4 - 3$
kurtosis = gold_price.kurt()
print("描述性统计:")
print(f"均值: {mu:.2f}, 中位数: {median:.2f}, 标准差: {sigma:.2f}")
print(f"最小值: {p_min:.2f}, 最大值: {p_max:.2f}")
print(f"偏度: {skewness:.2f}, 峰度: {kurtosis:.2f}")
# -----------------------------
# 3. 黄金价格趋势图 + 移动平均线
# -----------------------------
# 计算滑动平均:
# MA7: $\text{MA}_t = \frac{1}{7} \sum_{i=t-6}^{t} p_i$
df['MA7'] = gold_price.rolling(window=7).mean()
# MA30: $\text{MA}_t = \frac{1}{30} \sum_{i=t-29}^{t} p_i$
df['MA30'] = gold_price.rolling(window=30).mean()
# 计算波动率(滑动标准差):
# $V_t = \sqrt{\frac{1}{k} \sum_{j=t-k+1}^{t} (p_j - \text{MA}_t)^2}$
df['Volatility'] = gold_price.rolling(window=30).std()
# 绘图
plot_df = df[['Close', 'MA7', 'MA30']].dropna()
plt.figure(figsize=(14, 6))
plt.plot(plot_df.index, plot_df['Close'], label='收盘价', linewidth=1)
plt.plot(plot_df.index, plot_df['MA7'], label='7日均线', linewidth=1.2)
plt.plot(plot_df.index, plot_df['MA30'], label='30日均线', linewidth=1.2)
plt.title('黄金价格及其移动平均趋势图')
plt.xlabel('日期')
plt.ylabel('价格(美元)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.xticks(rotation=45)
plt.show()
# -----------------------------
# 4. 年度与季度结构统计
# -----------------------------
# 年度聚合统计
annual_group = df.groupby('Year')['Close']
annual_mean = annual_group.mean() # 年均价 $\mu^{(y)}$
annual_std = annual_group.std() # 年标准差 $\sigma^{(y)}$
annual_min = annual_group.min() # 年最小价
annual_max = annual_group.max() # 年最大价
# 年度箱型图(展示每年价格分布)
plt.figure(figsize=(12, 6))
sns.boxplot(x='Year', y='Close', data=df.reset_index())
plt.title('黄金价格年度分布箱型图')
plt.xlabel('年份')
plt.ylabel('价格(美元)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# 季度平均价格柱状图
quarterly_mean = df.groupby('Quarter')['Close'].mean()
plt.figure(figsize=(14, 6))
quarterly_mean.plot(kind='bar', color='skyblue')
plt.title('季度平均黄金价格柱状图')
plt.xlabel('季度')
plt.ylabel('平均价格(美元)')
plt.xticks(rotation=90)
plt.tight_layout()
plt.grid(True)
plt.show()
# -----------------------------
# 5. 月度波动热力图(标准差)
# -----------------------------
# 每月波动:$\sigma_{y,m} = \text{std}(\{p_i^{(y,m)}\})$
monthly_std = df.groupby(['Year', 'Month'])['Close'].std().unstack()
plt.figure(figsize=(12, 6))
sns.heatmap(monthly_std, cmap='coolwarm', annot=False)
plt.title('按月划分的黄金价格波动热力图(标准差)')
plt.xlabel('月份')
plt.ylabel('年份')
plt.tight_layout()
plt.show()
后续都在“数模加油站”......