呉恩達マシン学習練習:SVMサポートベクトルマシン


1 Support Vector Macines
1.1 Example Dataset 1

%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from scipy.io import loadmat
from sklearn import svm
ほとんどのSVMのライブラリは自動的に追加の特徴X_;を追加します。θ_;ですので、手動で追加する必要はありません。

mat = loadmat('./data/ex6data1.mat')
print(mat.keys())
# dict_keys(['__header__', '__version__', '__globals__', 'X', 'y'])
X = mat['X']
y = mat['y']

def plotData(X, y):
    plt.figure(figsize=(8,5))
    plt.scatter(X[:,0], X[:,1], c=y.flatten(), cmap='rainbow')
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.legend() 
plotData(X, y)
output_5_1.png

def plotBoundary(clf, X):
    '''plot decision bondary'''
    x_min, x_max = X[:,0].min()*1.2, X[:,0].max()*1.1
    y_min, y_max = X[:,1].min()*1.1,X[:,1].max()*1.1
    xx, yy = np.meshgrid(np.linspace(x_min, x_max, 500),
                         np.linspace(y_min, y_max, 500))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.contour(xx, yy, Z)

models = [svm.SVC(C, kernel='linear') for C in [1, 100]]
clfs = [model.fit(X, y.ravel()) for model in models]

title = ['SVM Decision Boundary with C = {} (Example Dataset 1'.format(C) for C in [1, 100]]
for model,title in zip(clfs,title):
    plt.figure(figsize=(8,5))
    plotData(X, y)
    plotBoundary(model, X)
    plt.title(title)
output_9_2.png
output_9_4.png
上の図から見れば、Cが比較的小さい時にモデルの誤植分類に対する罰則が増大し、比較的厳格で、誤植分類が少なく、間隔が狭い。
Cが大きいとモデルの誤分類に対する罰則が大きくなり、比較的ゆとりがあり、一定の誤分類が存在することができ、間隔が大きい。
1.2 SVM with Gaussian Kernels
この部分はSVMを用いて非線形分類を行った。ガウス核関数を使用します。
SVMを用いて非線形決定境界を見出すためには,まずGauss核関数を実現しなければならない。Gauss核関数を類似度関数として想像できます。サンプルの距離を測るために用いられます。ʲ ⁾,y_;̾̾⁾)
image.png
ここではslearnが持参したsvmの核関数を使えばいいです。
1.2.1 Gaussian Kernel

def gaussKernel(x1, x2, sigma):
    return np.exp(- ((x1 - x2) ** 2).sum() / (2 * sigma ** 2))
gaussKernel(np.array([1, 2, 1]),np.array([0, 4, -1]), 2.)  # 0.32465246735834974
1.2.2 Example Dataset 2

mat = loadmat('./data/ex6data2.mat')
X2 = mat['X']
y2 = mat['y']

plotData(X2, y2)
output_16_1.png

sigma = 0.1
gamma = np.power(sigma,-2.)/2
clf = svm.SVC(C=1, kernel='rbf', gamma=gamma)
modle = clf.fit(X2, y2.flatten())
plotData(X2, y2)
plotBoundary(modle, X2)
output_17_1.png
1.2.3 Example Dataset 3

mat3 = loadmat('data/ex6data3.mat')
X3, y3 = mat3['X'], mat3['y']
Xval, yval = mat3['Xval'], mat3['yval']
plotData(X3, y3)
output_19_1.png

Cvalues = (0.01, 0.03, 0.1, 0.3, 1., 3., 10., 30.)
sigmavalues = Cvalues
best_pair, best_score = (0, 0), 0
for C in Cvalues:
    for sigma in sigmavalues:
        gamma = np.power(sigma,-2.)/2
        model = svm.SVC(C=C,kernel='rbf',gamma=gamma)
        model.fit(X3, y3.flatten())
        this_score = model.score(Xval, yval)
        if this_score > best_score:
            best_score = this_score
            best_pair = (C, sigma)
print('best_pair={}, best_score={}'.format(best_pair, best_score))
# best_pair=(1.0, 0.1), best_score=0.965

model = svm.SVC(C=1., kernel='rbf', gamma = np.power(.1, -2.)/2)
model.fit(X3, y3.flatten())
plotData(X3, y3)
plotBoundary(model, X3)
output_21_1.png

#           ,     ,       。
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
# we create 40 separable points
np.random.seed(0)
X = np.array([[3,3],[4,3],[1,1]])
Y = np.array([1,1,-1])
# fit the model
clf = svm.SVC(kernel='linear')
clf.fit(X, Y)
# get the separating hyperplane
w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]
# plot the parallels to the separating hyperplane that pass through the
# support vectors
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])
# plot the line, the points, and the nearest vectors to the plane
plt.figure(figsize=(8,5))
plt.plot(xx, yy, 'k-')
plt.plot(xx, yy_down, 'k--')
plt.plot(xx, yy_up, 'k--')
#       
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
            s=150, facecolors='none', edgecolors='k', linewidths=1.5)
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.rainbow)
plt.axis('tight')
plt.show()
print(clf.decision_function(X))
output_22_0.png

[ 1. 1.5 -1. ]
2 Spam Class ification
2.1 Processing Emals
この部分はSVMでスパム分類器を作成する。各emailをn次元の特徴ベクトルに変える必要があります。この分類器は、指定されたメールxが迷惑メール(y=1)か迷惑メールでないかを判断します。
take a look at examples from the dataset

