Nonlinear Component Analysis as a Kernel Eigenvalue Problem

Scholkopf B, Smola A J, Muller K, et al. Nonlinear component analysis as a kernel eigenvalue problem[J]. Neural Computation, 1998, 10(5): 1299-1319.

普通的PCA将下式进行特征分解(用论文的话讲就是对角化):
C = \frac{1}{M} \sum \limits_{j=1}^M x_j x_j^T
其中x_j \in \mathbb{R}^{N}, j = 1, \ldots, M,且\sum \limits_{j=1}^M x_j = 0(中心化)。

而kernel PCA试图通过一个非线性函数:
\Phi:\mathbb{R}^N \rightarrow F, x \rightarrow X
其中F是一个高维空间(甚至是无限维)。
所以我们要解决这么一个问题:
\bar{C} = \frac{1}{M} \sum_{j=1}^M \Phi (x_j) \Phi(x_j)^T

其实我们面对的第一个问题不是维度的问题而是\Phi的选择或者说构造。我们为什么要把数据映射到高维的空间?因为当前数据的结构(或者说分布)并不理想。

比如满足(x-1)^2+(y-1)^2=4的点,我们可以扩充到高维空间(x^2, x, y, y^2),在高维空间是线性的(虽然这个例子用在kernel SVM 比较好)。

因为\Phi(\cdot)的构造蛮麻烦的,即便有一些先验知识。我们来看一种比较简单的泛用的映射:
(x_1, x_2, x_3) \rightarrow (x_1^3, x_2^3, x_3^3, x_1^2x_2,x_1^2x_3,x_1x_2^2,x_1x_3^2,x_2^2x_3,x_2x_3^2,x_1x_2x_3)
这种样子的映射,很容易把维度扩充到很大很大,这个时候求解特征问题会变得很麻烦。

kernel PCA

假设\sum \limits_{i=1}^M \Phi(x_i)=0(如何保证这个性质的成立在最后讲,注意即便\sum \limits_{i=1}^M x_i = 0\sum \limits_{i=1}^M \Phi(x_i)=0也不一定成立)。

假设我们找到了\bar{C}的特征向量V \ne 0:
\bar{C}V = \lambda V
因为V\Phi(x_i),i=1,\ldots, M的线性组合(这个容易证明),所以,V可以由下式表示:
V = \sum \limits_{i=1}^M \alpha_i \Phi(x_i)

所以:
\lambda V^T \Phi(x_j) = V^T\bar{C} \Phi(x_j), \quad for \: all \: j=1,\ldots, M
等价于(记\Phi = [\Phi(x_1), \ldots, \Phi(x_M)]):
\begin{array}{ll} \lambda \sum \limits_{i=1}^M \alpha_i (\Phi^T(x_i)\Phi(x_j)) &= \lambda \{ \Phi^T \Phi(x_j)\} ^T \alpha \\ & =\frac{1}{M} \sum \limits_{i=1}^M \alpha_i \Phi^T(x_i) \Phi \Phi^T \Phi(x_j) \\ & = \frac{1}{M} \{\Phi^T \Phi \Phi^T \Phi(x_j)\}^T \alpha \end{array}
对于j=1,\ldots, M均成立,其中\alpha = [\alpha_1, \ldots, \alpha_M]^T

等价于:
M \lambda \Phi^T \Phi \alpha = \Phi^T \Phi \Phi^T \Phi \alpha
K = \Phi^T \Phi,那么可写作:
M \lambda K \alpha = K^2\alpha
其中K_{ij} = \Phi^T(x_i) \Phi(x_j)

所以,我们可以通过下式来求解\alpha:
M\lambda \alpha = K \alpha
\alphaK的特征向量(注意,当\alpha为特征向量的时候是一定符合M \lambda K \alpha = K^2\alpha的,反之也是的,即二者是等价的)。

假设\lambda_1 \ge \lambda_2 \ge \ldots \ge \lambda_M对应\alpha^1, \ldots, \alpha^M,那么相应的V也算是求出来了。

需要注意的是,\|\alpha\|往往不为1,因为我们希望\|V\|=1,所以:
V^TV = \alpha^T K \alpha = \lambda \|\alpha\|^2 = 1
所以\|\alpha\| = \frac{1}{\sqrt{\lambda}}

PCA当然需要求主成分,假设有一个新的样本x,我们需要求:
\Phi(x)^TV = \Phi^T(x) \Phi \alpha = \sum \limits_{i=1}^M \alpha_i \Phi^T(x_i) \Phi(x)

注意,我们只需要计算\Phi^T(x_i) \Phi(x)

现在回到kernel PCA 上的关键kernel上。注意到,无论是K,还是最后计算主成分,我们都只需要计算\Phi^T(x)\Phi(y)就可以了,所以如果我们能够找到一个函数k(x,y)来替代就不必显示将x映射到\Phi(x)了,这就能够避免了\Phi(\cdot)的选择问题和计算问题。

kernel 的选择

显然,PCA的\lambda \ge 0,所以我们也必须保证K为半正定矩阵,相应的核函数k称为正定核,Mercer定理有相应的构建。

也有现成的正定核:

多项式核

k(x, y) = (x^Ty + 1)^d
论文中是(x^Ty)^d

