原始数据:表格、图片、视频、文本、语音、……
模型学习:最核心的部分,学习一个用来预测的映射
特征工程:
词袋模型 (bag-of-words):文本是单词的集合,单词独立无序
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer document1 = "I have a pen, I have an apple, apple pen." document2 = "I have a pen, I have pineapple, pineapple pen." cv = CountVectorizer(lowercase=False, token_pattern='\w+', binary=True) model = cv.fit_transform([document1, document2]) print(pd.DataFrame(model.toarray(), columns=cv.get_feature_names_out())) # I a an apple have pen pineapple # 0 1 1 1 1 1 1 0 # 1 1 1 0 0 1 1 1
| 词典 | I | a | an | apple | have | pen | pineapple |
|---|---|---|---|---|---|---|---|
| 文本 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
| 文本 2 | 1 | 1 | 0 | 0 | 1 | 1 | 1 |
词袋模型 (bag-of-words):文本是单词的集合,单词独立无序
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer document1 = "I have a pen, I have an apple, apple pen." document2 = "I have a pen, I have pineapple, pineapple pen." cv = CountVectorizer(lowercase=False, token_pattern='\w+') model = cv.fit_transform([document1, document2]) print(pd.DataFrame(model.toarray(), columns=cv.get_feature_names_out())) # I a an apple have pen pineapple # 0 2 1 1 2 2 2 0 # 1 2 1 0 0 2 2 2
| 词典 | I | a | an | apple | have | pen | pineapple |
|---|---|---|---|---|---|---|---|
| 文本 1 | 2 | 1 | 1 | 2 | 2 | 2 | 0 |
| 文本 2 | 2 | 1 | 0 | 0 | 2 | 2 | 2 |
词频 - 逆文本频率:对当前文本重要的单词必然
tf = 单词在当前文本中出现的次数 / 当前文本的总词数
idf = ln ((全部文本数 + C) / (包含该词的总文本数 + C)) + 1
tf - idf 特征 = normalize (tf × idf),即将 tf 和 idf 相乘后再标准化
import pandas as pd from sklearn.feature_extraction.text import TfidfVectorizer document1 = "I have a pen, I have an apple, apple pen." document2 = "I have a pen, I have pineapple, pineapple pen." tv = TfidfVectorizer(lowercase=False, token_pattern='\w+', norm='l1', smooth_idf=False) model = tv.fit_transform([document1, document2]) print(pd.DataFrame(model.toarray(), columns=tv.get_feature_names_out())) # I a an apple have pen pineapple # 0 0.165571 0.082785 0.140168 0.280335 0.165571 0.165571 0.000000 # 1 0.192561 0.096281 0.000000 0.000000 0.192561 0.192561 0.326035
| 词典 | I | a | an | apple | have | pen | pineapple |
|---|---|---|---|---|---|---|---|
| tf | 2 / 10 | 1 / 10 | 1 / 10 | 2 / 10 | 2 / 10 | 2 / 10 | 0 |
| 2 / 9 | 1 / 9 | 0 | 0 | 2 / 9 | 2 / 9 | 2 / 9 | |
| idf | ln(1) + 1 | ln(1) + 1 | ln(2) + 1 | ln(2) + 1 | ln(1) + 1 | ln(1) + 1 | ln(2) + 1 |
| tf - idf | 0.165 | 0.082 | 0.140 | 0.280 | 0.165 | 0.165 | 0.000 |
| 0.192 | 0.096 | 0.000 | 0.000 | 0.192 | 0.192 | 0.326 |
| 次序 | 时间 | 方式 | 天气 | 课业 | 疫情 | 电视 | 约会 |
|---|---|---|---|---|---|---|---|
| 1 | 周六 | 吃饭 | 晴天 | 轻松 | 清零 | 精彩 | 是 |
| 6 | 周六 | 逛街 | 晴天 | 轻松 | 平缓 | 无聊 | 是 |
| 10 | 周六 | 学习 | 雨天 | 轻松 | 严峻 | 无聊 | 否 |
| 13 | 周六 | 逛街 | 晴天 | 适中 | 清零 | 精彩 | 否 |
import numpy as np from sklearn.preprocessing import LabelBinarizer, OneHotEncoder X = np.array([ [1, '周六', '吃饭', '晴天', '轻松', '清零', '精彩'], [6, '周六', '逛街', '晴天', '轻松', '平缓', '无聊'], [10, '周六', '-', '雨天', '轻松', '严峻', '无聊'], [13, '周六', '逛街', '晴天', '正常', '清零', '精彩'], ]) y = np.array(['是', '是', '否', '否']) print(LabelBinarizer().fit_transform(y).squeeze()) # 标记二值化 # [1 1 0 0] enc = OneHotEncoder() print(enc.fit_transform(X[:, 1:7]).toarray()) # 对6个类别特征采用独热编码 # [[1. 0. 1. 0. 1. 0. 0. 1. 0. 0. 1. 0. 1.] # [1. 0. 0. 1. 1. 0. 0. 1. 0. 1. 0. 1. 0.] # [1. 1. 0. 0. 0. 1. 0. 1. 1. 0. 0. 1. 0.] # [1. 0. 0. 1. 1. 0. 1. 0. 0. 0. 1. 0. 1.]] print(enc.get_feature_names_out()) # 独热编码对应的原始特征 # ['x0_周六' 'x1_-' 'x1_吃饭' 'x1_逛街' 'x2_晴天' 'x2_雨天' 'x3_正常' 'x3_轻松' 'x4_严峻' # 'x4_平缓' 'x4_清零' 'x5_无聊' 'x5_精彩']
| 次序 | 时间 | 方式 | 天气 | 课业 | 疫情 | 电视 | 温度 | 距离 | 约会 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 周六 | 吃饭 | 晴天 | 轻松 | 清零 | 精彩 | 25.2 | 0.5 | 是 |
| 6 | 周六 | 逛街 | 晴天 | 轻松 | 平缓 | 无聊 | - | 2.0 | 是 |
| 10 | 周六 | - | 雨天 | 轻松 | 严峻 | 无聊 | 32.6 | 8.2 | 否 |
| 13 | 周六 | 逛街 | 晴天 | 适中 | 清零 | 精彩 | 36.4 | 9.8 | 否 |
最简单的方法就是直接删除有特征缺失的样本,信息丢失
补全:
import numpy as np from sklearn.ensemble import ExtraTreesRegressor from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer, SimpleImputer from sklearn.neighbors import KNeighborsRegressor from sklearn.tree import DecisionTreeRegressor X = np.array([ [1, '周六', '吃饭', '晴天', '轻松', '清零', '精彩', 25.2, 0.5], [6, '周六', '逛街', '晴天', '轻松', '平缓', '无聊', np.nan, 2.0], [10, '周六', '-', '雨天', '轻松', '严峻', '无聊', 32.6, 8.2], [13, '周六', '逛街', '晴天', '正常', '清零', '精彩', 36.4, 9.8], ]) imp_mean = SimpleImputer(strategy='mean') print(imp_mean.fit_transform(X[:, [7]])) # 用均值填充 # [[25.2] # [31.4] # [32.6] # [36.4]] imp_median = SimpleImputer(strategy='median') print(imp_median.fit_transform(X[:, [7]])) # 用中位数填充 # [[25.2] # [32.6] # [32.6] # [36.4]] imp_frequent = SimpleImputer(missing_values='-', strategy='most_frequent') print(imp_frequent.fit_transform(X[:, [2]].astype('object'))) # 用众数填充 # [['吃饭'] # ['逛街'] # ['逛街'] # ['逛街']] # 回归器默认采用BayesianRidge # 其它可选DecisionTreeRegressor ExtraTreesRegressor KNeighborsRegressor imp_iter = IterativeImputer(estimator=KNeighborsRegressor(n_neighbors=2)) print(imp_iter.fit_transform(X[:, [0, 7, 8]])) # [[ 1. 25.2 0.5] # [ 6. 28.9 2. ] # [10. 32.6 8.2] # [13. 36.4 9.8]]
也称归一化,旨在消除不同特征间的量纲影响
离差标准化:将原始特征线性变换到 [0, 1] 区间
$$ \begin{align*} \quad x \leftarrow \frac{x - x_\min}{x_\max - x_\min} \in [0,1] \end{align*} $$
最大值标准化:除以该特征的绝对值最大值
$$ \begin{align*} \quad x \leftarrow \frac{x}{\max_{i \in [m]} |x_i|} \in [-1,1] \end{align*} $$
标准差标准化:经过处理的特征近似符合标准正态分布$\Ncal(0,1)$
$$ \begin{align*} \quad x \leftarrow \frac{x - \mu}{\sigma}, \quad x \leftarrow \frac{x - x_{\text{median}}}{\sum_{i \in [m]} |x_i - x_{\text{median}}| / m} \end{align*} $$
import numpy as np from sklearn.preprocessing import MaxAbsScaler, MinMaxScaler, scale X = np.array([ [1, '周六', '吃饭', '晴天', '轻松', '清零', '精彩', 25.2, 0.5], [6, '周六', '逛街', '晴天', '轻松', '平缓', '无聊', 27.4, 2.0], [10, '周六', '学习', '雨天', '轻松', '严峻', '无聊', 32.6, 8.2], [13, '周六', '逛街', '晴天', '正常', '清零', '精彩', 36.4, 9.8], ]) print(MinMaxScaler().fit_transform(X[:, [0, 7, 8]])) # 最大值变成1 同时 最小值变成0 # [[0. 0. 0. ] # [0.41666667 0.19642857 0.16129032] # [0.75 0.66071429 0.82795699] # [1. 1. 1. ]] print(MaxAbsScaler().fit_transform(X[:, [0, 7, 8]])) # 最大值变成1 # [[0.07692308 0.69230769 0.05102041] # [0.46153846 0.75274725 0.20408163] # [0.76923077 0.8956044 0.83673469] # [1. 1. 1. ]] x = scale(X[:, [0, 7, 8]]) print(x) # [[-1.44444444 -1.1861146 -1.17034706] # [-0.33333333 -0.68429689 -0.79077504] # [ 0.55555556 0.50181772 0.77812264] # [ 1.22222222 1.36859377 1.18299946]] print(x.mean(axis=0), x.std(axis=0)) # 均值为0 标准差为1 # [ 5.55111512e-17 2.22044605e-16 -5.55111512e-17] [1. 1. 1.]
模型学习前的最后一步,亦有将该步与模型学习融合的做法
当部分特征冗余甚至有害时,挑选或生成有用的特征子集
当特征稀缺时,利用现有特征构造新的特征
import numpy as np from sklearn.feature_selection import VarianceThreshold # 对6个离散类别特征采用了独热编码 X = np.array([ [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1.], [1., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0.], [1., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0.], [1., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.] ]) print(X.shape) # (4, 13) # 第1列由特征“时间”而来 四个样本都取值“周六” 独热编码后都是1 方差为0 XX = VarianceThreshold(threshold=0.01).fit_transform(X) print(XX) # [[1. 0. 0. 1. 0. 0. 1. 0. 0. 1. 0. 1.] # [0. 0. 1. 1. 0. 0. 1. 0. 1. 0. 1. 0.] # [0. 1. 0. 0. 1. 0. 1. 1. 0. 0. 1. 0.] # [0. 0. 1. 1. 0. 1. 0. 0. 0. 1. 0. 1.]] print(XX.shape) # (4, 12)
设共有$k$个类别,总样本数为$m = \sum_{i \in [k]} m_i$,总体均值为$\xbar$
设第$i$类第$j$个样本为$x_{ij}$,第$i$类的均值为$\xbar_i$,则总体偏差
$$ \begin{align*} \quad \sum_{i \in [k]} & \sum_{j \in [m_i]} (x_{ij} - \xbar)^2 = \sum_{i \in [k]} \sum_{j \in [m_i]} (x_{ij} - \xbar_i + \xbar_i - \xbar)^2 \\ & = \sum_{i \in [k]} \sum_{j \in [m_i]} [ (x_{ij} - \xbar_i)^2 + (\xbar_i - \xbar)^2 ] + \sum_{i \in [k]} 2 \underbrace{\sum_{j \in [m_i]} (x_{ij} - \xbar_i)}_{=~0} (\xbar_i - \xbar) \\ & = \sum_{i \in [k]} \sum_{j \in [m_i]} (x_{ij} - \xbar_i)^2 + \sum_{i \in [k]} m_i (\xbar_i - \xbar)^2 = \SSE + \SSB \end{align*} $$
对任意特征根据类别标记一分为二计算$F$值,判断差异是否显著
| 次序 | 时间 | 方式 | 天气 | 课业 | 疫情 | 电视 | 约会 |
|---|---|---|---|---|---|---|---|
| 1 | 周六 | 吃饭 | 晴天 | 轻松 | 清零 | 精彩 | 是 |
| 6 | 周六 | 逛街 | 晴天 | 轻松 | 平缓 | 无聊 | 是 |
| 10 | 周六 | 学习 | 雨天 | 轻松 | 严峻 | 无聊 | 否 |
| 13 | 周六 | 逛街 | 晴天 | 适中 | 清零 | 精彩 | 否 |
对特征“次序”,总体均值$\xbar = 7.5$
经独热编码,特征“是否无聊”的四个取值是$0,1,1,0$,均值$0.5$
import numpy as np from sklearn.feature_selection import SelectKBest, f_classif X = np.array([ # 已去掉方差为零的特征 [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1.], [6., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0.], [10., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0.], [13., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.], ]) y = [1, 1, 0, 0] sk = SelectKBest(f_classif) sk.fit_transform(X, y) print(sk.scores_) # [7.52941176 1. 1. 0. 1. 1. # 1. 1. 1. 1. 0. 0. # 0. ]
| 约会 | 不约会 | 边际概率 | |
|---|---|---|---|
| 吃饭 | $1, ~ (0.5 = 4 \times 0.25 \times 0.5)$ | $0, ~ (0.5 = 4 \times 0.25 \times 0.5)$ | $0.25$ |
| 逛街 | $1, ~ (1 = 4 \times 0.5 \times 0.5)$ | $1, ~ (1 = 4 \times 0.5 \times 0.5)$ | $0.5$ |
| 学习 | $0, ~ (0.5 = 4 \times 0.25 \times 0.5)$ | $1, ~ (0.5 = 4 \times 0.25 \times 0.5)$ | $0.25$ |
| 边际概率 | $0.5$ | $0.5$ | $1$ |
$$ \begin{align*} \quad \chi^2 = \sum_{ij} \frac{(o_{ij}-e_{ij})^2}{e_{ij}} = 4 \times \frac{(1 - 0.5)^2}{0.5} = 2 \end{align*} $$
import numpy as np from sklearn.feature_selection import SelectKBest, chi2 X = np.array([ # 已去掉方差为零的特征 [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1.], [6., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0.], [10., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0.], [13., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.], ]) y = [1, 1, 0, 0] sk = SelectKBest(chi2) sk.fit_transform(X, y) print(sk.scores_) # [8.53333333 1. 1. 0. 0.33333333 1. # 1. 0.33333333 1. 1. 0. 0. # 0. ]
独热编码将约会方式分成三个特征,卡方检验值为$1 + 1 + 0 = 2$
熵 (entropy) 可以度量随机变量的不确定性
$$ \begin{align*} \quad H(X) = - \sum_{i \in [m]} p(x_i) \log p(x_i) = - \Ebb [\log p(X)], \quad 0 \log 0 \triangleq 0 \end{align*} $$
设离散随机变量$X \in \{a,b,c,d\}$且
$$ \begin{align*} \quad p(a) = \frac{1}{2}, ~ p(b) = \frac{1}{4}, ~ p(c) = \frac{1}{8}, ~ p(d) = \frac{1}{8} \end{align*} $$
根据定义$H(X) = \frac{1}{2} \log 2 + \frac{1}{4} \log 4 + \frac{1}{8} \log 8 + \frac{1}{8} \log 8 = \frac{7}{4}$
霍夫曼编码:设最优前缀码为$a:0$、$b:10$、$c:110$、$d:111$
期望编码长度为$\frac{1}{2} \cdot 1 + \frac{1}{4} \cdot 2 + \frac{1}{8} \cdot 3 + \frac{1}{8} \cdot 3 = \frac{7}{4}$
霍夫曼编码是一种熵编码
熵 (entropy) 可以度量随机变量的不确定性
$$ \begin{align*} \quad H(X) = - \sum_{i \in [m]} p(x_i) \log p(x_i) = - \Ebb [\log p(X)], \quad 0 \log 0 \triangleq 0 \end{align*} $$
当$p(x_1) = \cdots = p(x_m) = 1/m$时,熵达到最大值$\log m$
拉格朗日函数$L = - \sum_{i \in [m]} p(x_i) \log p(x_i) - \alpha (\sum_{i \in [m]} p(x_i) - 1)$
$$ \begin{align*} \quad \nabla_{p(x_i)} L = - \log p(x_i) - 1 - \alpha = 0 ~ \Longrightarrow ~ p(x_i) = \exp(-1-\alpha) = \frac{1}{m} \end{align*} $$
当某个$p(x_i) = 1$、其余为零时,熵达到最小值$0$
$$ \begin{align*} \quad H(X) = \sum_{i \in [m]} p(x_i) \log \frac{1}{p(x_i)} \ge \sum_{i \in [m]} p(x_i) \log 1 = 0 \end{align*} $$
联合熵:两个随机变量的联合不确定性
$$ \begin{align*} \quad H(X,Y) = - \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log p(x_i,y_j) = - \Ebb [\log p(X,Y)] \end{align*} $$
条件熵:给定一个随机变量,另一个随机变量还具有的不确定性
$$ \begin{align*} \quad H(X|Y) & = H(X,Y) - H(Y) \\ & = - \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log p(x_i,y_j) + \sum_{j \in [n]} \class{blue}{p(y_j)} \log p(y_j) \\ & = - \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log p(x_i,y_j) + \sum_{j \in [n]} \class{blue}{\sum_{i \in [m]} p(x_i,y_j)} \log p(y_j) \\ & = - \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log p(x_i|y_j) \\ & = - \Ebb [\log p(X|Y)] \end{align*} $$
互信息:给定一个随机变量,另一个随机变量不确定性的缩减量
$$ \begin{align*} \quad I(X; Y) & = H(X) - H(X|Y) \\ & = - \sum_{i \in [m]} \class{blue}{p(x_i)} \log p(x_i) + \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log p(x_i|y_j) \\ & = - \sum_{i \in [m]} \class{blue}{\sum_{j \in [n]} p(x_i,y_j)} \log p(x_i) + \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log \frac{p(x_i,y_j)}{p(y_j)} \\ & = - \sum_{i \in [m]} \sum_{j \in [n]} p(x_i,y_j) \log \frac{p(x_i)p(y_j)}{p(x_i,y_j)} \\ & = \Ebb \left[ \log \frac{p(X,Y)}{p(X)p(Y)} \right] \end{align*} $$
由对称性可知$I(X; Y) = H(Y) - H(Y|X)$
互信息 (交集) 与熵、联合熵 (并集)、条件熵 (差集) 的关系为
$$ \begin{align*} \quad I(X;Y) & = H(X) - H(X|Y) = H(Y) - H(Y|X) \\ & = H(X) + H(Y) - H(X,Y) \\ & = H(X,Y) - H(X|Y) - H(Y|X) \end{align*} $$
利用每个特征和类别标记之间的互信息进行挑选
import numpy as np from sklearn.feature_selection import SelectKBest, mutual_info_classif np.random.seed(0) X = np.array([ # 已去掉方差为零的特征 [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1.], [6., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0.], [10., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0.], [13., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.], ]) y = [1, 1, 0, 0] sk = SelectKBest(mutual_info_classif) sk.fit_transform(X, y) print(sk.scores_) # [0.58333333 0.20833333 0.08333333 0. 0.08333333 0. # 0. 0. 0.20833333 0. 0. 0. # 0. ]
$$ \begin{align*} \quad \rho_{xy} = \frac{\cov(x,y)}{\sigma_x \sigma_y} = \frac{\sum_{i \in [m]} (x_i - \xbar)(y_i - \ybar)}{\sqrt{\sum_{i \in [m]} (x_i - \xbar)^2} \sqrt{\sum_{i \in [m]} (y_i - \ybar)^2}} \end{align*} $$
import numpy as np X = np.array([ # 已去掉方差为零的特征 [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1., 1.], [6., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0., 1.], [10., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0., 0.], [13., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1., 0.], ]) corr = np.corrcoef(X, rowvar=False) print(corr[-1, :]) # [-0.88888889 0.57735027 -0.57735027 0. 0.57735027 -0.57735027 # -0.57735027 0.57735027 -0.57735027 0.57735027 0. 0. # 0. 1. ]
范数$\|\cdot\|$:长度概念的推广,对任意标量$\alpha$和向量空间中的$\uv, \vv$
机器学习中常用的是向量的$\ell_p$范数:$\| \wv \|_p \triangleq (\sum_{i \in [d]} |w_i|^p)^{1/p}$
当$0 \le p < 1$时,$\| \cdot \|_p$不再是合法的范数,不满足三角不等式
$\Rbb^2$上的 5 个$\ell_p$范数球$\{ \wv \mid \| \wv \|_p \le t \}$
$\ell_1$唯一既凸且稀疏,将其范数球作为$\Rbb^2$上最小二乘的可行域
$$ \begin{align*} \quad \min_{w_1, w_2} ~ \left \| \begin{bmatrix} 6.590 & -0.654 \\ 1.498 & 0.413 \\ -2.550 & 1.682 \\ -5.538 & -1.441 \\ \end{bmatrix} \begin{bmatrix} w_1 \\ w_2 \\ \end{bmatrix} - \begin{bmatrix} 1 \\ 1 \\ 0 \\ 0 \\ \end{bmatrix} \right\|^2, \quad \st ~ |w_1| + |w_2| \le t \end{align*} $$
椭圆与正方形必然交于正方形的顶点处,即最优的$w_2 = 0$
构造$\Rbb^D$中的标准正交基$\wv_1, \ldots, \wv_d$,将样本投到该$d$维子空间
$$ \begin{align*} \quad \Xv \in \Rbb^{m \times D} \xrightarrow[\text{降维}]{\Wv = [\wv_1, \ldots, \wv_d] \in \Rbb^{D \times d}} \Xv \Wv \in \Rbb^{m \times d} \xrightarrow[\text{重构}]{\Wv^\top \in \Rbb^{d \times D}} \Xv \Wv \Wv^\top \end{align*} $$
投影到$d ~ (<D)$维子空间存在信息损失,$\Wv$应使得重构误差小
$$ \begin{align*} \quad \| \Xv & - \Xv \Wv \Wv^\top \|_F^2 = \tr [(\Xv - \Xv \Wv \Wv^\top) (\Xv - \Xv \Wv \Wv^\top)^\top] \\ & = \tr [\Xv \Xv^\top - 2 \Xv \Wv \Wv^\top \Xv^\top + \Xv \Wv \class{blue}{\Wv^\top \Wv} \Wv^\top \Xv^\top] \\ & = \tr [\Xv \Xv^\top - \Xv \Wv \Wv^\top \Xv^\top] \qquad \longleftarrow ~ \Wv^\top \Wv = \Iv \\ & = \const - \tr [\Wv^\top \Xv^\top \Xv \Wv] \qquad \longleftarrow ~ \tr [\Av \Bv] = \tr [\Bv \Av] \\ & = \const - \wv_1^\top \Xv^\top \Xv \wv_1 - \cdots - \wv_d^\top \Xv^\top \Xv \wv_d \\[5pt] & \Longrightarrow \quad \mathop{\mathrm{argmin}}_{\Wv^\top \Wv = \Iv} \| \Xv - \Xv \Wv \Wv^\top \|_F^2 = \mathop{\mathrm{argmax}}_{\Wv^\top \Wv = \Iv} \sum_{i \in [d]} \wv_i^\top \Xv^\top \Xv \wv_i \end{align*} $$
$$ \begin{align*} \quad \mathop{\mathrm{argmin}}_{\Wv^\top \Wv = \Iv} \| \Xv & - \Xv \Wv \Wv^\top \|_F^2 = \mathop{\mathrm{argmax}}_{\Wv^\top \Wv = \Iv} \sum_{i \in [d]} \wv_i^\top \Xv^\top \Xv \wv_i \end{align*} $$
假设已平移样本使其中心在原点,即$\onev^\top \Xv = \zerov$
$\Xv \wv_1$是样本在投影方向$\wv_1$上的投影,投影均值$\onev^\top \Xv \wv_1 = 0$
$$ \begin{align*} \quad \wv_1^\top \Xv^\top \Xv \wv_1 = \sum_{i \in [m]} (\xv_i^\top \wv_1)^2 = \sum_{i \in [m]} (\xv_i^\top \wv_1 - 0)^2 = \var [\xv_i^\top \wv_1] \end{align*} $$
最小化重构误差等价最大化投影方差,即投影后样本尽可能散开
拉格朗日函数$L = \wv_1^\top \Xv^\top \Xv \wv_1 - \alpha (\wv_1^\top \wv_1 - 1)$
$$ \begin{align*} \quad \nabla_{\wv_1} L = 2 \Xv^\top \Xv \wv_1 - 2 \alpha \wv_1 = \zerov \Longrightarrow \mathtip{\wv_1^\top \Xv^\top \Xv \wv_1 = \alpha}{\wv_1应为\Xv^\top \Xv最大特征值对应的特征向量} \end{align*} $$
主成分分析 (PCA):寻找一组投影方向 (成分) 使重构误差最小
主成分分析 (PCA):寻找一组投影方向 (成分) 使重构误差最小
import numpy as np from sklearn.decomposition import PCA X = np.array([ [1., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 1.], [6., 0., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1., 0.], [10., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 1., 0.], [13., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.], ]) pca = PCA(n_components=3) XX = pca.fit_transform(X) print(XX) # [[ 6.59008618 -0.65420003 -0.62672674] # [ 1.49765996 0.41345689 1.35501589] # [-2.55003899 1.68197454 -0.64673241] # [-5.53770716 -1.4412314 -0.08155674]] print(np.linalg.norm(X - pca.inverse_transform(XX))) # 3.1659611182970852e-15 pca = PCA(n_components=2) XX = pca.fit_transform(X) print(XX) # [[ 6.59008618 -0.65420003] # [ 1.49765996 0.41345689] # [-2.55003899 1.68197454] # [-5.53770716 -1.4412314 ]] print(np.linalg.norm(X - pca.inverse_transform(XX))) # 1.6290392142641008
Johnson–Lindenstrauss (JL) 定理:给定$\epsilon \in (0,1)$和正整数$m$,设整数$d$满足$d \ge 4 (\epsilon^2/2 - \epsilon^3/3)^{-1} \ln m$,则对$\Rbb^D$中的任意$m$个点组成的集合$\Scal$,存在可在随机多项式时间内得到的线性映射$f: \Rbb^D \mapsto \Rbb^d$使得对$\forall \uv, \vv \in \Scal$有
$$ \begin{align*} \quad (1 - \epsilon) \| \uv -\vv \|^2 \le \| f(\uv) - f(\vv) \|^2 \le (1 + \epsilon) \| \uv - \vv \|^2 \end{align*} $$
高维空间中的点集可线性映射到低维空间且相对保持距离
投影矩阵通常采用
import numpy as np from scipy.spatial import distance from sklearn import random_projection np.random.seed(0) X = np.random.rand(100, 10000) D1 = distance.cdist(X, X, 'euclidean') # 原样本的成对距离矩阵 transformer = random_projection.GaussianRandomProjection() # 高斯随机矩阵 XX = transformer.fit_transform(X) print(XX.shape) # (100, 3947) D2 = distance.cdist(XX, XX, 'euclidean') # 投影后样本的成对距离矩阵 print(np.linalg.norm(D1 - D2, ord='fro')) # 两个成对距离矩阵差的F范数 # 45.5042470391125 transformer = random_projection.SparseRandomProjection() # 稀疏随机矩阵 XX = transformer.fit_transform(X) print(XX.shape) # (100, 3947) D2 = distance.cdist(XX, XX, 'euclidean') # 投影后样本的成对距离矩阵 print(np.linalg.norm(D1 - D2, ord='fro')) # 两个成对距离矩阵差的F范数 # 45.20040904607192
模型学习前的最后一步,亦有将该步与模型学习融合的做法
当部分特征冗余甚至有害时,挑选或生成有用的特征子集
当特征稀缺时,利用现有特征构造新的特征
凭经验显式构造映射$\phi$,如二次多项式特征:
$$ \begin{align*} \quad [x_1; x_2] \xrightarrow{\phi: ~ \Rbb^2 \mapsto \Rbb^6} [x_1^2; x_2^2; \sqrt{2} x_1 x_2; \sqrt{2} x_1; \sqrt{2} x_2; 1] \end{align*} $$
$$ \begin{align*} \quad x_1^2 + x_2^2 \le t ~ \longrightarrow ~ z_1 + z_2 \le t \end{align*} $$
显式构造映射$\phi$过于依赖使用者的姿势水平,若后续模型学习
对映射$\phi([x_1;x_2]) = [x_1^2; x_2^2; \sqrt{2} x_1 x_2; \sqrt{2} x_1; \sqrt{2} x_2; 1]$和样本$\xv,\zv$有
$$ \begin{align*} \quad \phi(\xv)^\top \phi(\zv) & = x_1^2 z_1^2 + x_2^2 z_2^2 + 2 x_1 x_2 z_1 z_2 + 2 x_1 z_1 + 2 x_2 z_2 + 1 \\ & = (x_1 z_1 + x_2 z_2 + 1)^2 \\ & = (\xv^\top \zv + 1)^2 \\ & = \kappa (\xv, \zv) \end{align*} $$
构造新特征有两套方案:
核函数$\kappa(\cdot, \cdot)$是双变量对称函数,常见的有:
将 PCA 中的样本$\xv$用$\phi(\xv)$替代即核 PCA,先升维再降维
$\quad \max_{\|\wv\|_2^2 = 1} \wv^\top \Xv^\top \Xv \wv \overset{\phi}{\longrightarrow} \max_{\|\wv\|_2^2 = 1} \wv^\top \phi(\Xv)^\top \phi(\Xv) \wv$
其中$\Xv = \begin{bmatrix} \xv_1^\top \\ \vdots \\ \xv_m^\top \end{bmatrix}$、$\phi(\Xv) = \begin{bmatrix} \phi(\xv_1)^\top \\ \vdots \\ \phi(\xv_m)^\top \end{bmatrix}$,注意$\wv$的维度不一样
问题:如何让模型中只出现内积$\phi(\xv_i)^\top \phi(\xv_j)$的形式?
对$\wv$做正交分解$\wv = \sum_{i \in [m]} \alpha_i \phi(\xv_i) + \vv = \phi(\Xv)^\top \alphav + \vv$,其中
$$ \begin{align*} \quad \vv \perp \span \{ \phi(\xv_1), \ldots, \phi(\xv_m) \} ~ \Longrightarrow ~ \phi(\Xv) \vv = \zerov \end{align*} $$
于是
$$ \begin{align*} \quad & \|\wv\|_2^2 = \alphav^\top \phi(\Xv) \phi(\Xv)^\top \alphav + \vv^\top \vv = \alphav^\top \Kv \alphav + \vv^\top \vv \\ & \phi(\Xv) \wv = \phi(\Xv) (\phi(\Xv)^\top \alphav + \vv) = \phi(\Xv) \phi(\Xv)^\top \alphav = \Kv \alpha \\ & \Kv = \phi(\Xv) \phi(\Xv)^\top = \begin{bmatrix} \phi(\xv_1)^\top \phi(\xv_1) & \cdots & \phi(\xv_1)^\top \phi(\xv_m) \\ \vdots & \ddots & \vdots \\ \phi(\xv_m)^\top \phi(\xv_1) & \cdots & \phi(\xv_m)^\top \phi(\xv_m) \end{bmatrix} \end{align*} $$
核 PCA 可重写为 $\max_{\alphav, \vv} ~ \alphav^\top \Kv \Kv \alphav, ~ \st ~ \alphav^\top \Kv \alphav + \vv^\top \vv = 1$
核 PCA:$\max_{\alphav, \vv} ~ \alphav^\top \Kv \Kv \alphav, ~ \st ~ \alphav^\top \Kv \alphav + \vv^\top \vv = 1$
设最优解为$(\alphav_\star, ~ \vv_\star)$,下面说明$\vv_\star = \zerov$
核 PCA 的最终形式为 $\max_\alphav ~ \alphav^\top \Kv \Kv \alphav, ~ \st ~ \alphav^\top \Kv \alphav = 1$
通过拉格朗日乘子法求得$\alphav$后,样本$\xv_j$在成分$\wv$上的投影为
$$ \begin{align*} \quad \wv^\top \phi(\xv_j) = \sum_{i \in [m]} \alpha_i \phi(\xv_i)^\top \phi(\xv_j) = \sum_{i \in [m]} \alpha_i \kappa (\xv_i, \xv_j) \end{align*} $$
通过核 PCA 可以看出,全程我们都用不到$\phi(\cdot)$,只需要$\kappa(\cdot, \cdot)$
设$\sigma_1, \ldots, \sigma_l$是一系列简单的非线性函数,如$\sigma(x) = \max \{ x, 0 \}$
一个简单的$l$层神经网络:
$$ \begin{align*} \qquad \hv_1 & = \sigma_1(\Wv_1 \xv + \bv_1) \\ \hv_2 & = \sigma_2(\Wv_2 \hv_1 + \bv_2) \\ & \vdots \\ \hv_{l-1} & = \sigma_{l-1}(\Wv_{l-1} \hv_{l-2} + \bv_{l-1}) \\ f(\xv) & = \sigma_l (\Wv_l \hv_{l-1} + \bv_l) \end{align*} $$
前$l-1$层函数复合可视为特征变换,最后一层为模型学习