降维方法总结(未完)

一、降维方法的分类

降维方法主要分为两种:

  • 特征选择:仅保留原始数据集中最相关的变量。
  • 降维:寻找一组较少的新变量,其中每个变量都是输入变量的组合。

二、常用的降维方法

1、缺失值比率(Missing Value Ratio)

(1)理论

  • 当缺失值在数据集中的占比过高时,可以选择直接删除这个变量,因为它包含的信息太少了。
  • 通常设置一个阈值,如果缺失值占比高于阈值,删除它所在的列。
  • 阈值越高,降维方法越积极。

(2)编程实现

# 导入需要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 读取数据
train = pd.read_csv("Train_example.csv")

# 用 .isnull().sum() 检查每个变量中缺失值的占比
train.isnumm().sum()/len(train)*100 # 由结果设阈值为20%

# 保存变量中的缺失值
a = train.isnull().sum()/len(train)*100
# 保存列名
variables = train.columns
variable = []
for i in range(0,12):
  if a[i] <= 20:			# 设阈值为20%
    variable.append(variables[i])

2、低方差滤波(Low Variance Filter)

(1)理论

  • 通常认为低方差变量携带的信息量很少,所以可以直接删除。
  • 注意:方差与数据范围相关,因此采用该方法前需对数据归一化。

(2)编程实现

# 接上例,我们现估算缺失值
train['Weight'].fillna(train['Weight'].median, inplace=True)
train['Size'].fillna(train['Size'].mode()[0], inplace=True)

# 检查缺失值是否已经被填充
train.isnull().sum()/len(train)*100

# 计算所有数值变量的方差
train.var()

# 保留方差大于10的变量
numeric = train[['Weight','Visibility','MRP','Size']] # 提取数值列
var = numeric.var()
numeric = numeric.columns
variable = []
for i in range(0,len(var)):
  if var[i] >= 10:		# 将阈值设置为10
    variable.append(numeric[i+1])

3、高相关滤波(High Correlation filter)

(1)理论

  • 如果两个变量间高度相关,意味着它们具有相似的趋势并且可能携带类似的信息。
  • 并且这类变量的存在会降低某些模型的性能(例如线性和逻辑回归模型)。
  • 我们可以计算独立数值变量间的相关性,如果相关系数超过某个阈值,就删除其中一个变量。
  • 通常情况下,如果一对变量间相关性大于0.5-0.6,就可以考虑删除一列。

(2)编程实现

# 首先删除因变量(Sales),并将剩余的变量保存在新的数据列 df 中
df = train.drop('Sales', 1)
df.corr()

4、随机森林(Random Forest)

(1)理论

  • 随机森林是一种广泛使用的特征选择算法,它会自动计算各个特征的重要性。
  • 随机森林只接受数字输入。

(2)编程实现

# 首先将数据转换为数字格式,并删除不重要的 ID 列
from sklearn.ensemble import RandomForestRegressor
df = df.drop('ID', axis = 1)
df = pd.get_dummies(df)

# 拟合模型
model = RandomForestRegressor(random_state=1, max_depth=10)
model.fit(df,train.Sales)

# 根据特征的重要性绘制成图
features = df.columns
importances = model.feature_importances_
indices = np.argsort(importances[0:9])   # 重要性最高的10个特征
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Import')
plt.show()

# 可以手动选择重要性最高的特征来减少数据集中的维度
# 也可以直接使用 sklearn 中的 SelectFromModel,它根据权重的重要性选择特征
from sklearn.feature_selection import SelectFromModel
feature = SelectFromModel(model)
Fit = feature.fit_transform(df, train.Sales)

5、反向特征消除(Backward Feature Elimination)

(1)理论

  • 反向特征消除对应的是统计学变量选择方法中的“后退法”。
  • 以下是反向特征消除的主要步骤:
    1. 先获取数据集中的全部 n 个变量,然后用他们训练一个模型;
    2. 计算模型的性能;
    3. 在删除每个变量(n 次)后计算模型的性能,即我们每次都去掉一个变量,用剩余的 n-1 个变量训练模型;
    4. 确定对模型性能影响最小的变量,把它删除;
    5. 重复此过程,直到不再能删除任何变量。

(2)编程实现

