使用sklearn的PCA得到意外结果,附心脏病数据预处理代码
嘿,我来帮你排查下用sklearn做PCA时出现意外结果的常见问题——结合你用的克利夫兰心脏病数据集,大概率是这几个环节没处理好:
1. 先搞定数据里的缺失值
这个数据集的ca和thal列存在?作为缺失值标记,pd.read_csv默认会把这类值识别为字符串,导致整列变成object类型。PCA只能处理数值型数据,这种非数值特征会直接导致结果异常(甚至悄悄报错)。你需要在预处理里补全这步:
import pandas as pd import numpy as np def loadAndPreprocess(filename): print("Activity 1a: ") dataLabels = [ 'age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'class' ] # 读取时指定列名 data = pd.read_csv(filename, names=dataLabels) # 把?替换为标准缺失值标记NaN data = data.replace('?', np.nan) # 可选:删除含缺失值的行,或者用均值/中位数填充 data = data.dropna() # 简单直接的方式,适合初步排查 # 把原本是字符串的列转成数值型 data['ca'] = data['ca'].astype(float) data['thal'] = data['thal'].astype(float) return data
2. PCA必须先做数据标准化
PCA对数据尺度极度敏感:比如age是几十的范围,chol是几百的范围,如果不做标准化,方差大的特征会完全主导主成分的方向,导致你得到的PCA结果完全偏离预期。一定要在PCA前用标准化工具处理:
from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA # 用你的函数加载预处理后的数据 data = loadAndPreprocess("processed.cleveland.data") # 分离特征和标签 X = data.drop('class', axis=1) y = data['class'] # 标准化特征:让每个特征均值为0,方差为1 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 再执行PCA pca = PCA(n_components=2) X_pca = pca.fit_transform(X_scaled)
3. 检查特征列的类型是否全为数值型
可以在预处理函数末尾加一行print(data.dtypes),确认所有特征列都是int64或float64类型。如果还有object类型的列,说明还有非数值数据没处理干净,这也是PCA出问题的常见原因。
4. 验证PCA结果的小技巧
可以打印主成分的解释方差比,判断结果是否合理:
print("主成分解释方差占比:", pca.explained_variance_ratio_)
如果前几个主成分的解释方差占比极低,要么是数据本身特征相关性弱,要么就是你没做标准化,导致方差被大尺度特征垄断了。
内容的提问来源于stack exchange,提问作者AFS
相关产品推荐
相关产品推荐

