PCA和LDA进行数据降维

DimensionalityReduction
PCA和LDA进行数据降维

使用PCA对数据进行降维,我们使用两种方式:
直接按数学推导的方式实现PCA
使用sklearn实现PCA
利用降维后的特征进行逻辑回归分类
代码使用LDA对数据进行降维,我们使用两种方式:
直接按数学推导过程实现LDA
使用sklearn实现LDA
利用降维后的特征进行逻辑回归分类

#%% md



#%%

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from matplotlib.colors import ListedColormap
from sklearn.linear_model import LogisticRegression

#%% md

# 数据获取

#%%

# 读取数据()
df_wine = pd.read_csv('wine.data',header=None)

#%% md

该数据集是UCI的公开数据集,是对意大利同一地区种植的葡萄酒进行分析的结果,数据集共14列数据,第一个属性是类标识符,分别是1/2/3来表示,代表葡萄酒的三个分类。剩余的13个属性是,酒精、苹果酸、灰、灰分的碱度、镁、总酚、黄酮类化合物、非黄烷类酚类、原花色素、颜色强度、色调等。

#%%

# 设置列索引
df_wine.columns =  ['Class label', 'Alcohol', 'Malic acid', 'Ash',
                   'Alcalinity of ash', 'Magnesium', 'Total phenols',
                   'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
                   'Color intensity', 'Hue',
                   'OD280/OD315 of diluted wines', 'Proline']

#%%

# 数据维度
df_wine.shape

#%%

# 每一类数据包含的样本个数
df_wine['Class label'].value_counts()

#%%

df_wine.head()

#%% md

# 数据集划分

#%%

# 数据集设置:X为样本特征数据,y为目标数据,即标注结果
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values

#%%

# 数据集划分: 将数据集划分为训练集和测试集数据(测试集数据为30%,训练集为70%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
                                                    stratify=y,
                                                    random_state=0)

#%% md

# 数据标准化

#%%

# 实例化
sc = StandardScaler()

#%%

# 对数据集进行标准化(一般情况下我们在训练集中进行均值和方差的计算,直接在测试集中使用)
X_train_std = sc.fit_transform(X_train)
X_test_std = sc.transform(X_test)

#%% md

# PCA(Pricipal component analysis)

#%% md

## PCA实现

#%% md

### 特征值计算

#%%

# 计算协方差矩阵
cov_mat = np.cov(X_train_std.T)

#%%

# 对协方差矩阵进行特征值分解
eigen_vals, eigen_vecs = np.linalg.eig(cov_mat)

#%%

# 特征值
eigen_vals

#%% md

### 特征值分布

#%%

# 特征值之和
tot = sum(eigen_vals)

#%%

# 对特征进行排序,并计算所占的比例
var_exp = [(i / tot) for i in sorted(eigen_vals, reverse=True)]

#%%

# 累计求和
cum_var_exp = np.cumsum(var_exp)

#%%

# 绘制图像
plt.figure()
plt.bar(range(1, 14), var_exp, alpha=0.5, align='center',
        label='特征值分布')
plt.step(range(1, 14), cum_var_exp, where='mid',
         label='累计特征值')
plt.ylabel('特征值比例')
plt.xlabel('特征index')
plt.legend(loc='best')

#%% md

### 特征降维

#%%

# 创建列表,由(eigenvalue, eigenvector)元组构成
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i])
               for i in range(len(eigen_vals))]

#%%

# 按特征值从大到小对列表(eigenvalue, eigenvector)排序
eigen_pairs.sort(key=lambda k: k[0], reverse=True)

#%%

# 特征值与特征向量
eigen_pairs

#%%

# 取前两个特征值对应的特征向量作为主要成分
w = np.hstack((eigen_pairs[0][1][:, np.newaxis],
               eigen_pairs[1][1][:, np.newaxis]))

#%%

w

#%%

# 原始特征(以第一个样本为例)
X_train_std[0]

#%%

# 特征压缩后结果
X_train_std[0].dot(w)

#%%

# 全部特征压缩
X_train_pca = X_train_std.dot(w)

#%%

# 特征压缩后结果展示
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']

