import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 设置中文字体和负号显示支持
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

# 读取 Excel 文件
df = pd.read_excel("财报.xlsx")
df.set_index("指标", inplace=True)

# 转置：行是公司-年份，列是财务指标
df_T = df.T

# 转换单位并处理空值
def convert_to_float(x):
    try:
        if isinstance(x, str):
            x = x.replace("亿", "").replace(",", "").strip()
        return float(x)
    except:
        return np.nan

df_T = df_T.applymap(convert_to_float)
df_T.fillna(0, inplace=True)

# 标准化
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df_T)

# 主成分分析
pca = PCA()
pca_result = pca.fit_transform(df_scaled)

# 解释方差
print("各主成分解释方差比：", pca.explained_variance_ratio_)
print("累计解释方差比：", np.cumsum(pca.explained_variance_ratio_))

# 累计解释方差图（横坐标从1开始）
plt.figure(figsize=(8, 5))
plt.plot(
    range(1, len(pca.explained_variance_ratio_) + 1),
    np.cumsum(pca.explained_variance_ratio_),
    marker='o'
)
plt.xlabel('主成分数量')
plt.ylabel('累计解释方差比')
plt.title('主成分分析 - 累计解释方差比')
plt.grid(True)
plt.xticks(range(1, len(pca.explained_variance_ratio_) + 1))
plt.show()

# 载荷系数（每个主成分的权重）
loadings = pd.DataFrame(
    pca.components_.T,
    index=df_T.columns,
    columns=[f'PC{i+1}' for i in range(pca.n_components_)]
)
print("\n前3个主成分与原始财务指标的载荷系数：")
print(loadings.iloc[:, :3])
loadings.iloc[:, :5].to_excel("主成分变量权重.xlsx")

# -------- Biplot 图 -------- #
plt.figure(figsize=(10, 8))

# 投影点（公司）
x_pc1 = pca_result[:, 0]
y_pc2 = pca_result[:, 1]
plt.scatter(x_pc1, y_pc2, color='blue', alpha=0.6)

# 添加公司名称标签
for i, name in enumerate(df_T.index):
    plt.text(x_pc1[i], y_pc2[i], name, fontsize=9, alpha=0.8)

# 投影箭头（变量）
feature_vectors = pca.components_.T
arrow_size = 3
for i, v in enumerate(feature_vectors[:, :2]):
    plt.arrow(0, 0, v[0]*arrow_size, v[1]*arrow_size,
              color='r', alpha=0.6, head_width=0.05)
    plt.text(v[0]*arrow_size*1.1, v[1]*arrow_size*1.1,
             df_T.columns[i], color='r', fontsize=9)

plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("主成分分析 - 变量投影图（Biplot）")
plt.grid(True)
plt.axhline(0, color='gray', linestyle='--', linewidth=0.5)
plt.axvline(0, color='gray', linestyle='--', linewidth=0.5)
plt.tight_layout()
plt.show()
