机器学习大作业

文章目录


这是机器学习的一个大作业,主要用到了逻辑斯蒂算法、KNN算法、随机森林算法。
数据集是糖尿病的数据集。

import pandas as pd
import numpy as np
import warnings
import math
import lightgbm as lgb
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV,cross_val_score
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier, StackingClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
from sklearn.decomposition import PCA
from sklearn.metrics import roc_curve


from matplotlib import rcParams
warnings.filterwarnings('ignore')
#步骤1 todo:读取数据
df = pd.read_csv('diabetes_data_upload.csv', delimiter=',')
df.columns = ['Age', 'Gender', 'Polyuria', 'Polydipsia', 'sudden weight loss', 'weakness', 'Polyphagia', 'Genital thrush', 'visual blurring', 'Itching', 'Irritability', 'delayed healing', 'partial paresis', 'muscle stiffness', 'Alopecia', 'Obesity', 'class']
#步骤1.1 了解数据基本信息
print(df.head())
print(df.describe())
#步骤1.2 查看数据是否有缺失值情况
print('数据缺失值情况:\n', df.isna().sum())
# 数据清洗,去掉weakness
# data.drop(columns=['weakness'],axis=1,inplace=True)
#步骤1.3 对数据进行处理
df['Gender'] = df['Gender'].map({'Male': 1, 'Female': 0})
# 步骤1.4 目标变量中为字符串型数据,使用labelEncoder处理编码(spam-1,ham-0)
le = LabelEncoder()#转换成数值数据,对定型特征多值化
for col in df.columns:
    if df[col].dtype == 'object':
        df[col] = le.fit_transform(df[col])
# 步骤1.5 标准化处理,使用StandardScaler
#对 DataFrame 中的除最后一列外的所有数值类型的特征进行标准化处理,即将每个特征减去其均值后再除以标准差。
scaler = StandardScaler()
df[df.columns[:-1]] = scaler.fit_transform(df[df.columns[:-1]])
# 步骤1.6 特征工程
X = df[df.columns[:-1]]
y = df['class']
#步骤1.7 todo:对整体数据按照train_size进行划分,得到训练集和测试集, random_state确保结果的一致性
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.66)


# 步骤2 todo:可视化分析
# 统计年龄变量的分布情况
plt.figure(figsize=(8, 5))
# 将年龄划分为10个区间
age_bins = pd.cut(df['Age'], bins=10,labels=['{}-{}'.format(i*6+30, i*6+35) for i in range(10)])
# 统计每个区间的样本数量
age_counts = age_bins.value_counts().sort_index()
plt.bar(x=age_counts.index.astype(str), height=age_counts.values)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('年龄特征分布与异常值', fontsize=15)
plt.xlabel('年龄')
plt.ylabel('Count')
plt.savefig('./results/Age characteristic_distribution_and_outliers.png')
plt.show()
#统计不同性别糖尿病的情况
#将数据集 df 中的所有样本根据 'Gender' 列的取值进行分类,
# 并计算每个分类中 'class' 列的计数,最后将不同分类的计数以柱状图的形式绘制出来
plt.figure(figsize=(8, 5))
sns.countplot(x='Gender', data=df, hue='class')
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('不同性别糖尿病的情况', fontsize=15)
plt.xticks(ticks=[0, 1], labels=['Female', 'Male'])
plt.savefig('./results/Diabetes_mellitus_of_different_genders.png')
plt.show()
#统计Polydipsia(过度口渴)对糖尿病的情况
plt.figure(figsize=(8, 5))
sns.countplot(x='Polydipsia', data=df, hue='class')
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('过度口渴对糖尿病的情况', fontsize=15)
plt.xticks(ticks=[0, 1], labels=['Female', 'Male'])
plt.savefig('./results/Excessive_thirst_in_the_case_of_diabetes.png')
plt.show()
#统计Polyuria(多尿症)对糖尿病的情况
plt.figure(figsize=(8, 5))
sns.countplot(x='Polyuria', data=df, hue='class')
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('多尿症对糖尿病的情况', fontsize=15)
plt.xticks(ticks=[0, 1], labels=['Female', 'Male'])
plt.savefig('./results/Polyuria_is_a_case_of_diabetes.png')
plt.show()

# PCA 降维可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
df_pca = pd.DataFrame(X_pca, columns=['PC1', 'PC2'])
df_pca['class'] = y
sns.set(font_scale=1.2)
sns.scatterplot(x='PC1', y='PC2', hue='class', data=df_pca)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('主成分可视化', fontsize=10)
plt.savefig('./results/PCA_Visualization.png')
plt.show()
# 相关性分析
corr = df.corr()#计算相关性矩阵
#创建矩阵掩码以隐藏重复值
mask = np.triu(np.ones_like(corr, dtype=bool))
# 设置全局图形风格
plt.figure(figsize=(9, 6))
# 绘制相关性热图
sns.heatmap(corr, mask=mask, cmap='coolwarm', annot=True, fmt='.2f', annot_kws={'size': 5})
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title('相关性热图', fontsize=15)
plt.savefig('./results/Correlation_Matrix.png')
plt.show()

