import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.svm import SVC  # 导入支持向量机分类器
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score, classification_report, confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import seaborn as sns

# 设置支持中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 导入数据
data = pd.read_excel('堤防训练集数据0.xlsx')

# 假设前五列为特征，最后一列为输出标签
inputs = data.iloc[:, :-1].values  # 输入数据（特征）
output = data.iloc[:, -1].values.astype(int)  # 输出标签（确保为整数类型）

# 数据归一化
scaler = MinMaxScaler()
inputs = scaler.fit_transform(inputs)

# 打乱数据并按8:2划分训练集和验证集
train_inputs, val_inputs, train_output, val_output = train_test_split(
    inputs, output, test_size=0.2, random_state=42, shuffle=True)

# 初始化支持向量机模型
svm_model = SVC(C=1.0,                # 正则化参数
                kernel='rbf',         # 核函数类型
                gamma='scale',        # 核函数的系数
                probability=True,     # 启用概率估计
                random_state=42)      # 设置随机种子，保证结果可重复

# 训练模型
svm_model.fit(train_inputs, train_output)

# 计算训练集和验证集的预测值
train_pred_proba = svm_model.predict_proba(train_inputs)[:, 1]  # 获取类别 1 的概率值
val_pred_proba = svm_model.predict_proba(val_inputs)[:, 1]      # 获取类别 1 的概率值

# 计算离散的预测值
train_pred = svm_model.predict(train_inputs)
val_pred = svm_model.predict(val_inputs)

# 计算训练集和验证集的准确率、召回率、精度、F1分数
train_accuracy = accuracy_score(train_output, train_pred)
val_accuracy = accuracy_score(val_output, val_pred)
train_recall = recall_score(train_output, train_pred, average='macro')
val_recall = recall_score(val_output, val_pred, average='macro')
train_precision = precision_score(train_output, train_pred, average='macro')
val_precision = precision_score(val_output, val_pred, average='macro')
train_f1 = f1_score(train_output, train_pred, average='macro')
val_f1 = f1_score(val_output, val_pred, average='macro')

# 输出训练集和验证集的准确率、召回率、精度、F1分数
print(f'训练集准确率: {train_accuracy:.4f}')
print(f'训练集召回率: {train_recall:.4f}')
print(f'训练集精度: {train_precision:.4f}')
print(f'训练集F1分数: {train_f1:.4f}')
print(f'验证集准确率: {val_accuracy:.4f}')
print(f'验证集召回率: {val_recall:.4f}')
print(f'验证集精度: {val_precision:.4f}')
print(f'验证集F1分数: {val_f1:.4f}')

# 分类报告
print("验证集分类报告:")
print(classification_report(val_output, val_pred, target_names=['类别 0', '类别 1']))

# 绘制训练集的预测值与实际值对比曲线 (概率波动在0-1之间)
plt.figure(figsize=(10, 6))
plt.plot(train_output, label='实际值 (训练集)', color='blue', alpha=0.6)
plt.plot(train_pred_proba, label='预测概率值 (训练集)', color='red', linestyle='--', alpha=0.8)
plt.legend()
plt.xlabel('数据点')
plt.ylabel('类别概率')
plt.title('训练集：实际值与预测概率值对比')
plt.ylim([0, 1])  # 确保y轴范围在0和1之间
plt.show()

# 绘制验证集的预测值与实际值对比曲线 (概率波动在0-1之间)
plt.figure(figsize=(10, 6))
plt.plot(val_output, label='实际值 (验证集)', color='blue', alpha=0.6)
plt.plot(val_pred_proba, label='预测概率值 (验证集)', color='red', linestyle='--', alpha=0.8)
plt.legend()
plt.xlabel('数据点')
plt.ylabel('类别概率')
plt.title('验证集：实际值与预测概率值对比')
plt.ylim([0, 1])  # 确保y轴范围在0和1之间
plt.show()

# 绘制训练集混淆矩阵
train_cm = confusion_matrix(train_output, train_pred)

plt.figure(figsize=(8, 6))
sns.heatmap(train_cm, annot=True, fmt="d", cmap="Blues", cbar=False)
plt.title('训练集混淆矩阵')
plt.xlabel('预测类别')
plt.ylabel('实际类别')
plt.show()

# 绘制验证集混淆矩阵
val_cm = confusion_matrix(val_output, val_pred)

plt.figure(figsize=(8, 6))
sns.heatmap(val_cm, annot=True, fmt="d", cmap="Blues", cbar=False)
plt.title('验证集混淆矩阵')
plt.xlabel('预测类别')
plt.ylabel('实际类别')
plt.show()
