以下内容来自《Python数据科学指南》
降维方法比较:
- PCA:计算代价高昂,特征向量得存在线性相关。
- 核PCA: 特征向量是非线性相关也可以。
- SVD:比PCA更能解释数据,因为是直接作用于原数据集,不会像PCA一样,将相关变量转换为一系列不相干的变量。另外,PCA是单模因子分析方法,行列代表的是相同的实体,而SVD是双模因子(即适用两类实体矩阵),可以运用在文本挖掘中,行对应词,列对应文档。
- 高斯随机映射:速度快,利用欧氏距离降维,但数据多会有内存问题,可以考虑稀疏随机映射代替。
- NMF:常见于推荐系统,输入矩阵A = 降维矩阵(行)A_dash * 成本矩阵(列) F。
1. PCA: Principle Component Analysis, PCA 主成分分析,计算代价高昂,只适用于特征向量间存在线性相关的环境下。
- 将数据集中心化;
- 找出数据集的相关矩阵和单位标准偏差值;
- 将相关矩阵分解成它的特征向量和值;
- 基于降序的特征值选择Top-N特征向量;
- 投射输入的特征向量矩阵到一个新空间。
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 30 17:47:41 2018
@author: Alvin AI
"""
from sklearn.datasets import load_iris
import numpy as np
import matplotlib.pyplot as plt
import scipy
from sklearn.preprocessing import scale
data = load_iris()
x = data['data']
y = data['target']
x_s = scale(x,with_mean=True,with_std=True,axis=0)#中心化
x_c = np.corrcoef(x_s.T)#计算过相关矩阵
eig_val,r_eig_vec = scipy.linalg.eig(x_c)
print 'Eigen values \n%s' % (eig_val)#相关矩阵中找到的特征值
print '\n Eigen vectors \n%s' % (r_eig_vec)#相关矩阵中找的特征向量
#可解释变化的百分比=特征值/原特征变量的个数,这里是4个变量
w = r_eig_vec[:,0:2]#选择前两个特征向量,因为输出结果Eigen values的前两个特征值较大
x_rd = x_s.dot(w)#叉乘,四维变二维y
plt.figure(1)
plt.scatter(x_rd[:,0],x_rd[:,1],c=y)
plt.xlabel('component 1')
plt.ylabel('component 2')
#如何选择多少成分的方法
print "Component, Eigen Value, % of Variance, Cumulative %"
cum_per = 0
per_var = 0
for i,e_val in enumerate(eig_val):
per_var = round((e_val/len(eig_val)),3)
cum_per += per_var
print ('%d, %0.2f, %0.2f, %0.2f')%(i+1, e_val, per_var*100, cum_per*100)
#输出结果:
Eigen values #特征值
[2.91081808+0.j 0.92122093+0.j 0.14735328+0.j 0.02060771+0.j]
Eigen vectors #特征向量
[[ 0.52237162 -0.37231836 -0.72101681 0.26199559]
[-0.26335492 -0.92555649 0.24203288 -0.12413481]
[ 0.58125401 -0.02109478 0.14089226 -0.80115427]
[ 0.56561105 -0.06541577 0.6338014 0.52354627]]
#可解释变化的百分比=特征值/原特征变量的个数,这里是4个变量
#2.91/4=72.80
#第一个成分可解释72.80%,第二个成分可解释23%,前两份成分一起可以解释95.8%
Component, Eigen Value, % of Variance, Cumulative %
1, 2.91, 72.80, 72.80
2, 0.92, 23.00, 95.80
3, 0.15, 3.70, 99.50
4, 0.02, 0.50, 100.00
2. 核PCA:针对非线性数据集进行降维。核类别有:线性、多项式、sigmoid、余弦值、预先计算的、RBF。
from sklearn.datasets import make_circles
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA #PCA模块
from sklearn.decomposition import KernelPCA #核PCA模块
#生成一个变化非线性的数据集
np.random.seed(10)#定义一个随机种子号
x,y = make_circles(n_samples=400, factor=.2, noise=0.02)#factor代表维度
plt.close('all')#关闭当前所有图
plt.figure(1)
plt.title('original space')
plt.scatter(x[:,0],x[:,1],c=y)
plt.xlabel('$x_1$')
plt.ylabel('$x_2$')
#使用PCA降维
pca = PCA(n_components=2)
pca.fit(x)
x_pca=pca.transform(x)
#绘制前两个主成分的图
plt.figure(2)
plt.title('pca')
plt.scatter(x_pca[:,0],x_pca[:,1],c=y)
plt.xlabel('$x_1$')
plt.ylabel('$x_2$')
#将两个成分单独拎出来画,发现结果均映射在一条直线上,无法实现区分
class_1_index = np.where(y==0)[0]
class_2_index = np.where(y==1)[0]
plt.figure(3)
plt.title('pca-one component')
plt.scatter(x_pca[class_1_index,0],np.zeros(len(class_1_index)),color='red')
plt.scatter(x_pca[class_2_index,0],np.zeros(len(class_2_index)),color='blue')
#使用kernal PCA
#这里核PCA调用的核是径向基函数(Radial Basis Function, RBF)
#gamma值为10,gamma是一个核(用于处理非线性)参数--内核系数
kpca = KernelPCA(kernel='rbf',gamma=10)
x_kpca = kpca.fit_transform(x)
plt.figure(4)
plt.title('kernel pca')
plt.scatter(x_kpca[:,0],x_kpca[:,1],c=y)
plt.xlabel('$x_1$')
plt.ylabel('$x_2$')
3. 奇异值分解:Singular Value Decomposition, SVD, 与PCA不同,直接作用于原始数据矩阵。SVD把m*n矩阵分解成三个矩阵的乘积:A = U*S*V^T 。
- U:左奇异矩阵,m*k矩阵。
- V:右奇异矩阵,n*k矩阵。
- S:该矩阵的对角线值为奇异值,k*k矩阵。
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.preprocessing import scale
from scipy.linalg import svd
data = load_iris()
x = data['data']
y = data['target']
#只中心化,不需要把数据缩放到同一量纲
#因为现在的数据就是相同度量单位,不缩放还能捕捉到最大变化的基本单位
x_s = scale(x,with_mean=True,with_std=False,axis=0)
#用SVD分解矩阵
#没必要缩放数据,full_matrices=False是一定要有的
U,S,V = svd(x_s,full_matrices=False)
#选择最前两个奇异值来近似原始的矩阵
x_t = U[:,:2]
#最后用降维的成分来绘制出数据集的图形
plt.figure(1)
plt.scatter(x_t[:,0],x_t[:,1],c=y)
plt.xlabel("Component 1")
plt.ylabel("Component 2")
plt.show()
4. 高斯随机映射:速度快,利用数据间的距离来降低维度。
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 23 21:19:54 2018
@author: Alvin AI
"""
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import euclidean_distances
from sklearn.random_projection import GaussianRandomProjection
import matplotlib.pyplot as plt
#加载20个新闻租数据集
#我们只选用sci.crypt分类
#其他分类还包括“sci.med” "sci.space"等
cat = ['sci.crypt']
data = fetch_20newsgroups(categories=cat)
#从上面的数据集中创建一个词-文档矩阵,词频作为值,不哦那个idf
vectorizer = TfidfVectorizer(use_idf=False)
vector = vectorizer.fit_transform(data.data)
#执行映射,我们把维度降为1000
gauss_proj = GaussianRandomProjection(n_components=1000)
vector_t = gauss_proj.fit_transform(vector)
#打印出转换后的向量形态
print vector.shape
print vector_t.shape
#为了验证转换过程是否保持了距离,我们计算新的和旧的两点间距离
org_dist = euclidean_distances(vector)
red_dist = euclidean_distances(vector_t)
diff_dist = abs(org_dist-red_dist)
#绘制差距热图(只有前100个文档)
plt.figure()
plt.pcolor(diff_dist[0:100,0:100])
plt.colorbar()
plt.show()
5. 非负矩阵分解:Non-negative Matrix Factorization, NMF 。常用于推荐系统,预测原本缺失的数据。
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 31 15:04:36 2018
@author: Alvin AI
"""
import numpy as np#
#from collections import dafaultdict
from sklearn.decomposition import NMF
import matplotlib.pyplot as plt
#生成电影评分数据集
ratings = [\
[1,2,3,5,2,1],\
[2,3,1,1,2,1],\
[4,2,1,3,1,4],\
[2,9,5,4,2,1],\
[1,4,2,1,1,1]]
movie_dict = {1:'alvin story',
2:'star wars',
3:'inception',
4:'gunsa',
5:'dream',
6:'decomere'}
A = np.asmatrix(ratings,dtype=float)#向量化
max_components = 2
reconstruction_error = []
nmf = None
nmf = NMF(n_components = max_components, random_state=1) #降维到2
A_dash = nmf.fit_transform(A)#A_dash为降维矩阵,针对于行实例,即用户
for i in range(A_dash.shape[0]):
print 'User id = %d, comp1 score = %0.2f, comp2 score = \
%0.2f' % (i+1,A_dash[i][0],A_dash[i][1])
#输入矩阵A=A_dash*F
#A_dash为降维矩阵,针对于行实例,即用户
plt.figure(1)
plt.title('user concept mapping')
x = A_dash[:,0]
y = A_dash[:,1]
plt.scatter(x,y)
plt.xlabel('component1')
plt.ylabel('component2')
#F为成本矩阵,针对列实例,即电影
F =nmf.components_
plt.figure(2)
plt.title('movie concept mapping')
x = F[0,:]
y = F[1,:]
plt.scatter(x,y)
plt.xlabel('component1')
plt.ylabel('component2')
for i in range(F[0,:].shape[0]):
plt.annotate(movie_dict[i+1],(F[0,:][i],F[1,:][i]))#在图中给每个点加上电影名注释
plt.show()
#预测出电影评分,如果原输入矩阵有些是0,而在下面结果输出会预测出用户评分
reconstructed_A = np.dot(A_dash,F)
np.set_printoptions(precision=2)#精确到小数点后2位
print reconstructed_A