# 构建线性回归模型,Logistic回归模型同理
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
from sklearn import datasets
lreg = LinearRegression()
rfe = RFE(lreg, 10)
rfe = rfe.fit_transform(df, train.Sales)

6、前向特征选择(Forward Feature Selection)

(1)理论

  • 前向特征选择其实就是反向特征消除的相反过程,即找到能改善模型性能的最佳特征,而不是删除弱影响特征。
  • 前向特征选择对应的是统计学变量选择方法中的“前进法”。
  • 以下是前向特征选择的主要步骤:
    1. 每次选择一个特征,训练模型 n 次,得到 n 个模型;
    2. 选择模型性能最佳的变量作为初始变量;
    3. 每次添加一个变量继续训练,重复上一过程,最后保留性能提升最大的变量;
    4. 一直添加,一直筛选,直到模型性能不再有明显提高。

(2)编程实现

# 返回每个变量的 F 值和相对应的 p 值
from sklearn.feature_selection import f_regression
ffs = f_regression(df, train.Sales)	

# 选择 F 值大于10的变量
variable = []
for i in range(0,len(df.columns)-1):
  if ffs[0][i] >= 10:
    variable.append(df.columns[i])

注: 前向特征选择和反向特征消除耗时较久,计算成本也都很高,所以只适用于输入变量较少的数据集。

7、因子分析

(1)原理

  • 因子分析从多个变量中提取共性因子,并得到最优解。例如变量“收入”和“教育”,它们可能是高度相关的,因为总体来看,学历高的人一般收入也越高。所以他们可能存在一个潜在的共性因子:“能力”。
  • 在因子分析中,我们将变量按照其相关性分组,即组内变量相关性较高,组间变量相关性较低。
  • 我们把每个组称为一个因子,它是多个变量的组合。(是否有点像稀疏主成分分析?只是因子分析限定了不同因子的组成变量是不相关的,而稀疏主成分分析没有对此严格限制。)

(2)编程实现

import pandas as pd
import numpy as np
from glob import glob
import cv2
# 这里必须使用 train 文件夹的路径替换 glob 函数内的路径。
images = [cv2.imread(file) for file in glob('train/*.png')]

# 将图像转换为 numpy 数组格式,以便执行数学运算并绘制图像。
images = np.array(images)
images.shape
# Output: (60000,28,28,3)

# 将上面的三位数组转成一维(因为后续只接受一维输入),将图像展平:
image = []
for i in range(0,60000):
  img = images[i].flatten()
  image.append(img)
image = np.array(image)

# 创建一个数据框,其中包含每个像素的像素值,以及它们对应的标签:
train = pd.read_csv("/train.csv")
feat_cols = [ 'pixel'+str(i) for i in range(image.shape[1])]
df = pd.DataFrame(image, columns=feat_cols)
df['label'] = train['label']

# 用因子分析分解数据集,n_components 决定转换数据中的因子数量
from sklearn.decomposition import FactorAnalysis
FA = FactorAnalysis(n_components=3).fit_transform(df[feat_cols].values)

# 可视化因子转换结果
%matplotlib inline 
import matplotlib.pyplot as plt
plt.figure(figsize=(12,8))
plt.title('Factor Analysis Components')
plt.scatter(FA[:,0], FA[:,1])
plt.scatter(FA[:,1], FA[:,2])
plt.scatter(FA[:,2], FA[:,0])

8、主成分分析(PCA)

(1)原理

  • 因子分析假设存在一系列潜在因子,能反映变量携带的信息。
  • 主成分分析通过正交变换将原始的 n 维数据集变化到一个新的被称作主成分的数据集中,即从现有的大量变量中提取一组新的变量。

(2)编程实现

# 在降维前,先随机绘制数据集中的某些图
rndperm = np.random.permutation(df.shape[0])
plt.gray()
fig = plt.figure(figsize=(20,20))
for i in range(0,15):
  ax = fig.add_subplot(3,5,i+1)
  ax.matshow(df.loc[rndperm[i],feat_cols].values.
            reshape((28,28*3)).astype(float))

# 实现 PCA,其中 n_components 决定转换数据中的主成分数量
from sklearn.decomposition import PCA
pca = PCA(n_components=4)
pca_result = pca.fit_transform(df[feat_cols].values)

