第二十天打卡

@浙大疏锦行

常见的降维算法

1.  LDA线性判别

2.  PCA主成分分析

3.  t-sne降维

特征降维

特征降维的基本步骤
1. 数据准备 :
   
   - 无监督降维:只需要特征矩阵X(n_samples × n_features)
   - 有监督降维:需要特征矩阵X和对应的标签y
2. 选择降维方法 :
   
   - 根据问题类型选择无监督或有监督方法
   - 根据数据特点选择线性或非线性方法
3. 拟合模型 :

# 以PCA为例
from sklearn.decomposition import PCA
pca = PCA(n_components=2)  # 降到2维
X_reduced = pca.fit_transform(X)

评估降维效果 :

- 可视化降维结果
- 计算保留的方差比例(PCA)
- 评估分类性能(有监督方法)

主成分分析

### 一、PCA通俗理解
想象你有一堆三维空间的点,PCA就是找到一个最佳的二维平面,把这些点投影上去,使得投影后的点尽可能分散(保留最多信息)。这个平面就是由前两个主成分定义的。

### 二、PCA核心步骤
1. 数据标准化 :
   
   - 每个特征减去均值,除以标准差

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

- 计算协方差矩阵 :

- 反映特征间的相关性
- 特征分解 :

- 计算协方差矩阵的特征值和特征向量
- 选择主成分 :

- 按特征值从大到小排序,选择前k个
- 数据投影

from sklearn.decomposition import PCA
pca = PCA(n_components=2)  # 降到2维
X_pca = pca.fit_transform(X_scaled)

### 三、输出结果解读
1. 主成分方向 :
   
   - pca.components_ :各主成分由原始特征的权重
2. 解释方差 :
   
   - pca.explained_variance_ratio_ :每个主成分解释的方差比例
3. 降维数据 :
   
   - 新特征矩阵,行数不变,列数减少
### 四、实际应用场景
1. 数据可视化 :

plt.scatter(X_pca[:,0], X_pca[:,1], c=y)
plt.xlabel('PC1'); plt.ylabel('PC2')

1. 特征压缩 :
   
   - 图像处理(人脸识别)
   - 基因数据分析
2. 去除噪声 :
   
   - 保留主要成分,过滤小方差成分
3. 预处理步骤 :
   
   - 在分类/回归前降低维度
### 五、使用建议
1. 数据要先标准化
2. 选择n_components的常用方法:

pca = PCA().fit(X_scaled)
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('n_components'); plt.ylabel('Cumulative variance')
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import time
import numpy as np # 确保numpy导入

# 假设 X_train, X_test, y_train, y_test 已经准备好了

print(f"\n--- 2. PCA 降维 + 随机森林 (不使用 Pipeline) ---")


# 步骤 1: 特征缩放
scaler_pca = StandardScaler()
X_train_scaled_pca = scaler_pca.fit_transform(X_train)
X_test_scaled_pca = scaler_pca.transform(X_test) # 使用在训练集上fit的scaler

# 步骤 2: PCA降维
# 选择降到10维,或者你可以根据解释方差来选择,例如:
pca_expl = PCA(random_state=42)
pca_expl.fit(X_train_scaled_pca)
cumsum_variance = np.cumsum(pca_expl.explained_variance_ratio_)
n_components_to_keep_95_var = np.argmax(cumsum_variance >= 0.95) + 1
print(f"为了保留95%的方差,需要的主成分数量: {n_components_to_keep_95_var}")
--- 2. PCA 降维 + 随机森林 (不使用 Pipeline) ---
为了保留95%的方差,需要的主成分数量: 26
# 我们测试下降低到10维的效果
n_components_pca = 10
pca_manual = PCA(n_components=n_components_pca, random_state=42)

X_train_pca = pca_manual.fit_transform(X_train_scaled_pca)
X_test_pca = pca_manual.transform(X_test_scaled_pca) # 使用在训练集上fit的pca

print(f"PCA降维后,训练集形状: {X_train_pca.shape}, 测试集形状: {X_test_pca.shape}")
start_time_pca_manual = time.time()
# 步骤 3: 训练随机森林分类器
rf_model_pca = RandomForestClassifier(random_state=42)
rf_model_pca.fit(X_train_pca, y_train)

# 步骤 4: 在测试集上预测
rf_pred_pca_manual = rf_model_pca.predict(X_test_pca)
end_time_pca_manual = time.time()

