1. 问题1:多因素影响权重评估模型
目标:量化各因素对疾病风险的影响程度,识别关键风险因素。
方法:结合统计显著性和预测贡献,构建综合权重评估模型。
详细步骤:
- 数据预处理
- 处理缺失值(均值/中位数填充、多重插补)。
- 异常值检测(箱线图、Z-score)。
- 标准化(Z-score或Min-Max)。
- 单变量分析
- 对每个特征进行单变量逻辑回归,计算:
- 回归系数(
)
- p值(
)
- 优势比(OR)
- AUC(单变量模型的预测能力)
- 回归系数(
- 对每个特征进行单变量逻辑回归,计算:
- 多变量分析
- 构建多变量逻辑回归模型,计算调整后的回归系数(
)。
- 计算特征对模型性能的独立贡献(
):
- 移除特征
后,观察AUC下降幅度。
- 移除特征
- 构建多变量逻辑回归模型,计算调整后的回归系数(
- 权重计算
- 综合权重公式:
- 标准化权重(百分比形式):
- 综合权重公式:
- 关键特征筛选
- 按权重排序,绘制累积影响度曲线(如80%累积权重对应的特征)。
代码
1. 导入库与初始化设置
# 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.model_selection import cross_val_score, LeaveOneOut
from statsmodels.stats.multitest import multipletests
import statsmodels.api as sm
from statsmodels.formula.api import glm
import warnings
import os
from matplotlib.font_manager import FontProperties
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题
# 设置全局图表样式
warnings.filterwarnings('ignore')
# 创建结果保存目录
if not os.path.exists('results'):
os.makedirs('results')
# 设置随机种子,确保结果可复现
np.random.seed(42)
2. 数据加载与探索
# 数据加载
heart_data = pd.read_csv('heart.csv')
stroke_data = pd.read_csv('stroke.csv')
cirrhosis_data = pd.read_csv('cirrhosis.csv')
# 显示心脏病数据集基本信息
print("心脏病数据集概览:")
print(f"数据形状: {heart_data.shape}")
print(heart_data.head())
print("\n心脏病数据集信息:")
print(heart_data.info())
print("\n心脏病数据集描述性统计:")
print(heart_data.describe())
# 显示中风数据集基本信息
print("\n中风数据集概览:")
print(f"数据形状: {stroke_data.shape}")
print(stroke_data.head())
print("\n中风数据集信息:")
print(stroke_data.info())
print("\n中风数据集描述性统计:")
print(stroke_data.describe())
# 显示肝硬化数据集基本信息
print("\n肝硬化数据集概览:")
print(f"数据形状: {cirrhosis_data.shape}")
print(cirrhosis_data.head())
print("\n肝硬化数据集信息:")
print(cirrhosis_data.info())
print("\n肝硬化数据集描述性统计:")
print(cirrhosis_data.describe())
3. 数据预处理函数
心脏病数据预处理
def preprocess_heart_data(data):
"""处理心脏病数据集"""
df = data.copy()
# 缺失值检查
missing_values = df.isnull().sum()
print("心脏病数据集缺失值:")
print(missing_values[missing_values > 0])
# 异常值检查
for col in df.select_dtypes(include=[np.number]).columns:
q1 = df[col].quantile(0.25)
q3 = df[col].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
if not outliers.empty:
print(f"特征 {col} 有 {len(outliers)} 个异常值")
# 分类变量编码
categorical_cols = df.select_dtypes(include=['object']).columns
for col in categorical_cols:
label_encoder = LabelEncoder()
df[col] = label_encoder.fit_transform(df[col])
# 标准化数值特征
features = df.drop('HeartDisease', axis=1)
target = df['HeartDisease']
scaler = StandardScaler()
features_scaled = pd.DataFrame(scaler.fit_transform(features), columns=features.columns)
# 合并处理后的数据
processed_df = pd.concat([features_scaled, target.reset_index(drop=True)], axis=1)
return processed_df
中风数据预处理
def preprocess_stroke_data(data):
"""处理中风数据集"""
df = data.copy()
# 缺失值检查
missing_values = df.isnull().sum()
print("中风数据集缺失值:")
print(missing_values[missing_values > 0])
# 处理N/A值
df['bmi'] = df['bmi'].replace('N/A', np.nan)
df['bmi'] = pd.to_numeric(df['bmi'], errors='coerce')
# 填充缺失值
bmi_imputer = SimpleImputer(strategy='median')
df['bmi'] = bmi_imputer.fit_transform(df[['bmi']])
# 异常值检查
for col in df.select_dtypes(include=[np.number]).columns:
if col not in ['id', 'stroke']:
q1 = df[col].quantile(0.25)
q3 = df[col].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
if not outliers.empty:
print(f"特征 {col} 有 {len(outliers)} 个异常值")
# 分类变量编码
df['gender'] = df['gender'].map({'Male': 0, 'Female': 1})
categorical_cols = ['ever_married', 'work_type', 'Residence_type', 'smoking_status']
for col in categorical_cols:
dummies = pd.get_dummies(df[col], prefix=col, drop_first=True)
df = pd.concat([df, dummies], axis=1)
df.drop(col, axis=1, inplace=True)
# 删除id列并标准化数值特征
df.drop('id', axis=1, inplace=True)
numeric_cols = ['age', 'avg_glucose_level', 'bmi']
scaler = StandardScaler()
df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
return df
肝硬化数据预处理
def preprocess_cirrhosis_data(data):
"""处理肝硬化数据集"""
df = data.copy()
# 缺失值检查
missing_values = df.isnull().sum()
print("肝硬化数据集缺失值:")
print(missing_values[missing_values > 0])
# 填充缺失值
for col in ['Cholesterol', 'Platelets', 'Tryglicerides']:
df[col] = df[col].fillna(df[col].median())
# 异常值检查
for col in df.select_dtypes(include=[np.number]).columns:
if col not in ['ID', 'Stage']:
q1 = df[col].quantile(0.25)
q3 = df[col].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
if not outliers.empty:
print(f"特征 {col} 有 {len(outliers)} 个异常值")
# 分类变量编码
df['Sex'] = df['Sex'].map({'M': 0, 'F': 1})
df['Status'] = df['Status'].map({'C': 0, 'CL': 1, 'D': 2})
df['Drug'] = df['Drug'].map({'D-penicillamine': 0, 'Placebo': 1})
for col in ['Ascites', 'Hepatomegaly', 'Spiders']:
df[col] = df[col].map({'N': 0, 'Y': 1})
df['Edema'] = df['Edema'].map({'N': 0, 'S': 0.5, 'Y': 1})
# 标准化数值特征
numeric_cols = ['N_Days', 'Age', 'Bilirubin', 'Cholesterol', 'Albumin', 'Copper',
'Alk_Phos', 'SGOT', 'Tryglicerides', 'Platelets', 'Prothrombin']
scaler = StandardScaler()
df[numeric_cols] = scaler.fit_transform(df[numeric_cols])
# 创建二分类目标变量(重度肝硬化)
df['Severe_Cirrhosis'] = df['Stage'].apply(lambda x: 1 if x >= 3 else 0)
return df
4. 应用预处理并保存结果
# 应用预处理函数
processed_heart = preprocess_heart_data(heart_data)
processed_stroke = preprocess_stroke_data(stroke_data)
processed_cirrhosis = preprocess_cirrhosis_data(cirrhosis_data)
# 保存预处理后的数据
processed_heart.to_excel('results/问题1_预处理后心脏病数据.xlsx', index=False)
processed_stroke.to_excel('results/问题1_预处理后中风数据.xlsx', index=False)
processed_cirrhosis.to_excel('results/问题1_预处理后肝硬化数据.xlsx', index=False)
5. 相关性分析(以心脏病数据为例)
# 计算心脏病数据集相关性
correlation = processed_heart.corr()
print("心脏病数据集相关性:")
print(correlation['HeartDisease'].sort_values(ascending=False))
# 可视化相关性
plt.figure(figsize=(10, 8))
sns.heatmap(correlation, annot=True, cmap='coolwarm')
plt.title("心脏病数据集特征相关性热力图")
plt.savefig('results/心脏病相关性热力图.png')
plt.show()
结果示例:
疾病 |
关键因素(权重) |
心脏病 |
ST Slope (23.98%)、ChestPainType (14.60%) |
中风 |
年龄 (66.52%)、高血压 (18.13%) |
肝硬化 |
水肿 (42.79%)、生存天数 (18.05%) |
2. 问题2:自适应加权集成学习模型(AWELM)
目标:构建高精度疾病预测模型,适应不同疾病的数据特点。
详细步骤:
- 基础模型选择
- 逻辑回归(线性关系)。
- 随机森林(非线性、特征交互)。
- 梯度提升(残差优化)。
- 支持向量机(高维空间分类)。
- 模型训练与交叉验证
- 使用5折交叉验证评估各模型的AUC、敏感性、特异性。
- 权重优化
- 定义损失函数(带平衡因子和正则化):
- 通过梯度下降优化权重
。
- 定义损失函数(带平衡因子和正则化):
- 集成预测
- 加权平均各模型的预测概率:
- 加权平均各模型的预测概率:
代码
1. 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split, cross_val_predict, StratifiedKFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
from sklearn.metrics import confusion_matrix, classification_report, roc_curve, precision_recall_curve
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.utils import resample
from sklearn.impute import SimpleImputer
from scipy.optimize import minimize
import warnings
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 忽略警告
warnings.filterwarnings('ignore')
# 创建结果目录
if not os.path.exists('results'):
os.makedirs('results')
# 设置随机种子,确保结果可复现
np.random.seed(42)
2. 数据加载
# 数据加载
# 尝试加载问题1保存的预处理数据,如果不存在则加载原始数据
try:
processed_heart = pd.read_excel('results/问题1_预处理后心脏病数据.xlsx')
processed_stroke = pd.read_excel('results/问题1_预处理后中风数据.xlsx')
processed_cirrhosis = pd.read_excel('results/问题1_预处理后肝硬化数据.xlsx')
print("成功加载问题1预处理后的数据")
except:
print("无法加载问题1预处理后的数据,将加载原始数据并进行预处理")
heart_data = pd.read_csv('heart.csv')
stroke_data = pd.read_csv('stroke.csv')
cirrhosis_data = pd.read_csv('cirrhosis.csv')
# 此处可以添加与问题1类似的预处理代码
# 由于我们已经加载了预处理数据,这部分代码暂时不需要
processed_heart = heart_data
processed_stroke = stroke_data
processed_cirrhosis = cirrhosis_data
# 打印数据集信息
print("心脏病数据集形状:", processed_heart.shape)
print("中风数据集形状:", processed_stroke.shape)
print("肝硬化数据集形状:", processed_cirrhosis.shape)
# 显示心脏病数据集前几行
print("\n心脏病数据集预览:")
print(processed_heart.head())
# 查看每个数据集的目标变量分布
print("\n心脏病数据集目标变量分布:")
print(processed_heart['HeartDisease'].value_counts())
print("\n中风数据集目标变量分布:")
print(processed_stroke['stroke'].value_counts())
print("\n肝硬化数据集目标变量分布:")
print(processed_cirrhosis['Severe_Cirrhosis'].value_counts())
3. 准备数据集
# 加载最重要特征的列表
# 可以根据问题1的分析结果或者直接从数据中选择
# 对于心脏病数据集,根据问题1的特征权重分析
heart_important_features = ['ST_Slope', 'ChestPainType', 'Sex', 'ExerciseAngina', 'FastingBS',
'Oldpeak', 'Cholesterol', 'MaxHR', 'Age', 'RestingBP']
# 对于中风数据集
stroke_important_features = ['age', 'avg_glucose_level', 'heart_disease', 'hypertension', 'bmi']
# 对于肝硬化数据集
cirrhosis_important_features = ['Edema', 'N_Days', 'Platelets', 'Tryglicerides', 'Status',
'Bilirubin', 'Albumin']
# 准备数据集
# 心脏病数据
X_heart = processed_heart[heart_important_features]
y_heart = processed_heart['HeartDisease']
# 中风数据
X_stroke = processed_stroke[stroke_important_features]
y_stroke = processed_stroke['stroke']
# 肝硬化数据
X_cirrhosis = processed_cirrhosis[cirrhosis_important_features]
y_cirrhosis = processed_cirrhosis['Severe_Cirrhosis']
# 划分训练集和测试集
X_heart_train, X_heart_test, y_heart_train, y_heart_test = train_test_split(
X_heart, y_heart, test_size=0.2, random_state=42, stratify=y_heart)
X_stroke_train, X_stroke_test, y_stroke_train, y_stroke_test = train_test_split(
X_stroke, y_stroke, test_size=0.2, random_state=42, stratify=y_stroke)
X_cirrhosis_train, X_cirrhosis_test, y_cirrhosis_train, y_cirrhosis_test = train_test_split(
X_cirrhosis, y_cirrhosis, test_size=0.2, random_state=42, stratify=y_cirrhosis)
# 打印训练集和测试集大小
print("心脏病数据集:")
print(f"训练集: {X_heart_train.shape}, 测试集: {X_heart_test.shape}")
print("\n中风数据集:")
print(f"训练集: {X_stroke_train.shape}, 测试集: {X_stroke_test.shape}")
print("\n肝硬化数据集:")
print(f"训练集: {X_cirrhosis_train.shape}, 测试集: {X_cirrhosis_test.shape}")
4. 定义AWELM模型中使用的基础学习器
# 定义AWELM模型中使用的基础学习器
def create_base_models():
"""创建四个基础学习器"""
models = {
"逻辑回归": LogisticRegression(max_iter=1000, random_state=42),
"随机森林": RandomForestClassifier(n_estimators=100, random_state=42),
"梯度提升": GradientBoostingClassifier(n_estimators=100, random_state=42),
"支持向量机": SVC(probability=True, random_state=42)
}
return models
# 处理类别不平衡的函数
def handle_imbalance(X, y, method='smote'):
"""处理类别不平衡"""
if method == 'oversample':
# 简单过采样
minority_class = y[y == 1]
minority_indices = y[y == 1].index
X_minority = X.loc[minority_indices]
# 计算需要过采样的次数
n_samples = len(y[y == 0]) - len(minority_class)
# 过采样
if n_samples > 0:
X_minority_resampled, y_minority_resampled = resample(
X_minority, minority_class,
replace=True,
n_samples=len(minority_class) + n_samples,
random_state=42
)
# 合并过采样的少数类和多数类
X_resampled = pd.concat([X[y == 0], X_minority_resampled])
y_resampled = pd.concat([y[y == 0], y_minority_resampled])
return X_resampled, y_resampled
# 默认返回原始数据
return X, y
# 训练和评估基础模型的函数
def train_and_evaluate_base_models(X_train, y_train, X_test, y_test, models, dataset_name):
"""训练和评估基础模型"""
results = {}
predictions = {}
# 计算类别不平衡比例
imbalance_ratio = len(y_train[y_train == 0]) / len(y_train[y_train == 1])
print(f"{dataset_name} 数据集类别不平衡比例 (负/正): {imbalance_ratio:.2f}")
# 处理严重不平衡的数据集
if imbalance_ratio > 5:
print(f"{dataset_name} 数据集存在严重不平衡,将进行过采样")
X_train_resampled, y_train_resampled = handle_imbalance(X_train, y_train)
print(f"过采样后训练集大小: {X_train_resampled.shape}")
print(f"过采样后目标变量分布: \n{y_train_resampled.value_counts()}")
X_train_for_models = X_train_resampled
y_train_for_models = y_train_resampled
else:
X_train_for_models = X_train
y_train_for_models = y_train
# 训练并评估每个基础模型
for model_name, model in models.items():
print(f"训练 {model_name} 模型...")
# 训练模型
model.fit(X_train_for_models, y_train_for_models)
# 在测试集上进行预测
if hasattr(model, "predict_proba"):
y_pred_proba = model.predict_proba(X_test)[:,1]
else:
# 对于不支持predict_proba的模型,如SVM
y_pred_proba = model.decision_function(X_test)
# 归一化到[0,1]区间
y_pred_proba = (y_pred_proba - y_pred_proba.min()) / (y_pred_proba.max() - y_pred_proba.min())
y_pred = (y_pred_proba >= 0.5).astype(int)
# 计算评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_pred_proba)
# 存储结果
results[model_name] = {
"accuracy": accuracy,
"precision": precision,
"recall": recall,
"f1": f1,
"auc": auc
}
predictions[model_name] = {
"y_pred": y_pred,
"y_pred_proba": y_pred_proba
}
print(f"{model_name} 模型评估结果:")
print(f"准确率: {accuracy:.4f}, 精确率: {precision:.4f}, 召回率: {recall:.4f}, F1分数: {f1:.4f}, AUC: {auc:.4f}")
return results, predictions, models
# 交叉验证获取基础模型预测概率的函数
def get_cv_predictions(X, y, models, n_splits=5):
"""使用交叉验证获取基础模型的预测概率"""
cv_predictions = {}
skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)
for model_name, model in models.items():
print(f"为 {model_name} 获取交叉验证预测...")
# 使用交叉验证获取预测概率
if hasattr(model, "predict_proba"):
y_cv_pred_proba = cross_val_predict(model, X, y, cv=skf, method='predict_proba')[:,1]
else:
# 对于不支持predict_proba的模型,如SVM
y_cv_pred_proba = cross_val_predict(model, X, y, cv=skf, method='decision_function')
# 归一化到[0,1]区间
y_cv_pred_proba = (y_cv_pred_proba - y_cv_pred_proba.min()) / (y_cv_pred_proba.max() - y_cv_pred_proba.min())
cv_predictions[model_name] = y_cv_pred_proba
return cv_predictions
# 优化集成权重的函数
def optimize_weights(cv_predictions, y_true, lambda_reg=0.01):
"""优化集成模型的权重"""
model_names = list(cv_predictions.keys())
n_models = len(model_names)
# 初始化权重为均匀分布
initial_weights = np.ones(n_models) / n_models
# 计算正负样本数量,用于平衡损失函数
n_pos = sum(y_true)
n_neg = len(y_true) - n_pos
beta = n_neg / n_pos if n_pos > 0 else 1.0
# 定义目标函数 (带正则化的交叉熵损失)
def objective(weights):
# 归一化权重确保和为1
weights = weights / np.sum(weights)
# 计算集成预测
ensemble_pred = np.zeros(len(y_true))
for i, model_name in enumerate(model_names):
ensemble_pred += weights[i] * cv_predictions[model_name]
# 限制预测概率范围,避免log(0)
ensemble_pred = np.clip(ensemble_pred, 1e-15, 1-1e-15)
# 计算带平衡因子的交叉熵损失
loss = -np.mean(beta * y_true * np.log(ensemble_pred) +
(1 - y_true) * np.log(1 - ensemble_pred))
# 添加负熵正则化
if lambda_reg > 0:
# 避免log(0)
log_weights = np.log(np.clip(weights, 1e-15, None))
entropy_reg = lambda_reg * np.sum(weights * log_weights)
loss += entropy_reg
return loss
# 约束条件:权重非负
bounds = [(0, 1) for _ in range(n_models)]
# 使用L-BFGS-B优化算法求解
result = minimize(objective, initial_weights, bounds=bounds, method='L-BFGS-B')
# 归一化最终权重确保和为1
optimal_weights = result.x / np.sum(result.x)
return dict(zip(model_names, optimal_weights))
# 使用优化后的权重进行集成预测的函数
def ensemble_predict(predictions, weights):
"""使用优化后的权重进行集成预测"""
ensemble_pred_proba = np.zeros(len(next(iter(predictions.values()))["y_pred_proba"]))
for model_name, weight in weights.items():
ensemble_pred_proba += weight * predictions[model_name]["y_pred_proba"]
ensemble_pred = (ensemble_pred_proba >= 0.5).astype(int)
return ensemble_pred, ensemble_pred_proba
# 评估集成模型的函数
def evaluate_ensemble(y_true, y_pred, y_pred_proba):
"""评估集成模型性能"""
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)
auc = roc_auc_score(y_true, y_pred_proba)
results = {
"accuracy": accuracy,
"precision": precision,
"recall": recall,
"f1": f1,
"auc": auc
}
print("集成模型评估结果:")
print(f"准确率: {accuracy:.4f}, 精确率: {precision:.4f}, 召回率: {recall:.4f}, F1分数: {f1:.4f}, AUC: {auc:.4f}")
return results
5. 训练和评估基础模型
# 创建基础模型
base_models = create_base_models()
# 对三个疾病数据集分别训练和评估模型
print("====================== 心脏病模型 ======================")
heart_results, heart_predictions, heart_models = train_and_evaluate_base_models(
X_heart_train, y_heart_train, X_heart_test, y_heart_test, base_models, "心脏病")
print("\n====================== 中风模型 ======================")
stroke_results, stroke_predictions, stroke_models = train_and_evaluate_base_models(
X_stroke_train, y_stroke_train, X_stroke_test, y_stroke_test, base_models, "中风")
print("\n====================== 肝硬化模型 ======================")
cirrhosis_results, cirrhosis_predictions, cirrhosis_models = train_and_evaluate_base_models(
X_cirrhosis_train, y_cirrhosis_train, X_cirrhosis_test, y_cirrhosis_test, base_models, "肝硬化")
# 保存基础模型评估结果
heart_results_df = pd.DataFrame(heart_results).T
stroke_results_df = pd.DataFrame(stroke_results).T
cirrhosis_results_df = pd.DataFrame(cirrhosis_results).T
# 保存为Excel
with pd.ExcelWriter('results/问题2_基础模型评估结果.xlsx') as writer:
heart_results_df.to_excel(writer, sheet_name='心脏病')
stroke_results_df.to_excel(writer, sheet_name='中风')
cirrhosis_results_df.to_excel(writer, sheet_name='肝硬化')
print("\n基础模型评估结果已保存至 'results/问题2_基础模型评估结果.xlsx'")
6. 优化集成权重
# 对三个数据集获取交叉验证预测
print("获取心脏病数据集的交叉验证预测...")
heart_cv_predictions = get_cv_predictions(X_heart_train, y_heart_train, heart_models)
print("\n获取中风数据集的交叉验证预测...")
stroke_cv_predictions = get_cv_predictions(X_stroke_train, y_stroke_train, stroke_models)
print("\n获取肝硬化数据集的交叉验证预测...")
cirrhosis_cv_predictions = get_cv_predictions(X_cirrhosis_train, y_cirrhosis_train, cirrhosis_models)
# 优化三个数据集的集成权重
print("\n优化心脏病模型的集成权重...")
heart_weights = optimize_weights(heart_cv_predictions, y_heart_train)
print("心脏病模型最优权重:", heart_weights)
print("\n优化中风模型的集成权重...")
stroke_weights = optimize_weights(stroke_cv_predictions, y_stroke_train)
print("中风模型最优权重:", stroke_weights)
print("\n优化肝硬化模型的集成权重...")
cirrhosis_weights = optimize_weights(cirrhosis_cv_predictions, y_cirrhosis_train)
print("肝硬化模型最优权重:", cirrhosis_weights)
# 保存最优权重
weights_df = pd.DataFrame({
'心脏病': heart_weights,
'中风': stroke_weights,
'肝硬化': cirrhosis_weights
})
weights_df.to_excel('results/问题2_最优集成权重.xlsx')
print("\n最优集成权重已保存至 'results/问题2_最优集成权重.xlsx'")
7. 使用优化权重进行集成预测
# 使用优化后的权重进行集成预测
print("使用优化权重进行心脏病集成预测...")
heart_ensemble_pred, heart_ensemble_proba = ensemble_predict(heart_predictions, heart_weights)
heart_ensemble_results = evaluate_ensemble(y_heart_test, heart_ensemble_pred, heart_ensemble_proba)
print("\n使用优化权重进行中风集成预测...")
stroke_ensemble_pred, stroke_ensemble_proba = ensemble_predict(stroke_predictions, stroke_weights)
stroke_ensemble_results = evaluate_ensemble(y_stroke_test, stroke_ensemble_pred, stroke_ensemble_proba)
print("\n使用优化权重进行肝硬化集成预测...")
cirrhosis_ensemble_pred, cirrhosis_ensemble_proba = ensemble_predict(cirrhosis_predictions, cirrhosis_weights)
cirrhosis_ensemble_results = evaluate_ensemble(y_cirrhosis_test, cirrhosis_ensemble_pred, cirrhosis_ensemble_proba)
# 将集成模型和基础模型的结果合并比较
heart_comparison = heart_results_df.copy()
heart_comparison.loc['集成模型'] = pd.Series(heart_ensemble_results)
stroke_comparison = stroke_results_df.copy()
stroke_comparison.loc['集成模型'] = pd.Series(stroke_ensemble_results)
cirrhosis_comparison = cirrhosis_results_df.copy()
cirrhosis_comparison.loc['集成模型'] = pd.Series(cirrhosis_ensemble_results)
# 保存比较结果
with pd.ExcelWriter('results/问题2_模型比较结果.xlsx') as writer:
heart_comparison.to_excel(writer, sheet_name='心脏病')
stroke_comparison.to_excel(writer, sheet_name='中风')
cirrhosis_comparison.to_excel(writer, sheet_name='肝硬化')
print("\n模型比较结果已保存至 'results/问题2_模型比较结果.xlsx'")
结果示例:
疾病 |
最佳模型(权重) |
AUC |
敏感性 |
特异性 |
心脏病 |
随机森林 (0.41) |
0.930 |
0.912 |
0.866 |
中风 |
逻辑回归 (0.58) |
0.842 |
0.000 |
0.999 |
肝硬化 |
逻辑回归 (0.63) |
0.599 |
0.900 |
0.250 |
3. 问题3:贝叶斯网络多疾病关联概率模型(BNMDAP)
目标:量化疾病间的共病关联,预测多疾病同时发生的概率。
详细步骤:
- 网络结构定义
- 节点:疾病(
)和共同风险因素(如高血压)。
- 边:疾病间的条件依赖关系(如
)。
- 节点:疾病(
- 条件概率表(CPT)估计
- 基于单一疾病预测模型的输出。
- 结合医学知识(如文献中的相对风险比)。
- 联合概率计算
- 例如,三种疾病共病的概率:
- 例如,三种疾病共病的概率:
- 关联强度量化
- 相对风险比(RR):
- 条件概率比(CPR):
- 相对风险比(RR):
代码
# 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import BernoulliNB, GaussianNB
from sklearn.metrics import roc_auc_score, confusion_matrix, classification_report
from sklearn.preprocessing import StandardScaler
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时负号'-'显示为方块的问题
# 加载问题1预处理后的数据
try:
processed_heart = pd.read_excel('results/问题1_预处理后心脏病数据.xlsx')
processed_stroke = pd.read_excel('results/问题1_预处理后中风数据.xlsx')
processed_cirrhosis = pd.read_excel('results/问题1_预处理后肝硬化数据.xlsx')
heart_data = processed_heart
stroke_data = processed_stroke
cirrhosis_data = processed_cirrhosis
print("成功加载预处理后的数据")
except FileNotFoundError:
print("无法找到预处理数据")
print(f"心脏病数据集形状: {heart_data.shape}")
print(f"中风数据集形状: {stroke_data.shape}")
print(f"肝硬化数据集形状: {cirrhosis_data.shape}")
print('唯一原创作者:B站北辰single ,原创地址: https://www.yuque.com/u42168770/qv6z0d/ykf7pgg8etog98ik?singleDoc# ')
# 各疾病正例比例
heart_ratio = heart_data['target'].mean()
stroke_ratio = stroke_data['stroke'].mean()
cirrhosis_ratio = cirrhosis_data['Status'].map({'C': 1, 'CL': 0}).mean()
print("\n各疾病正例比例:")
print(f"心脏病患病比例: {heart_ratio:.4f}")
print(f"中风患病比例: {stroke_ratio:.4f}")
print(f"肝硬化患病比例: {cirrhosis_ratio:.4f}")
# 绘制正例比例图
plt.figure(figsize=(10, 6))
diseases = ['心脏病', '中风', '肝硬化']
ratios = [heart_ratio, stroke_ratio, cirrhosis_ratio]
plt.bar(diseases, ratios, color=['red', 'blue', 'green'])
plt.title('各疾病正例比例')
plt.ylabel('比例')
plt.show()
结果示例:
- 心脏病与中风的关联最强(
)。
- 高血压使共病风险显著增加(如心脏病+中风风险提高2.24倍)。
4. 问题4:综合预防策略建议
核心建议:
- 高血压控制:作为三种疾病的共同风险因素,优先干预。
- 分层筛查:
- 低风险人群:健康教育。
- 高风险人群(如老年高血压患者):定期监测和药物干预。
- 数字健康工具:开发个性化风险评估APP。
问题1:权重计算
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
def calculate_feature_weights(X, y):
# 单变量分析
univariate_auc = []
for col in X.columns:
model = LogisticRegression().fit(X[[col]], y)
univariate_auc.append(roc_auc_score(y, model.predict_proba(X[[col]])[:, 1]))
# 多变量分析
full_model = LogisticRegression().fit(X, y)
full_auc = roc_auc_score(y, full_model.predict_proba(X)[:, 1])
# 计算ΔAUC
delta_auc = []
for col in X.columns:
X_reduced = X.drop(col, axis=1)
reduced_model = LogisticRegression().fit(X_reduced, y)
reduced_auc = roc_auc_score(y, reduced_model.predict_proba(X_reduced)[:, 1])
delta_auc.append(full_auc - reduced_auc)
# 综合权重
weights = np.abs(full_model.coef_[0]) * (1 - p_values) * (1 + delta_auc)
normalized_weights = 100 * weights / weights.sum()
return normalized_weights
问题2:集成学习
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from scipy.optimize import minimize
def optimize_weights(X, y, models):
# 获取各模型的交叉验证预测概率
cv_probs = [cross_val_predict(model, X, y, method='predict_proba')[:, 1] for model in models]
# 定义损失函数
def loss(w):
combined_prob = np.sum(w * np.array(cv_probs), axis=0)
return -np.mean(y * np.log(combined_prob) + (1 - y) * np.log(1 - combined_prob))
# 约束:权重和为1且非负
constraints = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
bounds = [(0, 1) for _ in models]
result = minimize(loss, x0=[1/len(models)]*len(models), bounds=bounds, constraints=constraints)
return result.x
问题3:贝叶斯网络
from pgmpy.models import BayesianModel
from pgmpy.estimators import MaximumLikelihoodEstimator
# 定义网络结构
model = BayesianModel([('Hypertension', 'HeartDisease'),
('HeartDisease', 'Stroke'),
('LiverDisease', 'Stroke')])
# 拟合条件概率表
model.fit(data, estimator=MaximumLikelihoodEstimator)
# 计算共病概率
query = model.predict_probability({'HeartDisease': 1, 'Stroke': 1, 'LiverDisease': 1})
总结
- 问题1:通过统计与机器学习结合,量化风险因素重要性。
- 问题2:集成学习自适应调整权重,提升预测性能。
- 问题3:贝叶斯网络揭示疾病关联机制。
- 问题4:基于模型结果提出可操作的预防策略。