# 接下来看4个主成分解释了多少方差
plt.plot(range(4), pca.explained_variance_ratio_)
plt.plot(range(4), np.cumsum(pca.explained_variance_ratio_))
plt.title("Component-wise and Cumulative Explained Variance")

9、独立分量分析(ICA)

(1)原理

  • 独立分量分析(ICA)基于信息理论,是最广泛使用的降维技术之一。
  • PCA 和 ICA 之间的主要区别在于,PCA 寻找不相关的因素,而 ICA 寻找独立因素。(如果两个变量不相关,它们之间就没有线性关系。如果它们是独立的,它们就不依赖于其他变量。例如,一个人的年龄和他吃了什么/看了什么电视无关。)
  • ICA 假设给定变量是一些未知潜在变量的线性混合。它还假设这些潜在变量是相互独立的,即它们不依赖于其他变量,因此它们被称为观察数据的独立分量。
  • 测试分量独立性最常用的方法是非高斯性:
    • 根据中心极限定理,多个独立随机变量混合之后会趋向于正态分布(高斯分布)。
    • 因此,我们可以寻找所有独立分量中能最大化峰度的分量。
    • 一旦峰度被最大化,整个分布会呈现非高斯分布,我们也能得到独立分量。

(2)编程实现

from sklearn.decomposition import FastICA
ICA = FastICA(n_components=3, random_state=12)
X = ICA.fit_transform(df[feat_cols].values)

10、IOSMAP

(1)原理

未完

(2)编码实现

# n_neighbors:决定每个点的相邻点数
# n_components:决定流行的坐标数
# n_jobs=-1:使用所有可用的 CPU 核心
from sklearn import manifold
trans_data = manifold.Isomap(n_neighbors=5, n_components=3, n_jobs=-1).fit_transform(df[feat_cols][:6000].values)

# 可视化
plt.figure(figsize=(12,8))
plt.title('Decomposition using ISOMAP')
plt.scatter(trans_data[:,0], trans_data[:,1])
plt.scatter(trans_data[:,1], trans_data[:,2])
plt.scatter(trans_data[:,2], trans_data[:,3])

11、t-SNE

(1)原理

未完

(2)编程实现

from sklearn.manifold import TSNE
tsne = TSNE(n_components=3, n_iter=300).fit_transform(df[feat_cols][:6000].values)

# 可视化
plt.figure(figsize=(12,8))
plt.title('t-SNE components')
plt.scatter(tsne[:,0], tsne[:,1])
plt.scatter(tsne[:,1], tsne[:,2])
plt.scatter(tsne[:,2], tsne[:,0])

12、UMAP

(1)原理

未完

(2)编码实现

# n_neighbors:确定相邻点的数量
# min_dist:控制允许嵌入的紧密程度,较大的值可确保嵌入点的分布更均匀
import umap
umap_data = umap.UMAP(n_neighbors=5, min_dist=0.3, n_components=3).fit_transform(df[feat_cols][:6000].values)

# 可视化
plt.figure(figsize=(12,8))
plt.title('Decomposition using UMAP')
plt.scatter(umap_data[:,0], umap_data[:,1])
plt.scatter(umap_data[:,1], umap_data[:,2])
plt.scatter(umap_data[:,2], umap_data[:,0])

13、Hash Trick

(1)原理

  • Hash Trick 是自然语言处理中降维的手段,它可以对类别特征进行降维。
  • Hash Trick 利用哈希函数来降维。例如对所有的 location_id 取余:location_id(mod p),就可以将 location 映射到 p 个不同的数值上。在此之上再用 one-hot encoding,我们就只增加了 p 列。

(2)编程实现

未完

三、降维方法总结

方法 适用范围
缺失值比率 适合数据集缺失太多情况
低方差滤波 可以识别和删除常量变量
高相关滤波 可以解决多重共线性
随机森林 可以明确算出每个特征的重要性
前向特征选择 只适用于输入变量较少的数据集
反向特征消除 只适用于输入变量较小的数据集
因子分析 适合数据集中存在高度相关变量集的情况
PCA 广泛用于处理线性数据
ICA 可以得到独立分量数据
ISOMAP 适合非线性数据处理
t-SNE 适合非线性数据处理,相较 ISOMAP,可视化更直接
UMAP 适合高维数据,相较 t-SNE,速度更快
Hash Trick 适合自然语言处理中的类别特征(类别数特别多的情况)