for l, c, m in zip(np.unique(y_train), colors, markers):
    # 按照样本的真实值进行展示
    plt.scatter(X_train_pca[y_train == l, 0], 
                X_train_pca[y_train == l, 1], 
                c=c, label=l, marker=m)

plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%% md

## 使用sklearn实现PCA

#%% md

sklearn中提供了进行PCA的API

#%% md

### 特征值计算

#%%

# 实例化pca,保留所有特征
pca = PCA()

#%%

# 特征提取
X_train_pca = pca.fit_transform(X_train_std)
# 特征值结果
pca.explained_variance_ratio_

#%%

# 特征值绘制
# 绘制图像
plt.figure()
plt.bar(range(1, 14), pca.explained_variance_ratio_, alpha=0.5, align='center',
        label='特征值分布')
plt.step(range(1, 14), np.cumsum(pca.explained_variance_ratio_), where='mid',
         label='累计特征值')
plt.ylabel('特征值比例')
plt.xlabel('特征index')
plt.legend(loc='best')

#%% md

### 特征降维

#%%

# 压缩到二维特征
pca = PCA(n_components=2)

#%%

# 对训练数据进行处理
X_train_pca = pca.fit_transform(X_train_std)

#%%

# 特征值结果(只保留两个特征)
print(pca.explained_variance_ratio_)

#%%

# 对测试集数据进行处理
X_test_pca = pca.transform(X_test_std)

#%%

# 特征降维后结果展示
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']

for l, c, m in zip(np.unique(y_train), colors, markers):
    # 按照样本的真实值进行展示
    plt.scatter(X_train_pca[y_train == l, 0], 
                X_train_pca[y_train == l, 1], 
                c=c, label=l, marker=m)

plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%% md

## 利用逻辑回归进行分类

#%% md

### 绘制函数

#%%

# 绘制样本及其目标值
def plot_decision_regions(X, y, classifier, resolution=0.02):
    """
    X:样本特征值
    y:目标值
    classifier: 分类器
    """
    # 设置图像的标记及颜色
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # 利用样本点创建meshgrid
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    # 预测结果
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    # 绘制预测结果的等高线
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    # 绘制样本点,并根据真实值进行着色
    for idx, cl in enumerate(np.unique(y)):
        # 绘制散点图
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.6, 
                    c=cmap(idx),
                    edgecolor='black',
                    marker=markers[idx], 
                    label=cl)

#%% md

### PCA特征降维

#%%

# 利用PCA进行特征降维(提取)
# 保留两维特征
pca = PCA(n_components=2)
# 训练集数据处理
X_train_pca = pca.fit_transform(X_train_std)
# 测试集数据处理
X_test_pca = pca.transform(X_test_std)

#%% md

### LR分类器

#%%

# 实例化
lr = LogisticRegression()
# 模型训练
lr = lr.fit(X_train_pca, y_train)

#%% md

### 训练数据结果

#%%

plot_decision_regions(X_train_pca, y_train, classifier=lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%% md

### 测试数据结果

#%%

plot_decision_regions(X_test_pca, y_test, classifier=lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%% md

# LDA(Linear discriminant analysis)

#%% md

## LDA实现

#%%

# 精度设置,浮点数
np.set_printoptions(precision=4)

#%% md

### 平均向量

#%%

# 计算每一类数据的平均向量
mean_vecs = []
for label in range(1, 4):
    mean_vecs.append(np.mean(X_train_std[y_train == label], axis=0))
    print('MV %s: %s\n' % (label, mean_vecs[label - 1]))

#%% md

### 类内散度矩阵Sw

#%%

# 特征维度
d = 13 
S_W = np.zeros((d, d))
# 获取每个类别的平均值向量
for label, mv in zip(range(1, 4), mean_vecs):
    # 每一类别的散度矩阵
    class_scatter = np.zeros((d, d))  
    for row in X_train_std[y_train == label]:
        # 列向量
        row, mv = row.reshape(d, 1), mv.reshape(d, 1) 
        class_scatter += (row - mv).dot((row - mv).T)
    # 每个类别散度矩阵之和
    S_W += class_scatter                         

#%% md

### 类间散度矩阵SB

#%%

# 全局平均值
mean_overall = np.mean(X_train_std, axis=0)
# 特征维度
d = 13  
S_B = np.zeros((d, d))
# 获取每个类别的平均值
for i, mean_vec in enumerate(mean_vecs):
    n = X_train[y_train == i + 1, :].shape[0]
    # 列向量
    mean_vec = mean_vec.reshape(d, 1)  
    mean_overall = mean_overall.reshape(d, 1)  
    # 类间散度矩阵
    S_B += n * (mean_vec - mean_overall).dot((mean_vec - mean_overall).T)

#%% md

### 特征值计算

#%% md

求解矩阵 $S_W^{-1}S_B$的特征值和特征向量

#%%

# 计算LDA的特征值
eigen_vals, eigen_vecs = np.linalg.eig(np.linalg.inv(S_W).dot(S_B))

#%%

eigen_vals

#%% md

### 特征值分布

#%%

# 创建由特征值和特征向量组成的list
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i])
               for i in range(len(eigen_vals))]