print(f"手动PCA降维后,训练与预测耗时: {end_time_pca_manual - start_time_pca_manual:.4f} 秒")

print("\n手动 PCA + 随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_pca_manual))
print("手动 PCA + 随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_pca_manual))
PCA降维后,训练集形状: (6000, 10), 测试集形状: (1500, 10)
手动PCA降维后,训练与预测耗时: 9.6229 秒

手动 PCA + 随机森林 在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.77      0.94      0.85      1059
           1       0.70      0.33      0.45       441

    accuracy                           0.76      1500
   macro avg       0.74      0.64      0.65      1500
weighted avg       0.75      0.76      0.73      1500

手动 PCA + 随机森林 在测试集上的混淆矩阵:
[[996  63]
 [295 146]]

t-分布随机邻域嵌入 (t-SNE)

### 一、t-SNE通俗理解
想象你有一群在三维空间中的朋友,t-SNE就像把他们的关系网画在一张纸上:

- 关系好的朋友会靠得很近
- 不熟的人会离得远
- 但整体布局可能会变形(就像把地球仪压成平面地图)
### 二、t-SNE核心步骤
1. 计算相似度 :
   
   - 在高维空间计算点与点之间的相似度(高斯分布)

from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, perplexity=30)

低维映射 :

- 在低维空间用t分布保持相似关系
- 通过梯度下降优化布局

X_tsne = tsne.fit_transform(X)
plt.scatter(X_tsne[:,0], X_tsne[:,1], c=y)

### 输出结果特点
1. 只有相对距离有意义
2. 簇的形状比位置更重要
3. 多次运行结果可能不同

### 使用建议
1. 大数据集先用PCA降维:
   

pca = PCA(n_components=50)
X_pca = pca.fit_transform(X)
X_tsne = TSNE().fit_transform(X_pca)


2. 多试几个perplexity值
3. 不要用于特征工程(仅可视化)

from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import time
import numpy as np
import matplotlib.pyplot as plt # 用于可选的可视化
import seaborn as sns # 用于可选的可视化

# 假设 X_train, X_test, y_train, y_test 已经准备好了
# 并且你的 X_train, X_test 是DataFrame或Numpy Array

print(f"\n--- 3. t-SNE 降维 + 随机森林  ---")
print("       标准 t-SNE 主要用于可视化,直接用于分类器输入可能效果不佳。")


# 步骤 1: 特征缩放
scaler_tsne = StandardScaler()
X_train_scaled_tsne = scaler_tsne.fit_transform(X_train)
X_test_scaled_tsne = scaler_tsne.transform(X_test) # 使用在训练集上fit的scaler

# 步骤 2: t-SNE 降维
# 我们将降维到与PCA相同的维度(例如10维)或者一个适合分类的较低维度。
# t-SNE通常用于2D/3D可视化,但也可以降到更高维度。
# 然而,降到与PCA一样的维度(比如10维)对于t-SNE来说可能不是其优势所在,
# 并且计算成本会显著增加,因为高维t-SNE的优化更困难。
# 为了与PCA的 n_components=10 对比,我们这里也尝试降到10维。
# 但请注意,这可能非常耗时,且效果不一定好。
# 通常如果用t-SNE做分类的预处理(不常见),可能会选择非常低的维度(如2或3)。

# n_components_tsne = 10 # 与PCA的例子保持一致,但计算量会很大
n_components_tsne = 2    # 更典型的t-SNE用于分类的维度,如果想快速看到结果
                         # 如果你想严格对比PCA的10维,可以将这里改为10,但会很慢



# 对训练集进行 fit_transform
tsne_model_train = TSNE(n_components=n_components_tsne,
                        perplexity=30,    # 常用的困惑度值
                        n_iter=1000,      # 足够的迭代次数
                        init='pca',       # 使用PCA初始化,通常更稳定
                        learning_rate='auto', # 自动学习率 (sklearn >= 1.2)
                        random_state=42,  # 保证结果可复现
                        n_jobs=-1)        # 使用所有CPU核心
print("正在对训练集进行 t-SNE fit_transform...")
start_tsne_fit_train = time.time()
X_train_tsne = tsne_model_train.fit_transform(X_train_scaled_tsne)
end_tsne_fit_train = time.time()
print(f"训练集 t-SNE fit_transform 完成,耗时: {end_tsne_fit_train - start_tsne_fit_train:.2f} 秒")


# 对测试集进行 fit_transform
# 再次强调:这是独立于训练集的变换
tsne_model_test = TSNE(n_components=n_components_tsne,
                       perplexity=30,
                       n_iter=1000,
                       init='pca',
                       learning_rate='auto',
                       random_state=42, # 保持参数一致,但数据不同,结果也不同
                       n_jobs=-1)
print("正在对测试集进行 t-SNE fit_transform...")
start_tsne_fit_test = time.time()
X_test_tsne = tsne_model_test.fit_transform(X_test_scaled_tsne) # 注意这里是 X_test_scaled_tsne
end_tsne_fit_test = time.time()
print(f"测试集 t-SNE fit_transform 完成,耗时: {end_tsne_fit_test - start_tsne_fit_test:.2f} 秒")

print(f"t-SNE降维后,训练集形状: {X_train_tsne.shape}, 测试集形状: {X_test_tsne.shape}")

start_time_tsne_rf = time.time()
# 步骤 3: 训练随机森林分类器
rf_model_tsne = RandomForestClassifier(random_state=42)
rf_model_tsne.fit(X_train_tsne, y_train)

# 步骤 4: 在测试集上预测
rf_pred_tsne_manual = rf_model_tsne.predict(X_test_tsne)
end_time_tsne_rf = time.time()

print(f"t-SNE降维数据上,随机森林训练与预测耗时: {end_time_tsne_rf - start_time_tsne_rf:.4f} 秒")
total_tsne_time = (end_tsne_fit_train - start_tsne_fit_train) + \
                  (end_tsne_fit_test - start_tsne_fit_test) + \
                  (end_time_tsne_rf - start_time_tsne_rf)
print(f"t-SNE 总耗时 (包括两次fit_transform和RF): {total_tsne_time:.2f} 秒")


print("\n手动 t-SNE + 随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_tsne_manual))
print("手动 t-SNE + 随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_tsne_manual))
--- 3. t-SNE 降维 + 随机森林  ---
       标准 t-SNE 主要用于可视化,直接用于分类器输入可能效果不佳。
正在对训练集进行 t-SNE fit_transform...
训练集 t-SNE fit_transform 完成,耗时: 53.83 秒
正在对测试集进行 t-SNE fit_transform...
测试集 t-SNE fit_transform 完成,耗时: 9.03 秒
t-SNE降维后,训练集形状: (6000, 2), 测试集形状: (1500, 2)
t-SNE降维数据上,随机森林训练与预测耗时: 3.8160 秒
t-SNE 总耗时 (包括两次fit_transform和RF): 66.68 秒

手动 t-SNE + 随机森林 在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.70      0.91      0.79      1059
           1       0.20      0.06      0.09       441

    accuracy                           0.66      1500
   macro avg       0.45      0.48      0.44      1500
weighted avg       0.55      0.66      0.58      1500

手动 t-SNE + 随机森林 在测试集上的混淆矩阵:
[[962  97]
 [416  25]]

线性判别分析 (Linear Discriminant Analysis, LDA)

### 一、LDA通俗理解
想象你有一堆学生数据(身高、体重、成绩),LDA就像找到一个最佳角度拍照,让不同班级的学生在照片上尽可能分开站,而同一个班级的学生尽量站在一起。

### 二、LDA核心步骤
1. 数据准备 :
   
   - 需要特征X和标签y

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=2)

- 计算类间/类内散布矩阵 :

- 衡量不同类之间的距离和同类数据的紧凑程度
- 求解最优投影方向 :

- 找到最大化类间距离/类内距离比的方向
- 数据投影 :

X_lda = lda.fit_transform(X, y)  # 注意这里需要传入y

### 、关键特性
1. 降维上限: min(特征数, 类别数-1)
2. 输出坐标轴具有明确的判别意义
3. 每个新维度都是原始特征的线性组合
### 四、实际应用场景
1. 分类预处理 (你的信用评分案例):

# 先用LDA降维
lda = LinearDiscriminantAnalysis(n_components=1)  # 二分类最多降到1维
X_train_lda = lda.fit_transform(X_train, y_train)
# 再用随机森林分类
rf = RandomForestClassifier().fit(X_train_lda, y_train)

多分类可视化 :

# 3类数据降到2维可视化
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y)
plt.scatter(X_lda[:,0], X_lda[:,1], c=y)

1. 特征选择 :
   
   - 通过分析判别向量权重找出重要特征
### 五、使用建议
1. 数据要先标准化(与PCA相同)
2. 类别数较少时降维效果有限
3. 适合线性可分的数据
4. 可以同时用作分类器

lda = LinearDiscriminantAnalysis()
lda.fit(X_train, y_train)  # 作为分类器使用
accuracy = lda.score(X_test, y_test)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import time
import numpy as np
# 假设你已经导入了 matplotlib 和 seaborn 用于绘图 (如果需要)
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # 如果需要3D绘图
import seaborn as sns



print(f"\n--- 4. LDA 降维 + 随机森林 ---")

# 步骤 1: 特征缩放
scaler_lda = StandardScaler()
X_train_scaled_lda = scaler_lda.fit_transform(X_train)
X_test_scaled_lda = scaler_lda.transform(X_test) # 使用在训练集上fit的scaler

# 步骤 2: LDA 降维
n_features = X_train_scaled_lda.shape[1]
if hasattr(y_train, 'nunique'):
    n_classes = y_train.nunique()
elif isinstance(y_train, np.ndarray):
    n_classes = len(np.unique(y_train))
else:
    n_classes = len(set(y_train))

max_lda_components = min(n_features, n_classes - 1)

# 设置目标降维维度
n_components_lda_target = 10

if max_lda_components < 1:
    print(f"LDA 不适用,因为类别数 ({n_classes})太少,无法产生至少1个判别组件。")
    X_train_lda = X_train_scaled_lda.copy() # 使用缩放后的原始特征
    X_test_lda = X_test_scaled_lda.copy()   # 使用缩放后的原始特征
    actual_n_components_lda = n_features
    print("将使用缩放后的原始特征进行后续操作。")
else:
    # 实际使用的组件数不能超过LDA的上限,也不能超过我们的目标(如果目标更小)
    actual_n_components_lda = min(n_components_lda_target, max_lda_components)
    if actual_n_components_lda < 1: # 这种情况理论上不会发生,因为上面已经检查了 max_lda_components < 1
        print(f"计算得到的实际LDA组件数 ({actual_n_components_lda}) 小于1,LDA不适用。")
        X_train_lda = X_train_scaled_lda.copy()
        X_test_lda = X_test_scaled_lda.copy()
        actual_n_components_lda = n_features
        print("将使用缩放后的原始特征进行后续操作。")
    else:
        print(f"原始特征数: {n_features}, 类别数: {n_classes}")
        print(f"LDA 最多可降至 {max_lda_components} 维。")
        print(f"目标降维维度: {n_components_lda_target} 维。")
        print(f"本次 LDA 将实际降至 {actual_n_components_lda} 维。")

        lda_manual = LinearDiscriminantAnalysis(n_components=actual_n_components_lda, solver='svd')
        X_train_lda = lda_manual.fit_transform(X_train_scaled_lda, y_train)
        X_test_lda = lda_manual.transform(X_test_scaled_lda)

print(f"LDA降维后,训练集形状: {X_train_lda.shape}, 测试集形状: {X_test_lda.shape}")

start_time_lda_rf = time.time()
# 步骤 3: 训练随机森林分类器
rf_model_lda = RandomForestClassifier(random_state=42)
rf_model_lda.fit(X_train_lda, y_train)

# 步骤 4: 在测试集上预测
rf_pred_lda_manual = rf_model_lda.predict(X_test_lda)
end_time_lda_rf = time.time()

print(f"LDA降维数据上,随机森林训练与预测耗时: {end_time_lda_rf - start_time_lda_rf:.4f} 秒")

print("\n手动 LDA + 随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_lda_manual))
print("手动 LDA + 随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_lda_manual))
--- 4. LDA 降维 + 随机森林 ---
原始特征数: 30, 类别数: 2
LDA 最多可降至 1 维。
目标降维维度: 10 维。
本次 LDA 将实际降至 1 维。
LDA降维后,训练集形状: (6000, 1), 测试集形状: (1500, 1)
LDA降维数据上,随机森林训练与预测耗时: 5.1093 秒

手动 LDA + 随机森林 在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.78      0.78      0.78      1059
           1       0.47      0.47      0.47       441

    accuracy                           0.69      1500
   macro avg       0.63      0.63      0.63      1500
weighted avg       0.69      0.69      0.69      1500

手动 LDA + 随机森林 在测试集上的混淆矩阵:
[[828 231]
 [233 208]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值