从「降维打击」谈「降维」

        生活中常常听到一个词:降维打击。

        如何理解?

        “王健林的小目标和我的小目标”就是最好的诠释。

        对于数据来说,虽然不存在「打击」之说,但先对其降一波维,利用可视化的方式从整体上对数据有个事先的了解,再做后续分析,还是挺有用的,下面举两个例子。

示例1

        现有如下数据,每一行代表一个国家,每一列代表一个特征(比如GDP、居民生活指数等),那么该如何在建模前分析这些数据呢?

从「降维打击」谈「降维」_第1张图片

        我们知道,对数据先进行可视化操作,能够在一开始就把握数据的整体情况。然而,在这个问题中不可能把每一个特征当做一个维度进行可视化,因为只要超过3维就难以进行绘图,这个时候,降维就有用了:通过特征转换,构造出两个特征z1、z2来概括这些特征,从而可以在二维坐标系里绘图(需要注意的是,我们需要弄清楚这两个特征大致是什么意思):

从「降维打击」谈「降维」_第2张图片

图一

从「降维打击」谈「降维」_第3张图片

图二

        假如图二中横坐标代表GDP,纵坐标代表人均GDP或个人经济活跃程度,那么可以看出,越靠右上的国家,GDP和个人经济活跃程度就越高,代表这个国家是比较发达的,同时个人的生活满意度也会比较高;越靠左下的国家,GDP和个人经济活跃程度就越低,可能是一些比较小的国家,同时居民的生活水平不会很高。

示例2

        有时候拿到一些数据,但没有标签,从而不知道每个样本的属性是什么样的,那么,就需要利用诸如“聚类”的方法来初步探索数据,大概了解样本之间有没有什么共性。

        在计算机视觉领域,有一个入坑选手一定玩过的数据集——mnist手写数字数据集,随便选取一个样本,看看长什么样:

def image_show(image):
    fig = plt.gcf()
    fig.set_size_inches(5,5)
    plt.imshow(image,cmap = 'binary')
    plt.show()
​
image_show(X_train[5]) # 这里的5不是数字5,而是第6个样本

输出:

从「降维打击」谈「降维」_第4张图片

        上面是通过 .imshow( )函数可视化每个数字,如果直接输出这个样本,那么会得到一个长为784的向量:(更不可能通过这个来分析样本了)

从「降维打击」谈「降维」_第5张图片

        下面看看如何通过降维,把784的维度降到2维,然后可视化这些样本:

# 导入要用到的库:
from keras.datasets import mnist
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.cluster import KMeans
from scipy.linalg import eigh
import seaborn as sns

#降维:
(X_train,Y_train),(X_test,Y_test) = mnist.load_data() # 加载数据
X = X_train[:10000] # 选取前10000个数据
X_train = X.reshape(10000,-1)
df = pd.DataFrame(X_train) # 生成数据框,更好看
​
s = StandardScaler() # 标准化
df1 = s.fit_transform(df)
​
cov = np.matmul(df1.T, df1) # 计算协差阵,cov.shape=(784, 784)
values, vectors = eigh(cov, eigvals = (782, 783)) # 计算特征值和特征向量
vectors = vectors.T # vectors.shape=(2, 784)
df2 = np.matmul(vectors, df1.T) # 和协差阵相乘,降维,df2.shape=(2, 10000)
​
final_dfT = np.vstack((df2, label)).T # 把标签加进去
dataFrame = pd.DataFrame(final_dfT, columns = ['pca_1', 'pca_2','label'])

# 绘图
g = sns.FacetGrid(dataFrame, hue = 'label',size=10)
g.map(sns.scatterplot, 'pca_1', 'pca_2')
g.add_legend()
plt.show()
​


        最终:

从「降维打击」谈「降维」_第6张图片

        由于上面是利用带标签的数据进行降维+可视化的,所以还少了点意思(真实情况可能没有标签,所以针对数据的先验知识是很有限的)。

        下面就来看如何对没有标签的数据进行聚类+降维+可视化(尽管mnist中每个数字都带有标签,但我们假设所有数字是不带标签的):

# 数据依然用前面的:
X_train_1 = X.reshape(10000,784)
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train_1) # 最大最小归一化
​
# 直接调用PCA函数进行降维,之前是手动降维
pca_1=PCA(n_components=2, copy = False)
X_reduce = pca_1.fit_transform(X_train_minmax) # X_reduce.shape=(10000, 2)
​
# 利用 k-means 聚类
reduced_data = X_reduce
kmeans = KMeans(n_clusters=10, n_init=4)
kmeans.fit(reduced_data)
​
# 绘图
h = 0.02  
x_min, x_max = reduced_data[:, 0].min() - 1, reduced_data[:, 0].max() + 1
y_min, y_max = reduced_data[:, 1].min() - 1, reduced_data[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = kmeans.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8,8))
plt.clf()
plt.imshow(
    Z,
    interpolation="nearest",
    extent=(xx.min(), xx.max(), yy.min(), yy.max()),
    cmap=plt.cm.Paired,
    aspect="auto",
    origin="lower",
)
plt.plot(reduced_data[:, 0], reduced_data[:, 1], "k.", markersize=2)
centroids = kmeans.cluster_centers_
plt.scatter(
    centroids[:, 0],
    centroids[:, 1],
    marker="x",
    s=169,
    linewidths=3,
    color="w",
    zorder=10,
)
plt.title("K-means")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks(())
plt.yticks(())
plt.show()

最终:

从「降维打击」谈「降维」_第7张图片

        可以看出,在没有标签的情况下,利用聚类算法可以把类间相似的样本聚到一块儿,然后降成可在平面上绘图的二维数据。

小结:在解决一个新问题时,拿到手的数据往往是比较杂乱的,如果能降到二维/三维,然后对这些数据进行可视化,那么会更有利于后续特征的选取、模型的选取等工作。


如有新的想法,期待交流探讨

你可能感兴趣的:(机器学习/深度学习,聚类,数据挖掘,机器学习,python,计算机视觉)