Kaggle digit-recognizer PCA+SVM


https://www.kaggle.com/c/digit-recognizer


参考https://www.kaggle.com/cyberzhg/digit-recognizer/sklearn-pca-svm/code

什么是PCA

  • 主分析方法(PCA),是运用线性代数的知识,找到一个k维空间(k小于n, n为原来 样本的维度)让原来的样本投影到该空间后能保留最大的差异程度,具体表现为方差。

  • 举个一个简单的例子就是,全班同学的成绩语文相差很大,从50到90分布,但是英语成绩大家都考到90多分,如果两个成绩都用同样的比重区分排名,那么英语的作用就不这么明显,而且需要考虑两科成绩。
    这时如果我新建一个新变量,对两科取不同权重,这样计算出来的新维度即能保留原来的特征,又能达到降维的效果。
    这只是帮助理解,具体实现应该有出入。

  • 具体是先把样本写成矩阵形式,求出协方差矩阵(自己跟自己的转置相乘再除于样本数)。协方差有个特殊的性质就是,对角线上的元素代表元素的方差,其他位置的元素代表协方差,就是不同元素的相关程度。

  • 这时我们需要构造一个向量,令到协方差矩阵只留下对角线上的元素,其他位置的为0,其物理含义就是使原本元素投影到新空间后,每个维度之间的相关最小,而差异最大。这时再对对角线上的元素排序,选出最大的方差就达到降维的效果。至于怎么实现矩阵对角化,就是数学的知识了。

  • 具体可以参考http://www.360doc.com/content/13/1124/02/9482_331688889.shtml

什么是SVM

  • 支持向量机器(SVM),就是找到一个最佳超平面,把各类样本分开,具体数学思想目前没搞懂。只知道个大概或者说只能理解而二维的情况,汗。

我们来做题吧

  • 手写数字识别引用的是MNIST的样本库,train.csv是一个42000*785的数据集,有42000个样本,第一列是label,后面784是灰度值。 train.csv是测试集,28000个样本。

  • 第一次参考别人的随机树算法,采取n=200的参数,获得了0.9668的效果。

  • 想想可以用PCA先降维,那么问题来了,降到多少维了?一般是 (留下的方差总和) / (总方差和) = 85% 到 95%的区间,不说了,直接上测试代码。PCA函数内的n_components当填小数时是留下方差的百分比,不填就是全部保留,mle是自动。

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import pandas as pd

pca = PCA(whiten=True)
digit = pd.read_csv('train.csv')
train = digit.values[1:, :].astype(int)
pca.fit(train)
exr = pca.explained_variance_ratio_

x = []
y = []
line85 = []
line98 = []
for i in range(len(exr)) :
    x.append(i)
    line85.append(0.85)
    line98.append(0.98)
    if i == 0: 
        y.append(exr[0])
    else:
        y.append(exr[i]+y[i-1])

plt.plot(x, y)
plt.plot(x, line85)
plt.plot(x, line98)
plt.show()
  • 实验图片,通过pca降维器的属性可以查看留下几个维度,具体用法百度吧。可见98%大概是154个左右。

Kaggle digit-recognizer PCA+SVM_第1张图片

  • 然后后面是实验代码
# -*- coding: utf-8 -*-
from sklearn.decomposition import PCA
from sklearn.svm import SVC
import pandas as pd
import numpy as np

pca = PCA(n_components=0.95, whiten=True)
digit = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
label = digit.values[:, 0].astype(int)
train = digit.values[:, 1:].astype(int)
test_data = test.values[:, :].astype(int)

pca.fit(train)
train_data = pca.transform(train)

svc = SVC()
svc.fit(train_data, label)

test_data = pca.transform(test_data)
ans = svc.predict(test_data)

a = []
for i in range(len(ans)):
    a.append(i+1)

np.savetxt('PCA_0.95_SVC.csv', np.c_[a, ans], 
    delimiter=',', header='ImageId,Label', comments='', fmt='%d')
  • 调参数总共调了三次:
    1. 第一次用0.95,结果是0.9737。
    2. 第二次用0.85,结果是0.9815。
    3. 第三次直接试保留10个维度,结果是0.9341,比之前低了许多。

Summary

保留主要的特征维度,能提高分类器的鲁棒性,但是选取维度过少,会丢失了一些特征信息。参考别人的用了35的维度,取得的效果会好一点点。但是过度调参数感觉没什么意思。懂个大概思路就好,这次实验自己看了sklearn参考文档的PCA内容,虽然有些看不懂,但是也是一种锻炼吧。

Keep Fighting!

你可能感兴趣的:(Kaggle)