Python训练营打卡——DAY18(2025.5.7)

目录

一、基于聚类进一步推断类型

1. 聚类分析

2. 簇的总结与定义

二、作业

1. 聚类分析

2. 簇的总结与定义

3. 模型效果提升


一、基于聚类进一步推断类型

选用昨天kmeans得到的效果进行聚类,进而推断出每个簇的实际含义。

1. 聚类分析

# 先运行之前预处理好的代码
import pandas as pd
import pandas as pd    #用于数据处理和分析,可处理表格数据。
import numpy as np     #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt    #用于绘制各种类型的图表
import seaborn as sns   #基于matplotlib的高级绘图库,能绘制更美观的统计图形。
import warnings
warnings.filterwarnings("ignore")
 
 # 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False    # 正常显示负号
data = pd.read_csv('data.csv')    #读取数据


# 先筛选字符串变量 
discrete_features = data.select_dtypes(include=['object']).columns.tolist()
# Home Ownership 标签编码
home_ownership_mapping = {
    'Own Home': 1,
    'Rent': 2,
    'Have Mortgage': 3,
    'Home Mortgage': 4
}
data['Home Ownership'] = data['Home Ownership'].map(home_ownership_mapping)

# Years in current job 标签编码
years_in_job_mapping = {
    '< 1 year': 1,
    '1 year': 2,
    '2 years': 3,
    '3 years': 4,
    '4 years': 5,
    '5 years': 6,
    '6 years': 7,
    '7 years': 8,
    '8 years': 9,
    '9 years': 10,
    '10+ years': 11
}
data['Years in current job'] = data['Years in current job'].map(years_in_job_mapping)

# Purpose 独热编码,记得需要将bool类型转换为数值
data = pd.get_dummies(data, columns=['Purpose'])
data2 = pd.read_csv("data.csv") # 重新读取数据,用来做列名对比
list_final = [] # 新建一个空列表,用于存放独热编码后新增的特征名
for i in data.columns:
    if i not in data2.columns:
       list_final.append(i) # 这里打印出来的就是独热编码后的特征名
for i in list_final:
    data[i] = data[i].astype(int) # 这里的i就是独热编码后的特征名



# Term 0 - 1 映射
term_mapping = {
    'Short Term': 0,
    'Long Term': 1
}
data['Term'] = data['Term'].map(term_mapping)
data.rename(columns={'Term': 'Long Term'}, inplace=True) # 重命名列
continuous_features = data.select_dtypes(include=['int64', 'float64']).columns.tolist()  #把筛选出来的列名转换成列表
 
 # 连续特征用中位数补全
for feature in continuous_features:     
    mode_value = data[feature].mode()[0]            #获取该列的众数。
    data[feature].fillna(mode_value, inplace=True)          #用众数填充该列的缺失值,inplace=True表示直接在原数据上修改。

# 最开始也说了 很多调参函数自带交叉验证,甚至是必选的参数,你如果想要不交叉反而实现起来会麻烦很多
# 所以这里我们还是只划分一次数据集
from sklearn.model_selection import train_test_split
X = data.drop(['Credit Default'], axis=1)  # 特征,axis=1表示按列删除
y = data['Credit Default'] # 标签
# # 按照8:2划分训练集和测试集
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # 80%训练集,20%测试集
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns

# 标准化数据(聚类前通常需要标准化)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# X_scaled
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score
import matplotlib.pyplot as plt
import seaborn as sns

# 评估不同 k 值下的指标
k_range = range(2, 11)  # 测试 k 从 2 到 10
inertia_values = []
silhouette_scores = []
ch_scores = []
db_scores = []

for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans_labels = kmeans.fit_predict(X_scaled)
    inertia_values.append(kmeans.inertia_)  # 惯性(肘部法则)
    silhouette = silhouette_score(X_scaled, kmeans_labels)  # 轮廓系数
    silhouette_scores.append(silhouette)
    ch = calinski_harabasz_score(X_scaled, kmeans_labels)  # CH 指数
    ch_scores.append(ch)
    db = davies_bouldin_score(X_scaled, kmeans_labels)  # DB 指数
    db_scores.append(db)
    print(f"k={k}, 惯性: {kmeans.inertia_:.2f}, 轮廓系数: {silhouette:.3f}, CH 指数: {ch:.2f}, DB 指数: {db:.3f}")