# 步骤3 todo:模型训练、测试、评估
# 步骤3.1 todo:模型训练和评估
#定义基分类器
lr = LogisticRegression()
knn = KNeighborsClassifier()
rf = RandomForestClassifier()
# 建立五种模型并交叉验证,使用sklearn中的不同分类器,LogisticRegression, KNeighborsClassifier, RandomForestClassifier,
models = [lr, knn, rf]
names = ['Logistic Regression', 'KNN', 'Random Forest']
scores = []
for model in models:
    score = cross_val_score(model, X, y, cv=5, scoring='accuracy').mean()
    scores.append(score)
cv_test=score
# 输出各模型预测平均得分
results = pd.DataFrame({'Model': names, 'Score': scores})
print(results)
# 使用Stacking集成学习(LR),定义元分类器
stack = StackingClassifier(estimators=[('lr', lr), ('knn', knn), ('rf', rf)],
                           final_estimator=LogisticRegression())
params = {
    'lr__C': [0.1,0.5],
    'knn__n_neighbors': [3,5],
    'rf__n_estimators': [50,100],
    'rf__max_depth': [5,7],
    'final_estimator__C': [1.0,10]
}
grid = GridSearchCV(stack, params, cv=5, scoring='accuracy', n_jobs=-1)
grid.fit(X, y)
# 打印出最佳的模型参数
print(grid.best_params_)
## 最佳模型已经通过网格搜索得到了,不需要再次拟合,直接使用即可
best_model = grid.best_estimator_
best_model.fit(X_train, y_train)

# 步骤3.2 todo: 计算分类评价指标:测试集的准确率accuracy、精确率precision、召回率recall和综合评价指标 F1 值
y_pred = grid.predict(X_test)#利用最优模型来预测
accuracy = accuracy_score(y_test, y_pred)  # 准确率
precision = precision_score(y_test, y_pred, average='macro')  # 精确率
recall = recall_score(y_test, y_pred, average='macro')  # 召回率
f1 = f1_score(y_test, y_pred, average='macro')  # F1值
print('Accuracy: {:.6f}'.format(accuracy))
print('Precision: {:.6f}'.format(precision))
print('Recall: {:.6f}'.format(recall))
print('F1 score: {:.6f}'.format(f1))
print('cv_test: {:.6f}'.format(cv_test))
# 将评价指标保存到本地
df = pd.DataFrame({'Accuracy': [accuracy], 'Precision': [precision], 'Recall': [recall], 'F1 score': [f1], 'cv_test': [cv_test]})
file_name_csv = 'evaluation_results.csv'
df.to_csv(file_name_csv, index=False)
# 步骤3.3 todo: 绘制ROC曲线,计算auc,度量分类模型的预测能力
#计算预测概率值
y_prob = grid.predict_proba(X_test)[:, 1]
#计算假正率(fpr)、真正率(tpr)以及阈值(thresholds)
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
#计算auc值
auc_score = roc_auc_score(y_test, y_prob)
#绘制ROC曲线
plt.plot(fpr, tpr, color='blue', label='ROC curve (area = %0.2f)' % auc_score)
plt.plot([0, 1], [0, 1], color='red', linestyle='--', label='Random Guess')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.04])
plt.xlabel('假正例率')
plt.ylabel('真正例率(召回率)')
plt.title('Receiver operating characteristic (ROC) Curve')
plt.legend(loc="lower right")
plt.savefig('./results/ROC_Curve.png')
plt.show()

# 步骤3.4 todo:特征重要性分析(RF)
feature_importances = grid.best_estimator_.named_estimators_['rf'].feature_importances_
# 获取特征名称
feature_names = X.columns
# 对数据框进行排序
feature_df = pd.DataFrame({'Feature': feature_names, 'Importance': feature_importances})
feature_df.sort_values(by='Importance', ascending=False, inplace=True)
# 归一化特征重要性
total_importance = feature_df['Importance'].sum()
feature_df['Importance_perc'] = feature_df['Importance'] / total_importance * 100
#使用 seaborn 绘制条形图展示特征的重要性
plt.figure(figsize=(9,6))
ax = sns.barplot(x='Feature', y='Importance_perc', data=feature_df)
ax.set_xticklabels(ax.get_xticklabels(), rotation=90, fontsize=8)
ax.set_ylabel('Importance (%)', fontsize=8)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
ax.set_title("随机森林特征分析", fontsize=15, pad=10)
plt.savefig('./results/Random_Forest_Feature_Importance.png')
plt.show()
print("模型结束")

你可能感兴趣的:(机器学习,机器学习,python,数学建模)