# ── 完整 EDA 摘要:五张图,五个问题 ───────────────────────────
fig = plt.figure(figsize=(16, 12))
gs = fig.add_gridspec(3, 3, hspace=0.45, wspace=0.35)
# 图形:收益率分布。
ax1 = fig.add_subplot(gs[0, 0])
hs300["ret"].plot.kde(ax=ax1, color="darkblue", lw=1.8)
x_n = np.linspace(hs300["ret"].min(), hs300["ret"].max(), 200)
ax1.plot(
x_n,
stats.norm.pdf(x_n, hs300["ret"].mean(), hs300["ret"].std()),
linestyle="--",
color="red",
lw=1.2,
label="正态参照"
)
ax1.set_title("收益率分布:近似正态,尾部较厚")
ax1.set_xlabel("日度收益率")
ax1.legend(fontsize=7)
ax1.xaxis.set_major_formatter(mticker.PercentFormatter(1.0, decimals=1))
# 图形:滚动年化波动率。
ax2 = fig.add_subplot(gs[0, 1:])
hs_roll_summary = hs300.copy().set_index("date")
hs_roll_summary["rv20"] = hs_roll_summary["ret"].rolling(20).std() * np.sqrt(252) * 100
ax2.plot(
hs_roll_summary.index,
hs_roll_summary["rv20"],
color="darkorange",
lw=1.2
)
ax2.axhline(
hs_roll_summary["rv20"].mean(),
color="gray",
lw=0.8,
linestyle="--",
label=f"均值 = {hs_roll_summary['rv20'].mean():.1f}%"
)
ax2.set_title("20 日滚动年化波动率")
ax2.set_xlabel("日期")
ax2.legend(fontsize=7)
# 图形:行业 ROA 箱型图。
ax3 = fig.add_subplot(gs[1, :2])
roa23 = df_fin[df_fin["year"] == 2023].copy()
industry_order = (
roa23
.groupby("industry")["ROA"]
.median()
.sort_values(ascending=False)
.index
.tolist()
)
sns.boxplot(
data=roa23,
x="industry",
y="ROA",
order=industry_order,
color="darkblue",
width=0.55,
fliersize=2,
boxprops={"alpha": 0.55},
medianprops={"color": "red", "linewidth": 1.8},
ax=ax3
)
ax3.set_title("行业 ROA 分布 (2023 年)")
ax3.set_xlabel("行业")
ax3.set_ylabel("ROA")
# 图形:相关热力图。
ax4 = fig.add_subplot(gs[1, 2])
corr4 = roa23[["ROA", "Leverage", "Size"]].corr()
sns.heatmap(
corr4,
annot=True,
fmt=".2f",
cmap="RdBu_r",
vmin=-1,
vmax=1,
center=0,
square=True,
cbar=False,
linewidths=0.5,
ax=ax4,
annot_kws={"size": 9}
)
ax4.set_title("变量相关矩阵")
# 图形:国企 vs 民企 ROA 随时间变化。
ax5 = fig.add_subplot(gs[2, :])
soe_year = (
df_fin
.groupby(["soe", "year"])["ROA"]
.agg(["mean", "std"])
.reset_index()
)
for soe_val, label, color in [(0, "民企", "darkblue"), (1, "国企", "darkorange")]:
group = soe_year[soe_year["soe"] == soe_val]
x_year = group["year"].to_numpy()
y_mean = group["mean"].to_numpy()
y_std = group["std"].to_numpy()
ax5.plot(
x_year,
y_mean,
marker="o",
color=color,
lw=2,
label=label
)
ax5.fill_between(
x_year,
y_mean - y_std,
y_mean + y_std,
alpha=0.12,
color=color
)
ax5.axhline(0, color="gray", lw=0.5, linestyle=":")
ax5.set_title("国企与民企年均 ROA (±1 SD):民企均值持续较高")
ax5.set_xlabel("年份")
ax5.set_ylabel("ROA")
ax5.legend(fontsize=9)
fig.suptitle(
"金融数据 EDA 摘要:沪深 300 行情与上市公司财务面板",
fontsize=13,
y=1.01,
fontweight="bold"
)
plt.savefig(f"{OUTPUT}/EDA_eda_summary.png", dpi=150, bbox_inches="tight")
plt.show()
print("EDA 摘要图已保存至 output/EDA_eda_summary.png。")