# # 绘制评估指标图
# plt.figure(figsize=(15, 10))

# # 肘部法则图(Inertia)
# plt.subplot(2, 2, 1)
# plt.plot(k_range, inertia_values, marker='o')
# plt.title('肘部法则确定最优聚类数 k(惯性,越小越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('惯性')
# plt.grid(True)

# # 轮廓系数图
# plt.subplot(2, 2, 2)
# plt.plot(k_range, silhouette_scores, marker='o', color='orange')
# plt.title('轮廓系数确定最优聚类数 k(越大越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('轮廓系数')
# plt.grid(True)

# # CH 指数图
# plt.subplot(2, 2, 3)
# plt.plot(k_range, ch_scores, marker='o', color='green')
# plt.title('Calinski-Harabasz 指数确定最优聚类数 k(越大越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('CH 指数')
# plt.grid(True)

# # DB 指数图
# plt.subplot(2, 2, 4)
# plt.plot(k_range, db_scores, marker='o', color='red')
# plt.title('Davies-Bouldin 指数确定最优聚类数 k(越小越好)')
# plt.xlabel('聚类数 (k)')
# plt.ylabel('DB 指数')
# plt.grid(True)

# plt.tight_layout()
# plt.show()

# 提示用户选择 k 值
selected_k = 3 # 这里选择3后面好分析,也可以根据图选择最佳的k值

# 使用选择的 k 值进行 KMeans 聚类
kmeans = KMeans(n_clusters=selected_k, random_state=42)
kmeans_labels = kmeans.fit_predict(X_scaled)
X['KMeans_Cluster'] = kmeans_labels

# 使用 PCA 降维到 2D 进行可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# KMeans 聚类结果可视化
plt.figure(figsize=(6, 5))
sns.scatterplot(x=X_pca[:, 0], y=X_pca[:, 1], hue=kmeans_labels, palette='viridis')
plt.title(f'KMeans Clustering with k={selected_k} (PCA Visualization)')
plt.xlabel('PCA Component 1')
plt.ylabel('PCA Component 2')
plt.show()

# 打印 KMeans 聚类标签的前几行
print(f"KMeans Cluster labels (k={selected_k}) added to X:")
print(X[['KMeans_Cluster']].value_counts())
k=2, 惯性: 218529.50, 轮廓系数: 0.320, CH 指数: 479.34, DB 指数: 3.222
k=3, 惯性: 207982.87, 轮廓系数: 0.209, CH 指数: 441.88, DB 指数: 2.906
k=4, 惯性: 200477.28, 轮廓系数: 0.220, CH 指数: 399.12, DB 指数: 2.441
k=5, 惯性: 192940.36, 轮廓系数: 0.224, CH 指数: 384.19, DB 指数: 2.042
k=6, 惯性: 185411.81, 轮廓系数: 0.227, CH 指数: 380.64, DB 指数: 1.733
k=7, 惯性: 178444.49, 轮廓系数: 0.130, CH 指数: 378.31, DB 指数: 1.633
k=8, 惯性: 174920.27, 轮廓系数: 0.143, CH 指数: 352.31, DB 指数: 1.817
k=9, 惯性: 167383.96, 轮廓系数: 0.150, CH 指数: 364.27, DB 指数: 1.636
k=10, 惯性: 159824.84, 轮廓系数: 0.156, CH 指数: 378.43, DB 指数: 1.502

KMeans Cluster labels (k=3) added to X:
KMeans_Cluster
0                 5205
1                 1381
2                  914
dtype: int64

现在需要给这个簇赋予实际的含义,一般当你赋予实际含义的时候,你需要根据某几个特征来赋予,但是源数据特征很多,如何选择特征呢?有2种思路:

  1. 你最开始聚类的时候,就选择了你想最后用来确定簇含义的特征,那么你需要选择一些特征来进行聚类,那么你最后确定簇含义的特征就是这几个特征,而非全部。如你想聚类消费者购买习惯,那么他过去的消费记录、购买记录、购买金额等等,这些特征都与消费者购买习惯有关,你可以使用这些特征来确定簇含义,一些其他的特征,如消费者年龄,工作行业则不考虑。----适用于你本身就有构造某些明确含义的特征的情况。

  2. 最开始用全部特征来聚类,把其余特征作为 x,聚类得到的簇类别作为标签构建监督模型,进而根据重要性筛选特征,来确定要根据哪些特征赋予含义。---使用于你想构造什么,目前还不清楚。

