復習日:
1.標準化數據(聚類前通常需要標準化)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
StandardScaler() :這部分代碼調用了 StandardScaler 類的構造函數。在Python中,當你在類名后面加上括號時,就相當于調用了這個類的構造函數,構造函數會創建并初始化一個新的對象。
scaler = ... :這部分代碼把調用構造函數后創建的新對象賦值給變量 scaler 。之后,你就可以使用 scaler 這個變量來訪問 StandardScaler 類定義的屬性和方法。
2.k_range = range(2, 11) ?# 測試 k 從 2 到 10:為什么不是2到11呢?
Python 里 range() 函數的特性是左閉右開區間,也就是說,它會包含起始值,但不包含結束值。
3.plt.subplot(2, 2, 2)
用 matplotlib.pyplot 模塊的 subplot() 函數來創建一個子圖。 subplot() 函數的參數解釋如下:
- 第一個參數 2 :表示將圖形窗口在垂直方向上劃分為 2 行。
- 第二個參數 2 :表示將圖形窗口在水平方向上劃分為 2 列。
- 第三個參數 2 :表示當前要創建和操作的子圖編號,編號從左到右、從上到下依次遞增。在這個例子中, 2 表示選擇第二個子圖(即第一行的第二個位置)。
4.奇異值分解(SVD)
輸入為矩陣A,尺寸為m*n,可以不是方陣,經過SVD后得到三個矩陣、
和
:
左奇異向量矩陣:?是一個
的正交矩陣,列向量是矩陣
的特征向量。
? ?- 作用:表示原始矩陣 在行空間(樣本空間)中的主方向或基向量。簡單來說,$U$ 的列向量描述了數據在行維度上的“模式”或“結構”。
? ?- 應用:在降維中, 的前幾列可以用來投影數據到低維空間,保留主要信息(如在圖像處理中提取主要特征)。
奇異值矩陣:
- 是一個 的對角矩陣,對角線上的值是奇異值(singular values),按降序排列,非負。
? ?- 作用:奇異值表示原始矩陣 在每個主方向上的“重要性”或“能量”。較大的奇異值對應更重要的特征,較小的奇異值對應噪聲或次要信息。
? ?- 應用:通過選擇前個較大的奇異值,可以實現降維,丟棄不重要的信息(如數據壓縮、去噪)。
右奇異向量矩陣的轉置:
- 是 的轉置,
是一個
的正交矩陣,列向量是矩陣
的特征向量。
? ?- 作用:表示原始矩陣 在列空間(特征空間)中的主方向或基向量。簡單來說,
的列向量描述了數據在列維度上的“模式”或“結構”。
? ?- 應用:類似,
的前幾列可以用來投影數據到低維空間,提取主要特征。
????????簡單來說、
和
提供了數據的核心結構信息,幫助我們在保留主要信息的同時簡化數據處理。
????????奇異值分解(SVD)后,原始矩陣被分解為
,這種分解是等價的,意味著通過
、
和
的乘積可以完全重構原始矩陣
,沒有任何信息損失。
????????但在實際應用中,我們通常不需要保留所有的奇異值和對應的向量,而是可以通過篩選規則選擇排序靠前的奇異值及其對應的向量來實現降維或數據壓縮。以下是這個過程的核心思想:
1. 奇異值的排序:
? ?- 在 矩陣中,奇異值(對角線上的值)是按降序排列的。靠前的奇異值通常較大,代表了數據中最重要的信息或主要變化方向;靠后的奇異值較小,代表次要信息或噪聲。
? ?- 奇異值的大小反映了對應向量對原始矩陣 的貢獻程度。
2. 篩選規則:
? ?- 我們可以根據需求選擇保留前個奇異值(
是一個小于原始矩陣秩的數),并丟棄剩余的較小奇異值。
? ?- 常見的篩選規則包括:
? ? ?- 固定數量:直接選擇前 個奇異值(例如,前 10 個)。
? ? ?- 累計方差貢獻率:計算奇異值的平方(代表方差),選擇累計方差貢獻率達到某個閾值(如 95%)的前 個奇異值。
? ? ?- 奇異值下降幅度:觀察奇異值下降的“拐點”,在下降明顯變緩的地方截斷。
3. 降維與近似:
? ?- 保留前 個奇異值后,我們只取
矩陣的前
列(記為
,尺寸為
)、
矩陣的前
個奇異值(記為
,尺寸為
)、以及 $V^T$ 矩陣的前
行(記為
,尺寸為
)。
? ?- 近似矩陣為 ,這個矩陣是原始矩陣
的低秩近似,保留了主要信息,丟棄了次要信息或噪聲。
? ?- 這種方法在降維(如主成分分析 PCA)、圖像壓縮、推薦系統等領域非常常用。
4. 對應的向量:
? ?- $U$ 的列向量和 $V$ 的列向量分別對應左右奇異向量。保留前 個奇異值時,
的列向量代表數據在行空間中的主要方向,
的列向量代表數據在列空間中的主要方向。
? ?- 這些向量與奇異值一起,構成了數據的主要“模式”或“結構”。
總結:SVD 分解后原始矩陣是等價的,但通過篩選排序靠前的奇異值和對應的向量,我們可以實現降維,保留數據的主要信息,同時減少計算量和噪聲影響。這種方法是許多降維算法(如 PCA)和數據處理技術的基礎。
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score# 設置隨機種子以便結果可重復
np.random.seed(42)# 模擬數據:1000 個樣本,50 個特征
n_samples = 1000
n_features = 50
X = np.random.randn(n_samples, n_features) * 10 # 隨機生成特征數據
y = (X[:, 0] + X[:, 1] > 0).astype(int) # 模擬二分類標簽# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"訓練集形狀: {X_train.shape}")
print(f"測試集形狀: {X_test.shape}")# 對訓練集進行 SVD 分解
U_train, sigma_train, Vt_train = np.linalg.svd(X_train, full_matrices=False)
print(f"Vt_train 矩陣形狀: {Vt_train.shape}")# 選擇保留的奇異值數量 k
k = 10
Vt_k = Vt_train[:k, :] # 保留前 k 行,形狀為 (k, 50)
print(f"保留 k={k} 后的 Vt_k 矩陣形狀: {Vt_k.shape}")# 降維訓練集:X_train_reduced = X_train @ Vt_k.T
X_train_reduced = X_train @ Vt_k.T
print(f"降維后訓練集形狀: {X_train_reduced.shape}")# 使用相同的 Vt_k 對測試集進行降維:X_test_reduced = X_test @ Vt_k.T
X_test_reduced = X_test @ Vt_k.T
print(f"降維后測試集形狀: {X_test_reduced.shape}")# 訓練模型(以邏輯回歸為例)
model = LogisticRegression(random_state=42)
model.fit(X_train_reduced, y_train)# 預測并評估
y_pred = model.predict(X_test_reduced)
accuracy = accuracy_score(y_test, y_pred)
print(f"測試集準確率: {accuracy}")# 計算訓練集的近似誤差(可選,僅用于評估降維效果)
X_train_approx = U_train[:, :k] @ np.diag(sigma_train[:k]) @ Vt_k
error = np.linalg.norm(X_train - X_train_approx, 'fro') / np.linalg.norm(X_train, 'fro')
print(f"訓練集近似誤差 (Frobenius 范數相對誤差): {error}")
實際操作過程中的注意事項:
#1. 標準化數據:在進行 SVD 之前,通常需要對數據進行標準化(均值為 0,方差為 1),以避免某些特征的量綱差異對降維結果的影響。可以使用 `sklearn.preprocessing.StandardScaler`。from sklearn.preprocessing import StandardScalerscaler = StandardScaler()X_train_scaled = scaler.fit_transform(X_train)X_test_scaled = scaler.transform(X_test)
# 注意:`scaler` 必須在訓練集上 `fit`,然后對測試集只用 `transform`,以避免數據泄漏。#2. 選擇合適的 k:可以通過累計方差貢獻率(explained variance ratio)選擇 k,通常選擇解釋 90%-95% 方差的 k值。代碼中可以計算:explained_variance_ratio = np.cumsum(sigma_train**2) / np.sum(sigma_train**2)print(f"前 {k} 個奇異值的累計方差貢獻率: {explained_variance_ratio[k-1]}")#3. 使用 sklearn 的 TruncatedSVD:`sklearn` 提供了 `TruncatedSVD` 類,專門用于高效降維,尤其適合大規模數據。它直接計算前 k個奇異值和向量,避免完整 SVD 的計算開銷。from sklearn.decomposition import TruncatedSVDsvd = TruncatedSVD(n_components=k, random_state=42)X_train_reduced = svd.fit_transform(X_train)X_test_reduced = svd.transform(X_test)print(f"累計方差貢獻率: {sum(svd.explained_variance_ratio_)}")
@浙大疏錦行