欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【实战】支持向量机SVM基础实战篇(二)

程序员文章站 2024-03-16 10:32:40
...

【实战】支持向量机SVM基础实战篇(二)

这几篇SVM介绍是从0到1慢慢学会支持向量机,将是满满的干货,都是我亲自写的,没有搬运,可以随我一起从头了解SVM,并在短期内能使用SVM做到想要的分类或者预测~我也将附上自己基础训练的完整代码,可以直接跑,建议同我一样初学者们,自己从头到尾打一遍,找找手感,代码不能光看看,实践出真知!

回顾一下,上篇,我们建立和比较了线性分类器和非线性分类器,比较了多元线性核函数和线性核函数,解决了类型数量不平衡问题,话不多说,原理篇和实战基础一 请参见上几篇博客,我们循序渐进慢慢贴近真实情景!解决生活问题
原理篇请戳这里

实践基础篇一请戳这里


提取数据置信度

获取对位置数据分类的置信水平,在现实问题中非常有用,当一个心得数据点被分类为某一个一直类别时,我们可以训练SVM来计算输出类型的置信度。

先上图:

【实战】支持向量机SVM基础实战篇(二)

在我们用上一篇的方法做好训练分类器后:我们找几个点,如上图,黑色部分几个点是在我们认定的“正例”,其他的为负例,我们观察一下置信度(通俗的说也就是分类为正例还是负例的概率):

上代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import _validation

def load_data(input_file):
    X = []
    y = []
    with open(input_file, 'r') as f:
        for line in f.readlines():
            data = [float(x) for x in line.split(',')]
            X.append(data[:-1])
            y.append(data[-1]) 

    X = np.array(X)
    y = np.array(y)

    return X, y

def plot_classifier(classifier, X, y, title='Classifier boundaries', annotate=False):
    x_min, x_max = min(X[:, 0]) - 1.0, max(X[:, 0]) + 1.0
    y_min, y_max = min(X[:, 1]) - 1.0, max(X[:, 1]) + 1.0

    step_size = 0.01

    x_values, y_values = np.meshgrid(np.arange(x_min, x_max, step_size), np.arange(y_min, y_max, step_size))

    mesh_output = classifier.predict(np.c_[x_values.ravel(), y_values.ravel()])

    mesh_output = mesh_output.reshape(x_values.shape)

    plt.figure()

    plt.title(title)

    plt.pcolormesh(x_values, y_values, mesh_output, cmap=plt.cm.gray)

    plt.scatter(X[:, 0], X[:, 1], c=y, s=80, edgecolors='black', linewidth=1, cmap=plt.cm.Paired)

    plt.xlim(x_values.min(), x_values.max())
    plt.ylim(y_values.min(), y_values.max())

    plt.xticks(())
    plt.yticks(())

    if annotate:
        for x, y in zip(X[:, 0], X[:, 1]):
            plt.annotate(
                '(' + str(round(x, 1)) + ',' + str(round(y, 1)) + ')',
                xy=(x, y), xytext=(-15, 15),
                textcoords='offset points',
                horizontalalignment='right',
                verticalalignment='bottom',
                bbox=dict(boxstyle='round,pad=0.6', fc='white', alpha=0.8),
                arrowprops=dict(arrowstyle='-', connectionstyle='arc3,rad=0'))

def print_accuracy_report(classifier, X, y, num_validations=5):
    accuracy = _validation.cross_val_score(classifier,
            X, y, scoring='accuracy', cv=num_validations)
    print("Accuracy: " + str(round(100*accuracy.mean(), 2)) + "%")

    f1 = _validation.cross_val_score(classifier,
            X, y, scoring='f1_weighted', cv=num_validations)
    print("F1: " + str(round(100*f1.mean(), 2)) + "%")

    precision = _validation.cross_val_score(classifier,
            X, y, scoring='precision_weighted', cv=num_validations)
    print("Precision: " + str(round(100*precision.mean(), 2)) + "%")

    recall = _validation.cross_val_score(classifier,
            X, y, scoring='recall_weighted', cv=num_validations)
    print("Recall: " + str(round(100*recall.mean(), 2)) + "%")


介绍一下核心部分代码:

load_file(input_file) # 输入数据点,转成np.array 函数
plot_classifier(classifier, X, y, title='Classifier boundaries', annotate=False): # 数据可视化函数
classifier.decision_function([i])[0] # 这是测量数据点到边界的距离  方法
classifier.predict_proba([i])[0] # 测量置信度   方法