【上面这个思路好好学,这是真干货,构造具有价值的特征工程,妥妥的创新点和工作量】

X.columns
Index(['Id', 'Home Ownership', 'Annual Income', 'Years in current job',
       'Tax Liens', 'Number of Open Accounts', 'Years of Credit History',
       'Maximum Open Credit', 'Number of Credit Problems',
       'Months since last delinquent', 'Bankruptcies', 'Long Term',
       'Current Loan Amount', 'Current Credit Balance', 'Monthly Debt',
       'Credit Score', 'Purpose_business loan', 'Purpose_buy a car',
       'Purpose_buy house', 'Purpose_debt consolidation',
       'Purpose_educational expenses', 'Purpose_home improvements',
       'Purpose_major purchase', 'Purpose_medical bills', 'Purpose_moving',
       'Purpose_other', 'Purpose_renewable energy', 'Purpose_small business',
       'Purpose_take a trip', 'Purpose_vacation', 'Purpose_wedding',
       'KMeans_Cluster'],
      dtype='object')
x1= X.drop('KMeans_Cluster',axis=1) # 删除聚类标签列
y1 = X['KMeans_Cluster']
# 构建随机森林,用shap重要性来筛选重要性
import shap
import numpy as np
from sklearn.ensemble import RandomForestClassifier  # 随机森林分类器
model = RandomForestClassifier(n_estimators=100, random_state=42)  # 随机森林模型
model.fit(x1, y1)  # 训练模型,此时无需在意准确率 直接全部数据用来训练了
RandomForestClassifier(random_state=42)

In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

shap.initjs()
# 初始化 SHAP 解释器
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(x1) # 这个计算耗时
shap_values.shape # 第一维是样本数,第二维是特征数,第三维是类别数

(7500, 31, 3)
# --- 1. SHAP 特征重要性条形图 (Summary Plot - Bar) ---
print("--- 1. SHAP 特征重要性条形图 ---")
shap.summary_plot(shap_values[:, :, 0], x1, plot_type="bar",show=False)  #  这里的show=False表示不直接显示图形,这样可以继续用plt来修改元素,不然就直接输出了
plt.title("SHAP Feature Importance (Bar Plot)")
plt.show()
--- 1. SHAP 特征重要性条形图 ---

# 此时判断一下这几个特征是离散型还是连续型
import pandas as pd
selected_features = ['Purpose_debt consolidation', 'Bankruptcies',
                     'Number of Credit Problems', 'Purpose_other']

for feature in selected_features:
    unique_count = X[feature].nunique() # 唯一值指的是在某一列或某个特征中,不重复出现的值
    # 连续型变量通常有很多唯一值,而离散型变量的唯一值较少
    print(f'{feature} 的唯一值数量: {unique_count}')
    if unique_count < 10:  # 这里 10 是一个经验阈值,可以根据实际情况调整
        print(f'{feature} 可能是离散型变量')
    else:
        print(f'{feature} 可能是连续型变量')
Purpose_debt consolidation 的唯一值数量: 2
Purpose_debt consolidation 可能是离散型变量
Bankruptcies 的唯一值数量: 5
Bankruptcies 可能是离散型变量
Number of Credit Problems 的唯一值数量: 8
Number of Credit Problems 可能是离散型变量
Purpose_other 的唯一值数量: 2
Purpose_other 可能是离散型变量
# X["Purpose_debt consolidation"].value_counts() # 统计每个唯一值的出现次数
import matplotlib.pyplot as plt

# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X[feature], bins=20)
    axes[i].set_title(f'Histogram of {feature}')
    axes[i].set_xlabel(feature)
    axes[i].set_ylabel('Frequency')

plt.tight_layout()
plt.show()

