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

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

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

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

实践基础篇一请戳这里


提取数据置信度

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

先上图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZOQvV5V-1588126856991)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\1588080169972.png)]

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

上代码:

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] # 测量置信度   方法

看一下到边界的距离和置信度:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bmewSVqF-1588126856993)(D:\CSDN\pic\svm实战二\1588080710476.png)

可以看到:上面几行是该点到黑圈边界的距离,为正说明在黑圈边界以外,为负说明在内。例如:
[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)

看结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4xiz2l5-1588126856995)(D:\CSDN\pic\svm实战二\1588082282792.png)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93bGmlkE-1588126857000)(D:\CSDN\pic\svm实战二\1588082638576.png)]

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

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


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

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

下面我们准备一组数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vaxcC3m-1588126857002)(D:\CSDN\pic\svm实战二\1588123559007.png)]

准备了五千条数据可以看出:在 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])


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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7a3YBkxK-1588126857006)(D:\CSDN\pic\svm实战二\1588124509459.png)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rf4j2E4i-1588126857008)(D:\CSDN\pic\svm实战二\1588124767278.png)]

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSLP2pDL-1588126857012)(D:\CSDN\pic\svm实战二\1588126152158.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXQp3pOa-1588126857015)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\1588126410631.png)]

ok!跟真实结果一致。

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

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

原创文章 9 获赞 105 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_46098574/article/details/105834370
今日推荐