2025年第十五届APMCM亚太地区大学生数学建模竞赛中文赛项B题详细思路与分析(含可运行代码)

1. 问题1:多因素影响权重评估模型

目标:量化各因素对疾病风险的影响程度,识别关键风险因素。
方法:结合统计显著性和预测贡献,构建综合权重评估模型。

详细步骤

  1. 数据预处理
    • 处理缺失值(均值/中位数填充、多重插补)。
    • 异常值检测(箱线图、Z-score)。
    • 标准化(Z-score或Min-Max)。
  2. 单变量分析
    • 对每个特征进行单变量逻辑回归,计算:
      • 回归系数(
      • p值(
      • 优势比(OR)
      • AUC(单变量模型的预测能力)
  3. 多变量分析
    • 构建多变量逻辑回归模型,计算调整后的回归系数()。
    • 计算特征对模型性能的独立贡献():
      • 移除特征  后,观察AUC下降幅度。
  4. 权重计算
    • 综合权重公式:
    • 标准化权重(百分比形式):
  5. 关键特征筛选
    • 按权重排序,绘制累积影响度曲线(如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

目标:构建高精度疾病预测模型,适应不同疾病的数据特点。

详细步骤

  1. 基础模型选择
    • 逻辑回归(线性关系)。
    • 随机森林(非线性、特征交互)。
    • 梯度提升(残差优化)。
    • 支持向量机(高维空间分类)。
  2. 模型训练与交叉验证
    • 使用5折交叉验证评估各模型的AUC、敏感性、特异性。
  3. 权重优化
    • 定义损失函数(带平衡因子和正则化):
    • 通过梯度下降优化权重
  4. 集成预测
    • 加权平均各模型的预测概率:

代码

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

目标:量化疾病间的共病关联,预测多疾病同时发生的概率。

详细步骤

  1. 网络结构定义
    • 节点:疾病()和共同风险因素(如高血压)。
    • 边:疾病间的条件依赖关系(如 )。
  2. 条件概率表(CPT)估计
    • 基于单一疾病预测模型的输出。
    • 结合医学知识(如文献中的相对风险比)。
  3. 联合概率计算
    • 例如,三种疾病共病的概率:
  4. 关联强度量化
    • 相对风险比(RR):
    • 条件概率比(CPR):

代码

# 导入必要的库
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:综合预防策略建议

核心建议

  1. 高血压控制:作为三种疾病的共同风险因素,优先干预。
  2. 分层筛查
    • 低风险人群:健康教育。
    • 高风险人群(如老年高血压患者):定期监测和药物干预。
  3. 数字健康工具:开发个性化风险评估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:基于模型结果提出可操作的预防策略。

第十一apmcm亚太地区大学生数学建模竞赛多个问,其中一个问是关于城市交通规划的。这个问要求参赛者设计一个新型的交通系统,以减少交通拥堵和优化交通效率。 参赛者需要考虑以下几个因素:城市的地理特征、人口密度、交通工具的流动性以及人们的出行需求。参赛者需要根据这些因素,利用数学建模的方法来确定最佳的交通网络。 在解决这个问时,参赛者可以利用图论、网络流等数学工具。他们可以通过建立交通网络图,将城市的道路和交通节点抽象为图的顶点和边,并在图的边上设置流量的限制,来模拟交通的流动情况。然后,利用网络流算法来优化交通流量,减少拥堵和提高交通效率。 此外,参赛者还要考虑到城市人口的分布和出行需求。他们可以利用统计学方法对人口数据进行分析,确定人口的分布规律,并结合出行调查数据来确定人们的主要出行方式和目的地。通过将人口和出行数据交通网络图结合起来,参赛者可以建立一个综合模型,以优化交通规划。 最后,参赛者需要对他们的数学模型进行合理性检验。他们可以通过模拟和实地调查来验证模型的有效性,并根据真实数据进行误差分析。同时,他们还需要考虑到模型的可行性和可操作性,确保他们的交通规划方案能够在实际中实施。 总的来说,第十一apmcm亚太地区大学生数学建模竞赛的城市交通规划问是一个综合性的问,需要参赛者综合运用数学建模、统计学、图论和网络流等知识和方法,来设计一个效果好且可行的交通系统。这个问考察了参赛者解决实际问的能力和创新思维。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值