# 绘制出每个簇对应的这四个特征的分布图
X[['KMeans_Cluster']].value_counts()
KMeans_Cluster
0                 5205
1                 1381
2                  914
dtype: int64
# 分别筛选出每个簇的数据
X_cluster0 = X[X['KMeans_Cluster'] == 0]
X_cluster1 = X[X['KMeans_Cluster'] == 1]
X_cluster2 = X[X['KMeans_Cluster'] == 2]
# 先绘制簇0的分布图

import matplotlib.pyplot as plt

# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster0[feature], bins=20)
    axes[i].set_title(f'Histogram of {feature}')
    axes[i].set_xlabel(feature)
    axes[i].set_ylabel('Frequency')

plt.tight_layout()
plt.show()

# 先绘制簇0的分布图

import matplotlib.pyplot as plt

# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster1[feature], bins=20)
    axes[i].set_title(f'Histogram of {feature}')
    axes[i].set_xlabel(feature)
    axes[i].set_ylabel('Frequency')

plt.tight_layout()
plt.show()

# 先绘制簇2的分布图

import matplotlib.pyplot as plt

# 总样本中的前四个重要性的特征分布图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes = axes.flatten()

for i, feature in enumerate(selected_features):
    axes[i].hist(X_cluster2[feature], bins=20)
    axes[i].set_title(f'Histogram of {feature}')
    axes[i].set_xlabel(feature)
    axes[i].set_ylabel('Frequency')

plt.tight_layout()
plt.show()

把这三个簇的图发给ai,让ai给你定义

2. 簇的总结与定义

  1. 第一个簇 - 优质信用稳健财务型
    • 特征总结:在债务合并用途上表现一致,几乎无破产记录,信用问题极少,资金用途集中且很少涉及特殊类别。财务状况稳定,信用良好,资金流向明确。
    • 定义依据:各项关键财务和信用指标表现优异,显示出良好的财务自律性和信用履约能力,所以定义为 “优质信用稳健财务型”。
  2. 第二个簇 - 较稳健但信用有分化财务型
    • 特征总结:多数无债务合并需求,破产情况少见,但信用问题上存在个体差异,资金用途有一定分散性。整体财务状况相对稳定,但在信用和资金使用方向上不如第一个簇表现一致。
    • 定义依据:虽然总体财务状况尚可,但信用记录和资金用途的分化情况使其区别于第一个簇,因此定义为 “较稳健但信用有分化财务型”。
  3. 第三个簇 - 高风险财务困境型
    • 特征总结:债务合并需求分化,破产经历较多,信用问题普遍且严重,资金用途有差异。在财务健康和信用方面存在诸多问题,面临较大财务风险。
    • 定义依据:基于明显的财务困境迹象和高风险特征,定义为 “高风险财务困境型”。

现在你就得到了一个全新的特征,完成了你的特征工程

后续研究需要对这个特征独热编码,然后重新建模训练,如果加了这个特征后模型精度提高,说明这个特征是有用的。


二、作业

参考示例代码心脏病数据集采取类似操作并且评估特征工程模型效果提升

1. 聚类分析

# 环境设置
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score  # 添加缺失的导入
import shap
import warnings
warnings.filterwarnings("ignore")

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 1. 数据加载与预处理
def load_and_preprocess():
    # 加载数据
    df = pd.read_csv('heart.csv')
    
    # 显示列名用于调试
    print("数据集列名:", df.columns.tolist())
    
    # 自动识别目标变量(假设最后一列为目标变量)
    target_col = df.columns[-1]
    print(f"\n自动识别目标变量: {target_col}")
    
    # 处理分类变量(自动检测)
    categorical_cols = df.select_dtypes(include=['object', 'category']).columns.tolist()
    print("\n检测到的分类变量:", categorical_cols)
    
    # 标签编码
    le = LabelEncoder()
    for col in categorical_cols:
        df[col] = le.fit_transform(df[col])
    
    # 处理缺失值
    df.fillna(df.median(numeric_only=True), inplace=True)
    
    # 分离特征和目标变量
    X = df.drop(target_col, axis=1)  
    y = df[target_col]
    
    # 标准化
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)
    
    return X_scaled, X, y, target_col