看一下到边界的距离和置信度:
【实战】支持向量机SVM基础实战篇(二)

可以看到:上面几行是该点到黑圈边界的距离,为正说明在黑圈边界以外,为负说明在内。例如:
[4.8 5.2] --> -1.9202588134880436

[7.6 2. ] --> 2.0058455177573045

可以根据我们最上面的图明白该点越离边界远,值越大,同样的,越在黑圈中间,越小(绝对值越大)

我们看置信度:

[2. 1.5] --> [0.01421961 0.98578039]

说明该点为正例(在圈内)的概率为:0.01421961 同样的为负例的概率:0.98578039


寻找最优超参数

使用交叉验证网格搜索的方法(原理过段时间集中介绍)

parameter_grid = [{'kernel': ['linear'], 'C': [1, 10, 50, 600]},
                    {'kernel': ['poly'], 'degree': [2, 3]},
                    {'kernel': ['rbf'], 'gamma': [0.01, 0.001], 'C': [1, 10, 50, 600]},
                 ]

我们要验证这几个参数的组合搭配的效果
上代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.model_selection import GridSearchCV

def load_file(input_file):
    x = []
    y = []
    with open(input_file, "r") as f:
        for line in f.readlines():
            data = [float(x) for x in line.split(',')]
            x.append(data[:-1])
            y.append(data[-1])
    X = np.array(x)
    y = np.array(y)

    return X, y
input_file = 'data_multivar.txt'
X, y =load_file(input_file)

###############################################
# Train test split

X_train, X_test, y_train, y_test =train_test_split(X, y, test_size=0.25, random_state=5)

# Set the parameters by cross-validation
parameter_grid = [{'kernel': ['linear'], 'C': [1, 10, 50, 600]},
                    {'kernel': ['poly'], 'degree': [2, 3]},
                    {'kernel': ['rbf'], 'gamma': [0.01, 0.001], 'C': [1, 10, 50, 600]},
                 ]

metrics = ['precision', 'recall_weighted']

for metric in metrics:
    print("\n#### Searching optimal hyperparameters for", metric)

    classifier = GridSearchCV(svm.SVC(C=1),
            parameter_grid, cv=5, scoring=metric)
    classifier.fit(X_train, y_train)

    print("\nScores across the parameter grid:")
    for means, params in zip(classifier.cv_results_['mean_test_score'],  classifier.cv_results_['params']):
        print(params, '-->', means)

    print("\nHighest scoring parameter set:", classifier.best_params_)

    y_true, y_pred = y_test, classifier.predict(X_test)
    print("\nFull performance report:\n")
    print(classification_report(y_true, y_pred))


介绍一下重点部分代码:

metrics = ['precision', 'recall_weighted'] # 定义好需要测量的指标 precision 和recall(甚至可以设置accuracy和F1_score)

classifier = GridSearchCV(svm.SVC(C=1), # 网格搜索
            parameter_grid, cv=5, scoring=metric)
    classifier.fit(X_train, y_train)

看结果:

【实战】支持向量机SVM基础实战篇(二)

各种参数搭配的Precison 由结果可知,最高的组合是 {‘C’: 10, ‘gamma’: 0.01, ‘kernel’: ‘rbf’}

同样的看一下recall(召回率)

【实战】支持向量机SVM基础实战篇(二)

同样的这一组参数的召回率最高{‘C’: 600, ‘gamma’: 0.01, ‘kernel’: ‘rbf’}

在理想中,我们总是希望precison和recall越高越好,但是真实情况中,往往两者有着负相关,precision越高,往往recall越低,以后慢慢介绍这几种!


建立一个预测某时刻是否某地点有活动展开预测器

这是一个低维度预测器,只反映原理,并不代表实际情况,预测的准确率有待优化

下面我们准备一组数据:
【实战】支持向量机SVM基础实战篇(二)

准备了五千条数据可以看出:在 7 月 26号Tuesday 的20:00这一时刻,一栋大楼内进入的人数为2人

出大楼的人数为0人次,真实情况是:NOEVENT(也就是没有活动)根据这样的方法,记录了5000条数据,用于训练SVM的分类器,目的是给出某一时刻的数据,用于预测是否可能有聚会等活动发生(可供白嫖党吃吃喝喝-_-技术员始终不会饿着,哈哈)

