【CS231n】斯坦福大学李飞飞视觉识别课程笔记
原文地址:https://scikit-learn.org/stable/modules/random_projection.html
sklearn.random_projection模块实现了一种简单且计算效率高的降低数据的维数的方法,这种方法是通过控制一定的准确率(作为附加方差)来换取更快的处理时间和更小的模型规模。该模块实现了两种非结构化随机矩阵:高斯随机矩阵和稀疏随机矩阵。
控制随机投影矩阵的尺寸和分布,以保持数据集任意两个样本之间的成对距离(the pairwise distances )。因此,对于基于距离的方法,随机投影是一种合适的近似技术。
一、Johnson-Lindenstrauss引理
1)、用于Johnson-Lindenstrauss引理的理论解释
随机投影效率背后的主要理论结果是Johnson-Lindenstrauss引理(引自Wikipedia):
在数学中,约翰逊-林登-斯特劳斯引理是关于高维点到低维欧氏空间的低失真嵌入的结果。引理表明,高维空间中的一小组点可以嵌入到低维空间中,这样,点之间的距离几乎保持不变。用于嵌入的映射至少是 ,甚至可以看作是正交投影。
只知道样本的个数,sklearn.random_projection.johnson_lindenstrauss_min_dim保守估计随机子空间的最小尺寸,以保证随机投影引入有界失真:
sklearn.random_projection.johnson_lindenstrauss_min_dim(n_samples,
eps = 0.1
)
找到一个“安全”的组件数量,随机投影到其中
在欧氏空间中,随机投影p引入的失真只会使两点之间的距离变化一个因子( ),具有良好的概率。投影p为eps嵌入,定义为:
其中u和v是形状 [n_samples, n_features] 数据集中的任意行,eps在 ]0,1[ 中,p是由形状 [n_components, n_features] 的随机高斯N(0,1)矩阵(或稀疏无差矩阵)投影得到的。
保证嵌入eps的最小构件数为:
注意,维度的数量与原始特征的数量无关,而是取决于数据集的大小:数据集越大,嵌入eps的最小维度就越高。
参数:
-
n_samples: int或numpy数组的int值大于0,样品的数量。如果给定一个数组,它将按数组顺序计算一个安全的组件数。
-
eps: float或numpy数组中的float in ]0,1[ ,可选(默认值=0.1),最大失真率所定义的Johnson-Lindenstrauss引理。如果给定一个数组,它将按数组顺序计算一个安全的组件数。
Returns:
n_components: int或numpy数组的int,最小数量的组件,保证有良好的概率与eps嵌入n_samples。
>>> from sklearn.random_projection import johnson_lindenstrauss_min_dim
>>> johnson_lindenstrauss_min_dim(1e6, eps=[0.5, 0.1, 0.01])
array([ 663, 11841, 1112658])
>>> johnson_lindenstrauss_min_dim([1e4, 1e5, 1e6], eps=0.1)
array([ 7894, 9868, 11841])
第一个图表显示,随着样本n_samples数量的n_components增加,最小数量的维度以对数方式增加,以保证eps嵌入。
第二个图表明,允许失真的增加eps可以大大减少n_components给定数量样本的最小维数n_samples。
2)、使用稀疏随机矩阵的经验验证
我们在数字数据集或20个新闻组文本文档(TF-IDF词频率)数据集上验证上述边界:
-
对于数字数据集,500个手写数字图片的一些8×8灰度级像素数据被随机投影到空间以用于各种更大数量的维度n_components。
-
对于20个新闻组数据集,使用稀疏随机矩阵将具有100k特征的大约500个文档投影到具有针对目标维数的各种值的较小欧几里德空间n_components。
默认数据集是数字数据集。要在二十个新闻组数据集上运行该示例,请将-twenty-newsgroups命令行参数传递给此脚本。
对于每个值n_components,我们绘制:
- 样本对的2D分布,原始和投影空间中的成对距离分别为x和y轴。
- 这些距离(投射/原始)的比率的1D直方图。
我们可以看到,n_components分布的低值很宽,有许多失真的对和偏斜的分布(由于左边的零比率的硬限制,因为距离总是正的),而对于n_components的较大值,失真被控制并且随机投影很好地保留了距离。
3)、备注
根据JL引理,投影500个没有太多失真的样本将需要至少几千个维度,而不管原始数据集的特征数量。
因此,在输入空间中仅具有64个特征的数字数据集上使用随机投影是没有意义的:在这种情况下,它不允许降低维数。
另一方面,在二十个新闻组上,维度可以从56436减少到10000,同时合理地保留成对距离。
print(__doc__)
import sys
from time import time
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from distutils.version import LooseVersion
from sklearn.random_projection import johnson_lindenstrauss_min_dim
from sklearn.random_projection import SparseRandomProjection
from sklearn.datasets import fetch_20newsgroups_vectorized
from sklearn.datasets import load_digits
from sklearn.metrics.pairwise import euclidean_distances
# `normed` is being deprecated in favor of `density` in histograms
if LooseVersion(matplotlib.__version__) >= '2.1':
density_param = {'density': True}
else:
density_param = {'normed': True}
# Part 1: plot the theoretical dependency between n_components_min and
# n_samples
# range of admissible distortions
eps_range = np.linspace(0.1, 0.99, 5)
colors = plt.cm.Blues(np.linspace(0.3, 1.0, len(eps_range)))
# range of number of samples (observation) to embed
n_samples_range = np.logspace(1, 9, 9)
plt.figure()
for eps, color in zip(eps_range, colors):
min_n_components = johnson_lindenstrauss_min_dim(n_samples_range, eps=eps)
plt.loglog(n_samples_range, min_n_components, color=color)
plt.legend(["eps = %0.1f" % eps for eps in eps_range], loc="lower right")
plt.xlabel("Number of observations to eps-embed")
plt.ylabel("Minimum number of dimensions")
plt.title("Johnson-Lindenstrauss bounds:\nn_samples vs n_components")
# range of admissible distortions
eps_range = np.linspace(0.01, 0.99, 100)
# range of number of samples (observation) to embed
n_samples_range = np.logspace(2, 6, 5)
colors = plt.cm.Blues(np.linspace(0.3, 1.0, len(n_samples_range)))
plt.figure()
for n_samples, color in zip(n_samples_range, colors):
min_n_components = johnson_lindenstrauss_min_dim(n_samples, eps=eps_range)
plt.semilogy(eps_range, min_n_components, color=color)
plt.legend(["n_samples = %d" % n for n in n_samples_range], loc="upper right")
plt.xlabel("Distortion eps")
plt.ylabel("Minimum number of dimensions")
plt.title("Johnson-Lindenstrauss bounds:\nn_components vs eps")
# Part 2: perform sparse random projection of some digits images which are
# quite low dimensional and dense or documents of the 20 newsgroups dataset
# which is both high dimensional and sparse
if '--twenty-newsgroups' in sys.argv:
# Need an internet connection hence not enabled by default
data = fetch_20newsgroups_vectorized().data[:500]
else:
data = load_digits().data[:500]
n_samples, n_features = data.shape
print("Embedding %d samples with dim %d using various random projections"
% (n_samples, n_features))
n_components_range = np.array([300, 1000, 10000])
dists = euclidean_distances(data, squared=True).ravel()
# select only non-identical samples pairs
nonzero = dists != 0
dists = dists[nonzero]
for n_components in n_components_range:
t0 = time()
rp = SparseRandomProjection(n_components=n_components)
projected_data = rp.fit_transform(data)
print("Projected %d samples from %d to %d in %0.3fs"
% (n_samples, n_features, n_components, time() - t0))
if hasattr(rp, 'components_'):
n_bytes = rp.components_.data.nbytes
n_bytes += rp.components_.indices.nbytes
print("Random matrix with size: %0.3fMB" % (n_bytes / 1e6))
projected_dists = euclidean_distances(
projected_data, squared=True).ravel()[nonzero]
plt.figure()
plt.hexbin(dists, projected_dists, gridsize=100, cmap=plt.cm.PuBu)
plt.xlabel("Pairwise squared distances in original space")
plt.ylabel("Pairwise squared distances in projected space")
plt.title("Pairwise distances distribution for n_components=%d" %
n_components)
cb = plt.colorbar()
cb.set_label('Sample pairs counts')
rates = projected_dists / dists
print("Mean distances rate: %0.2f (%0.2f)"
% (np.mean(rates), np.std(rates)))
plt.figure()
plt.hist(rates, bins=50, range=(0., 2.), edgecolor='k', **density_param)
plt.xlabel("Squared distances rate: projected / original")
plt.ylabel("Distribution of samples pairs")
plt.title("Histogram of pairwise distance rates for n_components=%d" %
n_components)
# TODO: compute the expected value of eps and add them to the previous plot
# as vertical lines / region
plt.show()
> Automatically created module for IPython interactive environment
Embedding 500 samples with dim 64 using various random projections
Projected 500 samples from 64 to 300 in 0.015s
Random matrix with size: 0.028MB
> Mean distances rate: 1.01 (0.09)
Projected 500 samples from 64 to 1000 in 0.042s
Random matrix with size: 0.096MB
> Mean distances rate: 0.99 (0.05)
> Projected 500 samples from 64 to 10000 in 0.437s
Random matrix with size: 0.962MB
Mean distances rate: 1.00 (0.01)
二、高斯随机投影
在sklearn.random_projection.GaussianRandomProjection由上,其中组分从下列分布中抽取一个随机生成的矩阵投影原始输入空间减小了维数 。
class sklearn.random_projection.GaussianRandomProjection(n_components ='auto',
eps = 0.1,
random_state = None
)
通过高斯随机投影降低维数
随机矩阵的分量是从N(0,1/n_components)中提取的。
参数:
-
n_components : int或’auto’,可选(默认=‘自动’)
目标投影空间的维数。
n_components可以根据数据集中的样本数量和Johnson-Lindenstrauss引理给出的界限自动调整。在这种情况下,嵌入的质量由eps参数控制。
应该注意的是,Johnson-Lindenstrauss引理可以非常保守地估计所需的组件数量,因为它没有假设数据集的结构。
-
eps : 严格正浮动,可选(默认= 0.1)
当n_components设置为“auto”时,根据Johnson-Lindenstrauss引理控制嵌入质量的参数。
较小的值导致更好的嵌入和更大数量的维度(n_components)在目标投影空间中。
-
random_state : int,RandomState实例或None,可选(默认=无)
控制用于在拟合时生成矩阵的伪随机数发生器。如果是int,则random_state是随机数生成器使用的种子; 如果是RandomState实例,则random_state是随机数生成器; 如果没有,随机数生成器所使用的RandomState实例np.random。
属性:
-
n_component_ : int
当n_components =“auto”时计算的具体组件数。
-
components_ : numpy shape of shape [n_components,n_features]
用于投影的随机矩阵。
>>> import numpy as np
>>> from sklearn.random_projection import GaussianRandomProjection
>>> X = np.random.rand(100, 10000)
>>> transformer = GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.shape
(100, 3947)
方法:
- fit(X[, y]):生成稀疏随机投影矩阵
- fit_transform(X[, y]):适应数据,然后转换它。
- get_params([deep]):获取此估算工具的参数。
- set_params(**params):设置此估算器的参数。
- transform(X):使用具有随机矩阵的矩阵乘积来投影数据
__init__(n_components=’auto’, eps=0.1, random_state=None)
fit(X, y=None)
生成稀疏随机投影矩阵
参数:
- X : numpy数组或形状的scipy.sparse [n_samples,n_features]
训练集:仅基于前述论文中引用的理论,使用形状来找到最佳随机矩阵维度。 - y
Ignored
Returns:
- self
fit_transform(X, y=None, **fit_params)
适应数据,然后转换它
使用可选参数fit_params使变换器适合X和y,并返回X的变换版本。
参数:
-
X : numpy数组形状[n_samples,n_features]
训练集。 -
y : numpy数组形状[n_samples]
目标值。
Return:
- X_new : numpy形状数组[n_samples,n_features_new]
变形阵列。
get_params(deep=True)
获取此估算工具的参数。
参数:
- deep : 布尔值,可选
如果为True,将返回此估计器的参数并包含作为估算器的子对象。
Return:
- params : 将字符串映射到任何字符串
映射到其值的参数名称。
set_params(**params)
设置此估算器的参数。
该方法适用于简单估计器以及嵌套对象(例如管道)。后者具有表单的参数, __因此可以更新嵌套对象的每个组件。
Return:
- self
transform(X)
使用具有随机矩阵的矩阵乘积来投影数据
参数:
- X : numpy数组或形状的scipy.sparse [n_samples,n_features]
投影到较小维空间的输入数据。
Return:
- X_new : numpy数组或scipy稀疏形状[n_samples,n_components]
投射阵列。
三、稀疏随机投影
在sklearn.random_projection.SparseRandomProjection通过投影使用稀疏随机矩阵原始输入空间减小的维数。
稀疏随机矩阵是密集高斯随机投影矩阵的替代方案,其保证了类似的嵌入质量,同时具有更高的存储器效率并允许更快地计算投影数据。
如果我们定义,则从中抽取随机矩阵的元素s = 1 / density
其中
是投影子空间的大小。默认情况下,非零元素的密度设置为Ping Li等人推荐的最小密度:
。
class sklearn.random_projection.SparseRandomProjection(n_components=’auto’,
density=’auto’,
eps=0.1,
dense_output=False,
random_state=None
)
参数:
-
n_components : int或’auto’,可选(默认=‘自动’)
目标投影空间的维数。n_components可以根据数据集中的样本数量和Johnson-Lindenstrauss引理给出的界限自动调整。在这种情况下,嵌入的质量由eps参数控制。
应该注意的是,Johnson-Lindenstrauss引理可以非常保守地估计所需的组件数量,因为它没有假设数据集的结构。
-
密度 : 浮动范围] 0,1],可选(默认=‘自动’)
随机投影矩阵中非零分量的比率。如果density =‘auto’,则将该值设置为Ping Li等人推荐的最小密度:1 / sqrt(n_features)。
如果要重现Achlioptas,2001的结果,请使用density = 1 / 3.0。
-
eps : 严格正浮,可选,(默认= 0.1)
当n_components设置为“auto”时,根据Johnson-Lindenstrauss引理控制嵌入质量的参数。较小的值导致更好的嵌入和更大数量的维度(n_components)在目标投影空间中。
-
dense_output : 布尔值,可选(默认= False)
如果为True,即使输入和随机投影矩阵都是稀疏的,也要确保随机投影的输出是密集的numpy数组。实际上,如果组件的数量很少,则投影数据中的零组件的数量将非常小,并且使用密集表示将使CPU和存储器的效率更高。如果为False,则如果输入是稀疏的,则投影数据使用稀疏表示。
-
random_state : int,RandomState实例或None,可选(默认=无)
控制用于在拟合时生成矩阵的伪随机数发生器。如果是int,则random_state是随机数生成器使用的种子; 如果是RandomState实例,则random_state是随机数生成器; 如果没有,随机数生成器所使用的RandomState实例np.random。
属性:
-
n_component_ : int
当n_components =“auto”时计算的具体组件数。 -
components_ : 带有形状的CSR矩阵[n_components,n_features]
用于投影的随机矩阵。 -
density_ : 浮点范围0.0 - 1.0
从密度=“自动”时计算的混凝土密度。
>>> import numpy as np
>>> from sklearn.random_projection import SparseRandomProjection
>>> np.random.seed(42)
>>> X = np.random.rand(100, 10000)
>>> transformer = SparseRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.shape
(100, 3947)
>>> # very few components are non-zero
>>> np.mean(transformer.components_ != 0)
0.0100...
方法:
- fit(X[, y]):生成稀疏随机投影矩阵
- fit_transform(X[, y]):适应数据,然后转换它。
- get_params([deep]):获取此估算工具的参数。
- set_params(**params):设置此估算器的参数。
- transform(X):使用具有随机矩阵的矩阵乘积来投影数据
__init__(n_components=’auto’, eps=0.1, random_state=None)
fit(X, y=None)
生成稀疏随机投影矩阵
参数:
- X : numpy数组或形状的scipy.sparse [n_samples,n_features]
训练集:仅基于前述论文中引用的理论,使用形状来找到最佳随机矩阵维度。 - y
Ignored
Returns:
- self
fit_transform(X, y=None, **fit_params)
适应数据,然后转换它
使用可选参数fit_params使变换器适合X和y,并返回X的变换版本。
参数:
-
X : numpy数组形状[n_samples,n_features]
训练集。 -
y : numpy数组形状[n_samples]
目标值。
Return:
- X_new : numpy形状数组[n_samples,n_features_new]
变形阵列。
get_params(deep=True)
获取此估算工具的参数。
参数:
- deep : 布尔值,可选
如果为True,将返回此估计器的参数并包含作为估算器的子对象。
Return:
- params : 将字符串映射到任何字符串
映射到其值的参数名称。
set_params(**params)
设置此估算器的参数。
该方法适用于简单估计器以及嵌套对象(例如管道)。后者具有表单的参数, __因此可以更新嵌套对象的每个组件。
Return:
- self
transform(X)
使用具有随机矩阵的矩阵乘积来投影数据
参数:
- X : numpy数组或形状的scipy.sparse [n_samples,n_features]
投影到较小维空间的输入数据。
Return:
- X_new : numpy数组或scipy稀疏形状[n_samples,n_components]
投射阵列。