# 2. KMeans聚类分析
def perform_clustering(X_scaled):
    # 寻找最优K值
    inertia = []
    silhouette = []
    k_range = range(2, 8)
    
    for k in k_range:
        kmeans = KMeans(n_clusters=k, random_state=42)
        labels = kmeans.fit_predict(X_scaled)
        inertia.append(kmeans.inertia_)
        silhouette.append(silhouette_score(X_scaled, labels))  # 现在可以正常使用
    
    # 可视化评估指标
    plt.figure(figsize=(12,4))
    
    plt.subplot(1,2,1)
    plt.plot(k_range, inertia, 'bo-')
    plt.title('肘部法则')
    plt.xlabel('簇数量')
    
    plt.subplot(1,2,2)
    plt.plot(k_range, silhouette, 'ro-')
    plt.title('轮廓系数')
    plt.xlabel('簇数量')
    
    plt.tight_layout()
    plt.show()
    
    # 选择K=3进行聚类
    kmeans = KMeans(n_clusters=3, random_state=42)
    clusters = kmeans.fit_predict(X_scaled)
    
    return clusters

# 3. 特征重要性分析
def analyze_features(X, clusters):
    # 添加聚类标签
    X_clustered = X.copy()
    X_clustered['Cluster'] = clusters
    
    # 训练随机森林模型
    from sklearn.ensemble import RandomForestClassifier
    model = RandomForestClassifier(n_estimators=100, random_state=42)
    model.fit(X, clusters)
    
    # SHAP分析
    explainer = shap.TreeExplainer(model)
    shap_values = explainer.shap_values(X)
    
    # 特征重要性可视化
    plt.figure(figsize=(10,6))
    shap.summary_plot(shap_values, X, plot_type="bar", show=False)
    plt.title('SHAP特征重要性')
    plt.show()
    
    return X_clustered

# 4. 聚类结果解释
def interpret_clusters(X_clustered):
    # PCA可视化
    pca = PCA(n_components=2)
    X_pca = pca.fit_transform(X_clustered.drop('Cluster', axis=1))
    
    plt.figure(figsize=(8,6))
    sns.scatterplot(x=X_pca[:,0], y=X_pca[:,1], hue=X_clustered['Cluster'], 
                    palette='viridis', alpha=0.8)
    plt.title('聚类结果可视化 (PCA降维)')
    plt.xlabel('主成分1')
    plt.ylabel('主成分2')
    plt.show()
    
    # 关键特征分析
    print("\n各簇特征分布:")
    print(X_clustered.groupby('Cluster').agg(['mean', 'median']).T)

# 5. 特征工程效果验证
def evaluate_improvement(X_clustered, y, target_col):
    from sklearn.ensemble import GradientBoostingClassifier
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score
    
    # 添加聚类特征
    X_new = X_clustered.copy()
    X_new = pd.get_dummies(X_new, columns=['Cluster'], prefix='Cluster')
    
    # 划分数据集
    X_train, X_test, y_train, y_test = train_test_split(X_new, y, test_size=0.3, random_state=42)
    
    # 基准模型
    base_model = GradientBoostingClassifier(random_state=42)
    base_model.fit(X_train.drop(columns=X_new.filter(regex='Cluster_').columns), y_train)
    base_acc = accuracy_score(y_test, base_model.predict(X_test.drop(columns=X_new.filter(regex='Cluster_').columns)))
    
    # 新模型
    new_model = GradientBoostingClassifier(random_state=42)
    new_model.fit(X_train, y_train)
    new_acc = accuracy_score(y_test, new_model.predict(X_test))
    
    print(f"\n基准模型准确率: {base_acc:.4f}")
    print(f"新增特征后准确率: {new_acc:.4f}")
    print(f"准确率提升: {(new_acc - base_acc):.4f}")

# 主流程
if __name__ == "__main__":
    # 数据预处理
    X_scaled, X, y, target_col = load_and_preprocess()
    
    # 显示预处理后的数据
    print("\n预处理后的数据样例:")
    print(pd.DataFrame(X_scaled, columns=X.columns).head())
    
    # 聚类分析
    clusters = perform_clustering(X_scaled)
    
    # 特征分析
    X_clustered = analyze_features(X, clusters)
    
    # 结果解释
    interpret_clusters(X_clustered)
    
    # 效果验证
    evaluate_improvement(X_clustered, y, target_col)