高斯核函数

k(x, y) = \exp \{\ -\frac{\|x-y\|^2}{2\sigma^2}\}

性质

在这里插入图片描述

论文用上面的一个例子来说明,kernel PCA可能更准确地抓住数据的结构。

kernel PCA具有普通PCA的性质,良好的逼近(从方差角度),以及拥有最多的互信息等等。并且,如果k(x, y) = k(x^Hy),那么kernel PCA还具有酉不变性。

因为普通的PCA处理的是一个N \times N的协方差矩阵,所以,至多获得N个载荷向量,而kernel PCA至多获得M个载荷向量(特征值非零)。所以,kernel PCA有望比普通PCA更加精准。

一些问题

中心化

PCA处理的是协方差矩阵,正如我们最开始所假设的,\sum \limits_{i=1}^{M} \Phi(x_i)=0,即中心化。因为\Phi(\cdot)并不是线性函数,所以,即便\sum \limits_{i=1}^M x_i = 0也不能保证\sum \limits_{i=1}^{M} \Phi(x_i)=0,不过有别的方法处理。

\tilde{\Phi}(x_i) = \Phi(x_i) - \frac{1}{M}\sum \limits_{k=1}^M \Phi(x_k) \\ \tilde{K}_{ij} = \tilde{\Phi}^T(x_i) \Phi(x_j) \\ 1_{M} = \{1\}_{ij}^{M \times M}
可以得到:
\begin{array}{ll} \tilde{K}_{ij} &= \tilde{\Phi}^T(x_i) \Phi(x_j) \\ &= \big(\Phi(x_i) - \frac{1}{M}\sum \limits_{k=1}^M \Phi(x_k)\big)^T \big(\Phi(x_j) - \frac{1}{M}\sum \limits_{k=1}^M \Phi(x_k)\big) \\ &= K_{ij} - \frac{1}{M} \sum \limits_{k=1}^M K_{kj} - \frac{1}{M} \sum \limits_{k=1}^M K_{ik} + \frac{1}{M^2} \sum \limits \limits_{m,n=1}^M K_{mn} \\ &= (K - 1_MK - K1_M + 1_MK1_M)_{ij} \end{array}
于是,我们通过K可以构造出\tilde{K}。只需再求解\tilde{K}\tilde{\alpha} = M \lambda \tilde{\alpha}即可。

恢复

我们知道,根据PCA选出的载荷向量以及主成分,我们能够恢复出原数据(或者近似,如果我们只选取了部分载荷向量)。对于kernel PCA,比较困难,因为我们并没有显式构造\Phi(\cdot),也就没法显式找到V,更何况,有时候我们高维空间找到V在原空间中并不存在原像。
或许, 我们可以通过:
\min \limits_{x} \quad \|\Phi(x) - \Phi(\hat{x})\|^2
来求解,注意到,上式也只和核函数k(x,y)有关。

代码


import numpy as np

class KernelPCA:

    def __init__(self, data, kernel=1, pra=3):
        self.__n, self.__d = data.shape
        self.__data = np.array(data, dtype=float)
        self.kernel = self.kernels(kernel, pra)
        self.__K = self.center()

    @property
    def shape(self):
        return self.__n, self.__d

    @property
    def data(self):
        return self.data

    @property
    def K(self):
        return self.__K

    @property
    def alpha(self):
        return self.__alpha

    @property
    def eigenvalue(self):
        return self.__value

    def kernels(self, label, pra):
        """
        数据是一维的时候可能有Bug
        :param label: 1:多项式;2:exp
        :param pra:1: d; 2: sigma
        :return: 函数 或报错
        """
        if label is 1:
            return lambda x, y: (x @ y) ** pra
        elif label is 2:
            return lambda x, y: \
                np.exp(-(x-y) @ (x-y) / (2 * pra ** 2))
        else:
            raise TypeError("No such kernel...")

    def center(self):
        """中心化"""
        oldK = np.zeros((self.__n, self.__n), dtype=float)
        one_n = np.ones((self.__n, self.__n), dtype=float)
        for i in range(self.__n):
            for j in range(i, self.__n):
                x = self.__data[i]
                y = self.__data[j]
                oldK[i, j] = oldK[j, i] = self.kernel(x, y)
        return oldK - 2 * one_n @ oldK + one_n @ oldK @ one_n

    def processing(self):
        """实际上就是K的特征分解,再对alpha的大小进行一下调整"""
        value, alpha = np.linalg.eig(self.__K)
        index = value > 0
        value = value[index]
        alpha = alpha[:, index] * (1 / np.sqrt(value))
        self.__alpha = alpha
        self.__value = value / self.__n

    def score(self, x):
        """来了一个新的样本,我们进行得分"""
        k = np.zeros(self.__n)
        for i in range(self.__n):
            y = self.__data[i]
            k[i] = self.kernel(x, y)
        return k @ self.__alpha





"""

import matplotlib.pyplot as plt

x = np.linspace(-1, 1, 100)
y = x ** 2 + [np.random.randn() * 0.1 for i in range(100)]
data = np.array([x, y]).T

test = KernelPCA(data, pra=1)
test.processing()
print(test.alpha.shape)
print(test.alpha[:, 0])

"""

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355