数据是基于林轩田老师的《机器学习基石》,如果实在找不到,也可以通过链接进行下载:CSDN下载地址。
1. 线性可分数据
1.1 读取数据
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
data = pd.read_csv(r'E:/data/perceptron_15.dat', sep = '\s', header = None)
data.columns = ['x1', 'x2', 'x3', 'x4', 'y']
X_train = data.loc[:, ['x1', 'x2', 'x3', 'x4']]
y_train = data.loc[:, 'y']
X_train = X_train.values
y_train = y_train.values
1.2 感知机实现
其中为了加快运算速度,把b融入到了W中,所以对训练数据X也要做一定的处理(左边插入一列为1的数据)。
class PerceptronSeparable():
def __init__(self):
self.w = None
self.b = None
self.W = None
self.eta = 0.01
def sign(self, x):
if x >= 0:
return 1
else:
return -1
#检查单个数据是否预测正确
def check_one(self, x_train, y_train):
x_train_one = 1
x_train_extend = np.append(x_train_one, x_train)
y_predict = np.dot(x_train_extend, self.W)
y_predict = self.sign(y_predict)
return y_predict == y_train
#检查所有数据是否预测正确
def check_all(self, X_train, y_train):
X_train_ones = np.ones([len(X_train) ,1])
X_train_extend = np.concatenate([X_train_ones, X_train], axis = 1)
y_predict = np.dot(X_train_extend, self.W)
y_predict = np.array(list(map(self.sign, y_predict)))
return (y_predict == y_train).all()
def fit(self, X_train, y_train):
self.w = np.zeros([X_train.shape[1], 1])
self.b = 0
self.W = np.append(self.b, self.w)
times = 0
while True:
# 如果全部预测正确则退出
if self.check_all(X_train, y_train):
break
else:
random_index = np.random.randint(0, len(X_train))
x_train_single = X_train[random_index, :].reshape(-1, 1)
y_train_single = y_train[random_index]
if not self.check_one(x_train_single, y_train_single):
self.w = self.w + self.eta * x_train_single * y_train_single
self.b = self.b + self.eta * y_train_single
self.W = np.append(self.b, self.w)
times += 1
def predict(self, X_test):
X_test_ones = np.ones([len(X_test), 1])
X_test_new = np.concatenate([X_test_ones, X_test], axis=1)
y_test_predict = np.dot(X_test_new, self.W)
y_test_predict = np.array(list(map(self.sign, y_test_predict)))
return y_test_predict
1.3 效果评估
perceptron = PerceptronSeparable()
perceptron.fit(X_train, y_train)
print(accuracy_score(y_train, perceptron.predict(X_train)))
由于是线性可分数据,打印结果应该是1.0,否则说明代码是有bug。
2. 线性不可分数据
2.1 读取数据
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
data = pd.read_csv(r'E:/data/perceptron_18.dat', sep = '\s', header = None)
data.columns = ['x1', 'x2', 'x3', 'x4', 'y']
X_train = data.loc[:, ['x1', 'x2', 'x3', 'x4']]
y_train = data.loc[:, 'y']
X_train = X_train.values
y_train = y_train.values
2.2 感知机实现
实现是大同小异的。最大的区别在于,每次改变参数以后会和之前最优的结果进行比较,如果不如以前的结果,则模型回退到上一个版本。
class PerceptronNonSeparable():
def __init__(self):
self.w = None
self.b = None
self.W = None
self.eta = 0.01
def sign(self, x):
if x >= 0:
return 1
else:
return -1
def check_one(self, x_train, y_train):
x_train_one = 1
x_train_extend = np.append(x_train_one, x_train)
y_predict = np.dot(x_train_extend, self.W)
y_predict = self.sign(y_predict)
return y_predict == y_train
def check_all(self, X_train, y_train):
X_train_ones = np.ones([len(X_train) ,1])
X_train_extend = np.concatenate([X_train_ones, X_train], axis = 1)
y_predict = np.dot(X_train_extend, self.W)
y_predict = np.array(list(map(self.sign, y_predict)))
return (y_predict == y_train).all()
def get_predict_right_nums(self, X_train, y_train):
X_train_ones = np.ones([len(X_train) ,1])
X_train_extend = np.concatenate([X_train_ones, X_train], axis = 1)
y_predict = np.dot(X_train_extend, self.W)
y_predict = np.array(list(map(self.sign, y_predict)))
return np.sum(y_predict == y_train)
def fit(self, X_train, y_train):
self.w = np.zeros([X_train.shape[1], 1])
self.b = 0
self.W = np.append(self.b, self.w)
times = 0
predict_best_num = 0
for i in range(1000):
if self.check_all(X_train, y_train):
break
else:
random_index = np.random.randint(0, len(X_train))
x_train_single = X_train[random_index, :].reshape(-1, 1)
y_train_single = y_train[random_index]
if not self.check_one(x_train_single, y_train_single):
bak_w, bak_b, bak_W = self.w, self.b, self.W
self.w = self.w + self.eta * x_train_single * y_train_single
self.b = self.b + self.eta * y_train_single
self.W = np.append(self.b, self.w)
predict_right_num = self.get_predict_right_nums(X_train, y_train)
if predict_right_num < predict_best_num:
self.w, self.b, self.W = bak_w, bak_b, bak_W
def predict(self, X_test):
X_test_ones = np.ones([len(X_test), 1])
X_test_new = np.concatenate([X_test_ones, X_test], axis=1)
y_test_predict = np.dot(X_test_new, self.W)
y_test_predict = np.array(list(map(self.sign, y_test_predict)))
return y_test_predict
2.3 效果评估
perceptron = PerceptronNonSeparable()
perceptron.fit(X_train, y_train)
print(accuracy_score(y_train, perceptron.predict(X_train)))
由于是线性不可分数据,打印结果应该小于1.0,但也应该大于0.7,否则说明代码是有bug。