输出结果:

数据集列名: ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'target']

自动识别目标变量: target

检测到的分类变量: []

预处理后的数据样例:
        age       sex        cp  trestbps      chol       fbs   restecg  \
0  0.952197  0.681005  1.973123  0.763956 -0.256334  2.394438 -1.005832   
1 -1.915313  0.681005  1.002577 -0.092738  0.072199 -0.417635  0.898962   
2 -1.474158 -1.468418  0.032031 -0.092738 -0.816773 -0.417635 -1.005832   
3  0.180175  0.681005  0.032031 -0.663867 -0.198357 -0.417635  0.898962   
4  0.290464 -1.468418 -0.938515 -0.663867  2.082050 -0.417635  0.898962   

    thalach     exang   oldpeak     slope        ca      thal  
0  0.015443 -0.696631  1.087338 -2.274579 -0.714429 -2.148873  
1  1.633471 -0.696631  2.122573 -2.274579 -0.714429 -0.512922  
2  0.977514 -0.696631  0.310912  0.976352 -0.714429 -0.512922  
3  1.239897 -0.696631 -0.206705  0.976352 -0.714429 -0.512922  
4  0.583939  1.435481 -0.379244  0.976352 -0.714429 -0.512922  

各簇特征分布:
Cluster                   0           1           2
age      mean     58.092784   58.150538   48.053097
         median   59.000000   58.000000   48.000000
sex      mean      0.814433    0.268817    0.911504
         median    1.000000    0.000000    1.000000
cp       mean      0.185567    1.419355    1.265487
         median    0.000000    2.000000    1.000000
trestbps mean    135.876289  133.397849  126.513274
         median  132.000000  132.000000  125.000000
chol     mean    254.752577  257.817204  229.469027
         median  254.000000  248.000000  229.000000
fbs      mean      0.185567    0.182796    0.088496
         median    0.000000    0.000000    0.000000
restecg  mean      0.432990    0.440860    0.681416
         median    0.000000    0.000000    1.000000
thalach  mean    129.824742  150.516129  165.946903
         median  131.000000  154.000000  168.000000
exang    mean      0.731959    0.150538    0.123894
         median    1.000000    0.000000    0.000000
oldpeak  mean      1.965979    0.673118    0.546018
         median    1.800000    0.400000    0.000000
slope    mean      0.979381    1.430108    1.734513
         median    1.000000    1.000000    2.000000
ca       mean      1.381443    0.344086    0.486726
         median    1.000000    0.000000    0.000000
thal     mean      2.597938    1.956989    2.362832
         median    3.000000    2.000000    2.000000

基准模型准确率: 0.7802
新增特征后准确率: 0.8132
准确率提升: 0.0330

2. 簇的总结与定义

(1)Cluster 0(紫色) - 高风险集中群体

​分布特征​​:主成分1(+100 ~ +300)与主成分2(+20 ~ +60)双高区域
​潜在特性​​:

  • 可能具有高静息血压(RestingBP)与高胆固醇(Cholesterol)组合
  • 年龄分布可能偏大(主成分1正方向常与年龄正相关)
  • 最大心率(MaxHR)指标可能较低(与主成分2正相关呈反向趋势)
    ​风险特征​​:心血管代谢指标异常集中,建议重点关注潜在冠心病高危人群

(2)Cluster 1(青色) - 中度风险过渡群体

​分布特征​​:主成分1(-50 ~ +200)与主成分2(-20 ~ +40)广泛分布
​潜在特性​​:

  • 血压与胆固醇指标呈现中间值
  • 可能包含非典型症状患者(ST段压低oldpeak值中等)
  • 运动诱发心绞痛(exng)发生率具有波动性
    ​风险特征​​:临床指标存在异质性,需结合其他诊断参数进行分层管理

(3)Cluster 2(黄色) - 低风险健康群体

​分布特征​​:主成分1(-100 ~ +50)与主成分2(-60 ~ 0)双低区域
​潜在特性​​:

  • 静息血压与胆固醇水平最优
  • 最大心率保持最佳生理范围
  • 血管通畅度指标(caa)可能最优
    ​风险特征​​:心血管系统功能指标良好,建议作为健康对照组重点研究对象

    3. 模型效果提升

