# 七、特征工程
> 作者:[Chris Albon](https://chrisalbon.com/)
>
> 譯者:[飛龍](https://github.com/wizardforcel)
>
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
## 稀疏特征矩陣上的降維
```py
# 加載庫
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import TruncatedSVD
from scipy.sparse import csr_matrix
from sklearn import datasets
import numpy as np
# 加載數據
digits = datasets.load_digits()
# 標準化特征矩陣
X = StandardScaler().fit_transform(digits.data)
# 生成稀疏矩陣
X_sparse = csr_matrix(X)
# 創建 TSVD
tsvd = TruncatedSVD(n_components=10)
# 在稀疏矩陣上使用 TSVD
X_sparse_tsvd = tsvd.fit(X_sparse).transform(X_sparse)
# 展示結果
print('Original number of features:', X_sparse.shape[1])
print('Reduced number of features:', X_sparse_tsvd.shape[1])
'''
Original number of features: 64
Reduced number of features: 10
'''
# 前三個主成分的解釋方差比之和
tsvd.explained_variance_ratio_[0:3].sum()
# 0.30039385372588506
```
## 核 PCA 降維

```py
# 加載庫
from sklearn.decomposition import PCA, KernelPCA
from sklearn.datasets import make_circles
# 創建線性不可分的數據
X, _ = make_circles(n_samples=1000, random_state=1, noise=0.1, factor=0.1)
# 應用帶有徑向基函數(RBF)核的核 PCA
kpca = KernelPCA(kernel="rbf", gamma=15, n_components=1)
X_kpca = kpca.fit_transform(X)
print('Original number of features:', X.shape[1])
print('Reduced number of features:', X_kpca.shape[1])
'''
Original number of features: 2
Reduced number of features: 1
'''
```
## 使用 PCA 的降維

```py
# 加載庫
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn import datasets
# 加載數據
digits = datasets.load_digits()
# 標準化特征矩陣
X = StandardScaler().fit_transform(digits.data)
# 創建保留 99% 方差的 PCA
pca = PCA(n_components=0.99, whiten=True)
# 使用 PCA
X_pca = pca.fit_transform(X)
# 展示結果
print('Original number of features:', X.shape[1])
print('Reduced number of features:', X_pca.shape[1])
'''
Original number of features: 64
Reduced number of features: 54
'''
```
## PCA 特征提取
[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis)(PCA)是數據科學中常見的特征提取方法。 從技術上講,PCA 找到具有最高特征值的協方差矩陣的特征向量,然后使用這些特征向量將數據投影到相等或更小維度的新子空間。 實際上,PCA 將 n 個特征矩陣轉換為(可能)小于 n 個特征的新數據集。 也就是說,它通過構造新的較少變量來減少特征的數量,這些變量捕獲原始特征中找到的信息的重要部分。 但是,本教程的目的不是要解釋 PCA 的概念,這在其他地方做得非常好,而是用于演示 PCA 的實際應用。
```py
# 導入庫
import numpy as np
from sklearn import decomposition, datasets
from sklearn.preprocessing import StandardScaler
# 加載乳腺癌數據集
dataset = datasets.load_breast_cancer()
# 加載特征
X = dataset.data
```
請注意,原始數據包含 569 個觀測和 30 個特征。
```py
# 查看數據集的形狀
X.shape
# (569, 30)
```
這里是數據的樣子
```py
# 查看數據
X
'''
array([[ 1.79900000e+01, 1.03800000e+01, 1.22800000e+02, ...,
2.65400000e-01, 4.60100000e-01, 1.18900000e-01],
[ 2.05700000e+01, 1.77700000e+01, 1.32900000e+02, ...,
1.86000000e-01, 2.75000000e-01, 8.90200000e-02],
[ 1.96900000e+01, 2.12500000e+01, 1.30000000e+02, ...,
2.43000000e-01, 3.61300000e-01, 8.75800000e-02],
...,
[ 1.66000000e+01, 2.80800000e+01, 1.08300000e+02, ...,
1.41800000e-01, 2.21800000e-01, 7.82000000e-02],
[ 2.06000000e+01, 2.93300000e+01, 1.40100000e+02, ...,
2.65000000e-01, 4.08700000e-01, 1.24000000e-01],
[ 7.76000000e+00, 2.45400000e+01, 4.79200000e+01, ...,
0.00000000e+00, 2.87100000e-01, 7.03900000e-02]])
'''
# 創建縮放器對象
sc = StandardScaler()
# 使縮放器擬合特征并轉換
X_std = sc.fit_transform(X)
```
請注意,PCA 包含一個參數,即成分數。 這是輸出特征的數量,需要進行調整。
```py
# 創建 PCA 對象,使用兩個成分作為參數
pca = decomposition.PCA(n_components=2)
# 擬合 PCA 并轉換數據
X_std_pca = pca.fit_transform(X_std)
```
在 PCA 之后,新數據已降到了兩個特征,其行數與原始特征相同。
```py
# 查看新特征數據的形狀
X_std_pca.shape
# (569, 2)
# 查看新特征數據
X_std_pca
'''
array([[ 9.19283683, 1.94858307],
[ 2.3878018 , -3.76817174],
[ 5.73389628, -1.0751738 ],
...,
[ 1.25617928, -1.90229671],
[ 10.37479406, 1.67201011],
[ -5.4752433 , -0.67063679]])
'''
```
## 使用 KMeans 聚類對觀測分組
```py
# 加載庫
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import pandas as pd
# 制作模擬特征矩陣
X, _ = make_blobs(n_samples = 50,
n_features = 2,
centers = 3,
random_state = 1)
# 創建 DataFrame
df = pd.DataFrame(X, columns=['feature_1','feature_2'])
# 創建 KMeans 聚類器
clusterer = KMeans(3, random_state=1)
# 擬合聚類器
clusterer.fit(X)
'''
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto',
random_state=1, tol=0.0001, verbose=0)
'''
# 預測值
df['group'] = clusterer.predict(X)
# 前幾個觀測
df.head(5)
```
| | feature_1 | feature_2 | group |
| --- | --- | --- | --- |
| 0 | -9.877554 | -3.336145 | 0 |
| 1 | -7.287210 | -8.353986 | 2 |
| 2 | -6.943061 | -7.023744 | 2 |
| 3 | -7.440167 | -8.791959 | 2 |
| 4 | -6.641388 | -8.075888 | 2 |
# 為 LDA 選擇最佳數量的成分
在 scikit-learn 中,LDA 是使用`LinearDiscriminantAnalysis`實現的,包含一個參數`n_components`,表示我們想要返回的特征數。 為了找出用于`n_components`的參數值(例如,要保留多少參數),我們可以利用一個事實,`explain_variance_ratio_`告訴我們每個輸出特征的解釋方差并且是有序數組。
具體來說,我們可以運行`Linear_iscriminantAnalysis`,將`n_components`設置為`None`來返回由每個特征成分的解釋方差比,然后計算需要多少成分才能超過解釋方差的閾值(通常為 0.95 或 0.99)。
```py
# 加載庫
from sklearn import datasets
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
# 加載鳶尾花數據集
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 創建并運行 LDA
lda = LinearDiscriminantAnalysis(n_components=None)
X_lda = lda.fit(X, y)
# 創建解釋方差比的數組
lda_var_ratios = lda.explained_variance_ratio_
# 創建函數
def select_n_components(var_ratio, goal_var: float) -> int:
# 設置目前為止的初始解釋方差
total_variance = 0.0
# 設置初始特征數
n_components = 0
# 對于每個特征的解釋方差
for explained_variance in var_ratio:
# 將解釋方差添加到總體
total_variance += explained_variance
# 成分數加一
n_components += 1
# 如果我們達到了我們的解釋方差目標
if total_variance >= goal_var:
# 結束循環
break
# 返回成分數量
return n_components
# 執行函數
select_n_components(lda_var_ratios, 0.95)
# 1
```
## 為 TSVD 選擇最佳數量的成分
```py
# 加載庫
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import TruncatedSVD
from scipy.sparse import csr_matrix
from sklearn import datasets
import numpy as np
# 加載數據
digits = datasets.load_digits()
# Standardize the feature matrix
X = StandardScaler().fit_transform(digits.data)
# 制作系數矩陣
X_sparse = csr_matrix(X)
# 創建并使用特征數減一運行 TSVD
tsvd = TruncatedSVD(n_components=X_sparse.shape[1]-1)
X_tsvd = tsvd.fit(X)
# 解釋方差的列表
tsvd_var_ratios = tsvd.explained_variance_ratio_
# 創建函數
def select_n_components(var_ratio, goal_var: float) -> int:
# 設置目前為止的初始解釋方差
total_variance = 0.0
# 設置初始特征數
n_components = 0
# 對于每個特征的解釋方差
for explained_variance in var_ratio:
# 將解釋方差添加到總體
total_variance += explained_variance
# 成分數加一
n_components += 1
# 如果我們達到了我們的解釋方差目標
if total_variance >= goal_var:
# 結束循環
break
# 返回成分數量
return n_components
# 執行函數
select_n_components(tsvd_var_ratios, 0.95)
# 40
```
## 將 LDA 用于降維
```py
# 加載庫
from sklearn import datasets
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
# 加載鳶尾花數據集
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 創建 LDA,它將數據降維到 1 個特征
lda = LinearDiscriminantAnalysis(n_components=1)
# 運行 LDA 并使用它轉換特征
X_lda = lda.fit(X, y).transform(X)
# 打印特征數
print('Original number of features:', X.shape[1])
print('Reduced number of features:', X_lda.shape[1])
'''
Original number of features: 4
Reduced number of features: 1
'''
## 查看解釋方差比
lda.explained_variance_ratio_
# array([ 0.99147248])
```