with open('data/emailSample1.txt', 'r') as f:
    email = f.read()
    print(email)

> Anyone knows how much it costs to host a web portal ?
>
Well, it depends on how many visitors you're expecting.
This can be anywhere from less than 10 bucks a month to a couple of $100. 
You should checkout http://www.rackspace.com/ or perhaps Amazon EC2 
if youre running something big..
To unsubscribe yourself from this mailing list, send an email to:
[email protected]
メールの内容にはa URL、an email address、numbers、and dollar amountsが含まれていますが、メールごとに具体的な内容が異なる場合があります。したがって、メールを処理する際によく使われる方法は、これらのデータを標準化し、すべてのURLを同じとし、すべての数字を同じと見なすことです。
例えば、すべてのURLを唯一の文字列「httpaddr」で置き換えて、メールにはURLが含まれています。具体的なURLの内容は要求されません。これは通常、スパム分類器の性能を向上させる。スパム送信者は通常、URLをランダム化するので、新しいスパムの中で特定のURLを再度見る確率は非常に小さい。
私たちは次のように処理できます。

  1. Lower-casing:           。
  2. Stripping HTML:     HTML  ,     。
  3. Normalizing URLs:     URL       “httpaddr”.
  4. Normalizing Email Addresses:          “emailaddr”
  5. Normalizing Dollars:   dollar  ($)   “dollar”.
  6. Normalizing Numbers:        “number”
  7. Word Stemming(    ):           。  ,“discount”, “discounts”, “discounted” and “discounting”    “discount”。
  8. Removal of non-words:          ,     (tabs, newlines, spaces)       .

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from sklearn import svm
import re #regular expression for e-mail processing
#              (Porter stemmer)
from stemming.porter2 import stem
#                     ,        
import nltk, nltk.stem.porter

def processEmail(email):
    """   Word Stemming Removal of non-words     """
    email = email.lower()
    email = re.sub('<[^<>]>', ' ', email)  #   <  ,      < ,>    ,  >  ,     <...>
    email = re.sub('(http|https)://[^\s]*', 'httpaddr', email )  #   //           ,         
    email = re.sub('[^\s]+@[^\s]+', 'emailaddr', email)
    email = re.sub('[\$]+', 'dollar', email)
    email = re.sub('[\d]+', 'number', email) 
    return email
次は語幹の抽出と非文字の除去です。

def email2TokenList(email):
    """     ,           """
    # I'll use the NLTK stemmer because it more accurately duplicates the
    # performance of the OCTAVE implementation in the assignment
    stemmer = nltk.stem.porter.PorterStemmer()
    email = preProcess(email)
    #           ,re.split()          
    tokens = re.split('[ \@\$\/\#\.\-\:\&\*\+\=\[\]\?\!\(\)\{\}\,\'\"\>\_\<\;\%]', email)
    #            
    tokenlist = []
    for token in tokens:
        #             
        token = re.sub('[^a-zA-Z0-9]', '', token);
        # Use the Porter stemmer to     
        stemmed = stemmer.stem(token)
        #       ‘',        
        if not len(token): continue
        tokenlist.append(stemmed)
    return tokenlist  
2.1.1 Vocabulary List(語彙表)
メールを前処理した後、処理した単語のリストがあります。次のステップは私たちが分類器でどの単語を使いたいかを選択します。私たちはどの単語を削除する必要がありますか?
私たちは一つの語彙表vocab.txtを持っています。中には実際によく使われる単語が1899個保存されています。
処理後のメールにどれぐらいのvocab.txtの単語が含まれているかを計算して、vocab.txtのindexに戻ります。これは私達が欲しい単語の索引です。

def email2VocabIndices(email, vocab):
    """         """
    token = email2TokenList(email)
    index = [i for i in range(len(vocab)) if vocab[i] in token ]
    return index
2.2 Extracting Feature from Emals

def email2FeatureVector(email):
    """
     email      ,n vocab   。             1,   0
    """
    df = pd.read_table('data/vocab.txt',names=['words'])
    vocab = df.as_matrix()  # return array
    vector = np.zeros(len(vocab))  # init vector
    vocab_indices = email2VocabIndices(email, vocab)  #          
    #          1
    for i in vocab_indices:
        vector[i] = 1
    return vector

vector = email2FeatureVector(email)
print('length of vector = {}
num of non-zero = {}'.format(len(vector), int(vector.sum())))

length of vector = 1899
num of non-zero = 45
2.3 Training SVM for Spam Class ification
抽出された特徴ベクトルと対応するラベルを読みだします。トレーニングセットとテストセットを分けます。

# Training set
mat1 = loadmat('data/spamTrain.mat')
X, y = mat1['X'], mat1['y']
# Test set
mat2 = scipy.io.loadmat('data/spamTest.mat')
Xtest, ytest = mat2['Xtest'], mat2['ytest']

clf = svm.SVC(C=0.1, kernel='linear')
clf.fit(X, y)
2.4 Top Predictors for Spam

predTrain = clf.score(X, y)
predTest = clf.score(Xtest, ytest)
predTrain, predTest

(0.99825, 0.989)
以上で、マシン学習SVMサポートベクトルマシンの練習記事について紹介します。より多くの関連マシン学習内容は以前の文章を検索してください。または次の関連記事を引き続き閲覧してください。これからもよろしくお願いします。