评估特征工程模型效果提升

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score, roc_auc_score, f1_score
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

# 1. 数据加载与预处理
def load_data():
    df = pd.read_csv('heart.csv')
    
    # 自动识别目标变量(假设最后一列)
    target_col = df.columns[-1]
    print(f"目标变量: {target_col}")
    
    # 处理分类变量
    categorical_cols = df.select_dtypes(include=['object']).columns
    le = LabelEncoder()
    for col in categorical_cols:
        df[col] = le.fit_transform(df[col])
    
    # 填充缺失值
    df.fillna(df.median(numeric_only=True), inplace=True)
    
    # 分离特征和标签
    X = df.drop(target_col, axis=1)
    y = df[target_col]
    
    return X, y, target_col

# 2. 特征工程(添加聚类特征)
def add_cluster_features(X):
    # 标准化
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)
    
    # KMeans聚类
    kmeans = KMeans(n_clusters=3, random_state=42)
    clusters = kmeans.fit_predict(X_scaled)
    
    # 添加聚类特征
    X_new = X.copy()
    X_new['Cluster'] = clusters
    
    # PCA可视化验证
    pca = PCA(n_components=2)
    X_pca = pca.fit_transform(X_scaled)
    
    plt.figure(figsize=(8,6))
    sns.scatterplot(x=X_pca[:,0], y=X_pca[:,1], hue=clusters, 
                    palette='viridis', alpha=0.8)
    plt.title('特征工程后的聚类分布')
    plt.xlabel('主成分1')
    plt.ylabel('主成分2')
    plt.show()
    
    return X_new

# 3. 模型评估对比
def evaluate_improvement(X_original, X_enhanced, y):
    # 划分数据集
    X_train_base, X_test_base, y_train, y_test = train_test_split(X_original, y, test_size=0.3, random_state=42)
    X_train_enh, X_test_enh = train_test_split(X_enhanced, test_size=0.3, random_state=42)[:2]
    
    # 基准模型
    base_model = GradientBoostingClassifier(random_state=42)
    base_model.fit(X_train_base, y_train)
    base_pred = base_model.predict(X_test_base)
    
    # 增强模型
    enhanced_model = GradientBoostingClassifier(random_state=42)
    enhanced_model.fit(X_train_enh, y_train)
    enhanced_pred = enhanced_model.predict(X_test_enh)
    
    # 指标对比
    metrics = {
        '准确率': (accuracy_score(y_test, base_pred), accuracy_score(y_test, enhanced_pred)),
        'AUC': (roc_auc_score(y_test, base_model.predict_proba(X_test_base)[:,1]), 
                roc_auc_score(y_test, enhanced_model.predict_proba(X_test_enh)[:,1])),
        'F1': (f1_score(y_test, base_pred), f1_score(y_test, enhanced_pred))
    }
    
    # 可视化对比
    metrics_df = pd.DataFrame(metrics, index=['基准模型', '增强模型']).T
    metrics_df.plot(kind='bar', figsize=(10,6), color=['skyblue', 'orange'])
    plt.title('模型性能对比')
    plt.ylabel('分数')
    plt.xticks(rotation=0)
    plt.ylim(0, 1.05)
    plt.show()
    
    return metrics_df

# 主流程
if __name__ == "__main__":
    # 数据准备
    X, y, target = load_data()
    
    # 特征工程
    X_enhanced = add_cluster_features(X)
    
    # 性能评估
    print("\n模型性能对比:")
    results = evaluate_improvement(X, X_enhanced, y)
    print(results)
    
    # 效果总结
    improvement = (results['增强模型'] - results['基准模型']).mean()
    print(f"\n平均性能提升: {improvement:.2%}")
    if improvement > 0.05:
        print("✅ 特征工程显著提升模型性能")
    elif improvement > 0:
        print("⚠️  特征工程带来小幅提升")
    else:
        print("❌ 特征工程未产生积极效果")

目标变量: target

模型性能对比:

         基准模型      增强模型
准确率  0.780220  0.835165
AUC     0.870244  0.883902
F1         0.791667  0.842105

平均性能提升: 3.97%
⚠️  特征工程带来小幅提升


@浙大疏锦行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值