PCA不进行分类的动作,而只做做数据预处理,将样本变换到一个容易分类(向最大化方差的方向,principal component axes,投影)的更低维的新的特征空间中。Kernel PCA比PCA多了一步,也即先升维(RBF包括多项式核均是升高到无穷维)再进行投影的动作,因为有些非线性可分的数据集只有在升维的视角下才线性可分。
PCA
- 均值化的数据:
∑ixi=0
<code class="hljs python has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># python </span> <span class="hljs-prompt" style="color: rgb(0, 102, 102); box-sizing: border-box;">>>> </span>X-np.mean(X, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 一个二维矩阵减去一维向量?对,</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 这里用到的技术是numpy中broadcasting(广播机制)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
-
样本协方差矩阵(sample-covariance matrix C )
C=1N∑ixixTi=1NXXT
其中, X 的每一列表示一个样本(特征向量) -
特征分解
C=UΛUT=∑αλαuαuTα -
projection or transform
the projected data are de-correlated in this new axis.
- 重构
yi=UTkxi⇓Ukyi=UkUTkxi=xi
<code class="hljs python has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> pandas <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> pd <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np df = pd.read_csv(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'</span>, header=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>) X, y = df.values[:, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>:], df.values[:, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># step 1</span> X -= X.mean(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">## step 2</span> N = X.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] C = X.T.dot(X)/N <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">## step 3</span> Lambda, Q = np.linalg.eig(C) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">## step 4</span> k = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> eigen_pairs = [(Lambda[i], Q[:, i]) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(len(Lambda))] eigen_pairs = sorted(eigen_pairs, reverse=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>, key=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">lambda</span> k: k[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]) W = np.column_stack((eigen_pairs[i][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(k=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>))) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">## step 5</span> X_pca = X.dot(W)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>
Kernel PCA
以 Radial Basis Function(RBF) kernel PCA(不同的核,体现在代码上仅仅是一处细微的差别)为例进行说明:
- 计算核矩阵(相似度矩阵) K
这是最为常见的RBF(Rational Basis Function)核函数,也有多项式核:
和 sigmoid型(hyperbolic tangent)核:
其矩阵形式也即:
- center the K
其中 1n 是 n×n 的元素值全为 1n 矩阵。
- 对 K′ 进行特征值分解,获得对应于前 k 个特征值的特征向量。与标准PCA算法不同的是,这里获得特征向量不再是 principal component axes,而已经是全部样本在这些轴上的投影了,也即是我们所需的进行降维后的数据了。
这里为了验证核机制的性能,我们在如下的数据集上进行测试:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">from sklearn<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.datasets</span> import make_moons <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">X</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span> = make_moons(n_samples=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>, random_state=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">123</span>) plt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.scatter</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">X</span>[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">X</span>[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], colors=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'r'</span>, marker=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'^'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>) plt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.scatter</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">X</span>[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">X</span>[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], colors=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'b'</span>, marker=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'o'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
<code class="hljs python has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> scipy.spatial.distance <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> pdist, squareform <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">rbf_kpca</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(X, gamma, k)</span>:</span> sq_dist = pdist(X, metric=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'sqeuclidean'</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># N = X.shape[0] </span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># sq_dist.shape = N*(N-1)/2</span> mat_sq_dist = squareform(sq_dist) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># mat_sq_dist.shape = (N, N)</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># step 1</span> K = np.exp(-gamma*mat_sq_dist) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># step 2</span> N = X.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] one_N = np.ones((N, N))/N K = K - one_N.dot(K) - K.dot(one_N) + one_N.dot(K).dot(one_N) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># step 3</span> Lambda, Q = np.linalg.eig(K) eigen_pairs = [(Lambda[i], Q[:, i]) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(len(Lambda))] eigen_pairs = sorted(eigen_pairs, reverse=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>, key=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">lambda</span> k: k[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> np.column_stack((eigen_pairs[i][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(k)))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
调用:
<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">X_kpca </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> rbf_kpca(X, gamma=15, k=2)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
一个非线性可分的数据集
<code class="hljs mel has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">from sklearn.datasets import make_circles X, y = make_circles(n_samples=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">noise</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.1</span>, factor=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.2</span>, random_state=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">123</span>) plt.scatter(X[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], X[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'r'</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">marker</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'^'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>) plt.scatter(X[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], X[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'b'</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">marker</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'o'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>) plt.show()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
在这样的一个非线性可分的数据集,显然如何找到最大方差的方向都不可能使最后的数据集线性可分。接下来,我们探讨KPCA的核机制是如何工作的,使线性不可分的数据集变得线性可分,
应用kernel trick:
<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">X_kpca </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> rbf_kpca(X, gamma=15, k=2)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
可视化:
<code class="hljs rsl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">fig, ax = plt.subplots(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, figsize=(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>)) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].scatter(X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'r'</span>, marker=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'^'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].scatter(X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'b'</span>, marker=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'o'</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.4</span>) label_count = np.bincount(y) <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># 统计各类别出现的次数</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># label_count[0] = 500</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># label_count[1] = 500</span> ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].scatter(X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], np.zeros(label_count[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'r'</span>) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].scatter(X_kpca[y==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], np.zeros(label_count[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">color</span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'b'</span>) <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># y轴置零</span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># 投影到x轴</span> ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].set_ylim([-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].set_xlabel(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'PC1'</span>) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].set_ylabel(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'PC2'</span>) ax[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>].set_xlabel(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'PC1'</span>) plt.show()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
PCA 与 KPCA 的另一点重要不同
不同在于对新数据、新样本(当然还是同一类型数据,比如测试样本之于训练样本)的转换方式不同;
标准PCA算法,转换矩阵(transformation matrix
Wd×k
)对应于训练样本的协方差矩阵的特征向量,使用
W
可继续作用于新的数据集,
x′1×d⋅Wd×k
。而KPCA,
K
的特征向量(
Ka=λα
中的
α
)即为变换后的样本。
对于新的样本,我们想要计算:
而特征向量
v=∑ia(i)ϕ(x(i))
,则:
<code class="hljs python has-numbering" style="color: inherit; display: block; padding: 0px; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background-image: initial; background-attachment: initial; background-color: transparent; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> scipy.spatial.distance <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> sqdist, squareform <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">rbf_kpca</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(X, gamma, k)</span>:</span> sq_dists = sqdist(X, metric=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'sqeuclidean'</span>) mat_sq_dists = squareform(sq_dists) K = np.exp(-gamma*mat_sq_dists) N = X.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] one_N = np.ones((N, N))/N K = K-one_N.dot(K)-K.dot(one_N)+one_N.dot(K).dot(one_N) Lambda, Q = np.linalg.eigh(K) alphas = np.column_stack((Q[:, -i]<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>+k))) lambdas = [Lambda[-i] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, k+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> alphas, lambdas <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">proj_new</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(X_new, X, gamma, alphas, lambdas)</span>:</span> k = np.exp(-gamma*np.sum((X-X_new)**<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> k.dot(alphas/lambdas) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># alphas/lambdas,归一化后的alphas</span> X, y = make_moons(n_samples=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>, random_state=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">123</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 设置random_state,为了可重复性</span> alphas, lambdas = rbf_kpca(X, gamma=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>, k=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) X_new = X[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">25</span>] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 以当前样本的某一样本作为新的样本进行测试</span> X_proj = proj_new(X_new, X, gamma=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>, alphas, lambdas) print(alphas[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">25</span>]) print(X_proj) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># [-0.07877284]</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># [-0.07877284]</span></code><code class="hljs python has-numbering" style="color: inherit; display: block; padding: 0px; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background-image: initial; background-attachment: initial; background-color: transparent; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> </span></code><code class="hljs python has-numbering" style="color: inherit; display: block; padding: 0px; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background-image: initial; background-attachment: initial; background-color: transparent; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"> </span></code><code class="hljs python has-numbering" style="display: block; padding: 0px; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background-image: initial; background-attachment: initial; background-color: transparent; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="color:#880000;">本文转自:<a target=_blank href="http://http://blog.csdn.net/lanchunhui/article/details/50492482">http://blog.csdn.net/lanchunhui/article/details/50492482</a></span></code><ul class="pre-numbering" style="color: rgb(51, 51, 51); box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul><div class="save_code tracking-ad" data-mod="popu_249" style="color: rgb(255, 255, 255); box-sizing: border-box; position: absolute; height: 60px; right: 30px; top: 5px; cursor: pointer; z-index: 2;"><a target=_blank style="color: rgb(202, 0, 0); box-sizing: border-box;"><img src="http://static.blog.csdn.net/images/save_snippets.png" style="border: none; box-sizing: border-box; max-width: 100%;" alt="" /></a></div><ul class="pre-numbering" style="color: rgb(51, 51, 51); box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>