上代码:

from sklearn import preprocessing
import numpy as np
from sklearn.svm import SVC
from sklearn.model_selection import KFold, cross_val_score

input_file = 'building_event_multiclass.txt'

X = []
count = 0
with open(input_file, 'r') as f:
    for line in f.readlines():
        data = line[:-1].split(',')
        X.append([data[0]] + data[2:])

X = np.array(X)

label_encoder = []
X_encoded = np.empty(X.shape)
for i, item in enumerate(X[0]):
    if item.isdigit():
        X_encoded[:, i] = X[:, i]
    else:
        label_encoder.append(preprocessing.LabelEncoder())
        X_encoded[:, i] = label_encoder[-1].fit_transform(X[:, i])

X = X_encoded[:, :-1].astype(int)
y = X_encoded[:, -1].astype(int)

params = {'kernel': 'rbf', 'probability': True, 'class_weight': 'balanced', 'C':100}
classifier = SVC(**params)
classifier.fit(X, y)

accuracy = cross_val_score(classifier,
        X, y, scoring='accuracy', cv=3)
print("Accuracy of the classifier: " + str(round(100*accuracy.mean(), 2)) + "%")

input_data = ['Tuesday', '12:30:00','21','23']

input_data_encoded = [-1] * len(input_data)
count = 0
for i, item in enumerate(input_data):	
    if item.isdigit():
        input_data_encoded[i] = int(input_data[i])
    else:
        input_data_encoded[i] = int(label_encoder[count].transform([input_data[i]]))
        count = count + 1 

input_data_encoded = np.array(input_data_encoded)

input_data_encoded = input_data_encoded.reshape(1, len(input_data))
output_class = classifier.predict(input_data_encoded)
print("Output class:", label_encoder[-1].inverse_transform(output_class)[0])


代码逻辑也很简单,同上一样,训练数据,建立预测分类器,最后检验,用一批数据喂给分类器,就能得出预测结果

【实战】支持向量机SVM基础实战篇(二)

预测结果是有活动的在 ‘Tuesday’, ‘12:30:00’,‘21’,‘23’

这样的情况下我们再换个比较难以分辨的数据:

【实战】支持向量机SVM基础实战篇(二)

接下来,再少一些出入大楼的人,这一天的这个时刻就预测为没有活动发生了。

这些都是简单的代码,并且没有逻辑可言,就稍微介绍一下这里吧:

for i, item in enumerate(input_data):	
    if item.isdigit():
        input_data_encoded[i] = int(input_data[i])
    else:
        input_data_encoded[i] = int(label_encoder[count].transform([input_data[i]]))
        count = count + 1 

input_data_encoded = np.array(input_data_encoded)

input_data_encoded = input_data_encoded.reshape(1, len(input_data))
output_class = classifier.predict(input_data_encoded)
print("Output class:", label_encoder[-1].inverse_transform(output_class)[0])

这里我发现我的参考资料是错误的,我把它修改,并且在资料官网:Python Machine Learning CookBook留言了

首先在input_data中迭代,判断输入数据是否为纯数字(isdigit())方法,如果不是,那么就使用
transform方法做标准化处理,这边的标准化处理以及transform与fit_transform的区别,我们慢慢介绍。

然后使用reshape转换成数组形式,符合预测的形状(维度匹配),最后predict预测。

同样的我们修改一下数据:
这次明确了有一些活动:eventA,eventB,eventC

【实战】支持向量机SVM基础实战篇(二)

我们同样的预测一下(方法不变)

【实战】支持向量机SVM基础实战篇(二)

ok!跟真实结果一致。

通过上述两个方法,可以先预测出某时刻这栋大楼是否有事件,然后再预测是哪个事件,数据越多,预测越准确,防止过拟合是一种好的优化方案,我们以后再说,又到了文末,下期继续实践!感受一下魅力!现在还只是使用传统机器学习,做着与真实情况差别较大的理论基础,我们把地基打好,就开始实战!请求关注,我们下期再见~

最后附上上述代码用到的数据集:
网盘:
链接:https://pan.baidu.com/s/1w8MJVkRsQkx8hy977RY27A
提取码:68pw
感谢关注!
上海第二工业大学智能科学与技术大二 周小夏(CV调包侠)