# 根据特征值从大到小排序(eigenvalue, eigenvector)
eigen_pairs = sorted(eigen_pairs, key=lambda k: k[0], reverse=True)

# 特征值结果
for eigen_val in eigen_pairs:
    print(eigen_val[0])

#%%

# 实部求和
tot = sum(eigen_vals.real)
# 计算比例
discr = [(i / tot) for i in sorted(eigen_vals.real, reverse=True)]
# 累计求和
cum_discr = np.cumsum(discr)

plt.bar(range(1, 14), discr, alpha=0.5, align='center',
        label='"区分度"分布')
plt.step(range(1, 14), cum_discr, where='mid',
         label='累计"区分度"')
plt.ylabel('"区分度" 比例')
plt.xlabel('特征维度')
plt.ylim([-0.1, 1.1])
plt.legend(loc='best')
plt.show()

#%% md

### 特征降维

#%%

# 保留两维特征
w = np.hstack((eigen_pairs[0][1][:, np.newaxis].real,
              eigen_pairs[1][1][:, np.newaxis].real))

#%%

w

#%%

# 特征降维
X_train_lda = X_train_std.dot(w)

#%%

# 降维前
X_test_std[0]

#%%

# 降维后
X_train_lda[0]

#%%

# 结果绘制
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']

for l, c, m in zip(np.unique(y_train), colors, markers):
    plt.scatter(X_train_lda[y_train == l, 0],
                X_train_lda[y_train == l, 1] * (-1),
                c=c, label=l, marker=m)

plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.legend(loc='lower right')
plt.show()

#%% md

## 使用sklearn实现LDA并进行LR分类

#%%

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
# 实例化
lda = LDA(n_components=2)

#%%

# 对训练数据进行LDA处理
X_train_lda = lda.fit_transform(X_train_std, y_train)

#%%

X_train_lda[0]

#%%

# 实例化逻辑回归
lr = LogisticRegression()
# 训练
lr = lr.fit(X_train_lda, y_train)

#%%

# 训练数据结果
plot_decision_regions(X_train_lda, y_train, classifier=lr)
plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%%

# 测试数据结果
X_test_lda = lda.transform(X_test_std)

plot_decision_regions(X_test_lda, y_test, classifier=lr)
plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

#%% md

# kernel PCA 

#%% md

对于线性不可分的数据,在降维时可以使用带核函数的PCA

#%%

from sklearn.decomposition import KernelPCA
from sklearn.datasets import make_moons
# 数据生成
X, y = make_moons(n_samples=100, random_state=123)
# 实例化
scikit_kpca = KernelPCA(n_components=2, kernel='rbf', gamma=15)
# 数据处理
X_skernpca = scikit_kpca.fit_transform(X)
# 结果绘制
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 3))
ax[0].scatter(X[:,0],X[:,1],marker='o',c=y) 

ax[1].scatter(X_skernpca[y == 0, 0], X_skernpca[y == 0, 1],
            color='red', marker='^', alpha=0.5)
ax[1].scatter(X_skernpca[y == 1, 0], X_skernpca[y == 1, 1],
            color='blue', marker='o', alpha=0.5)

plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()

#%%



你可能感兴趣的:(#,机器学习,Machine,Learning)