基于matlab的fisher线性判别及感知器判别_[PRML]线性分类模型感知机原理及复现
线性分类相关文章:1、Fisher线性判别分析(LDA)[1]2、广义模型与线性模型& 判别分析 [2]3、逻辑回归[3]4、线性分类模型简介1 原理线性判别的另一个例子是感知机,在模式识别的历史中具有重要地位。其对应两类模型,输入变量首先用固定的非线性转换成特征向量,然后用于构建一个广义线性模型:式其中非线性激活函数由阶梯函数(step function)给出:式向量通常包括...
线性分类相关文章: 1、Fisher线性判别分析(LDA)[1] 2、广义模型与线性模型& 判别分析 [2] 3、逻辑回归[3] 4、 线性分类模型简介
1 原理
线性判别的另一个例子是感知机,在模式识别的历史中具有重要地位。其对应两类模型,输入变量首先用固定的非线性转换成特征向量,然后用于构建一个广义线性模型:
式其中非线性激活函数由阶梯函数(step function)给出:
式向量通常包括偏置成分。关于两类分类问题的目标编码,在概率模型中是合适的。而对于感知器来说,对于类使用目标值,对于类使用目标值更方便,符合激活函数的选择。
用来确定感知器参数的算法最容易被误差函数最小化所激发。错误函数的一个自然选择是错误分类模式的总数。然而,这并不能产生一个简单的学习算法,因为误差是的分段常数函数,当的变化导致决策边界跨越一个数据点时,就会出现不连续。利用误差函数的梯度来改变的方法不能应用,因为梯度几乎处处为零。
因此,考虑一个替代的误差函数称为感知器准则
(perceptron criterion)。为了推导这个,我们注意到我们正在寻找一个权值向量,这样在类中的模式将具有,而类的模式具有。采用目标编码方案,我们希望所有的编码模式都能满足。 感知器标准将零误差与任何被正确分类的模式相关联,而对于一个被错误分类的模式,它试图最小化量 。因此感知器准则为:
其中表示所有错分模式的集合。与特定的错误分类模式相关的误差的贡献是在错误分类模式的空间区域的线性函数,在正确分类模式的区域为零。因此,总误差函数是分段线性的。
现在对这个误差函数应用随机梯度下降算法。则权向量的变化量为:
其中,为学习率参数,而为整数,用于索引算法的步骤。因为感知器函数不变,如果用乘以一个常数,我们可以设置学习率参数等于1而不失一般性。随着权重向量在训练过程中的演变,分类错误的模式集合将会改变。
感知器学习算法有一个简单的解释。我们依次循环训练模式,对于每一个模式,计算感知器函数式52。如果模式是正确分类,权向量不变,而如果是错分类,则对于类别,添加矢量到当前估计的权向量上,对于类别减去向量。感知器学习算法如图7所示。
如果我们在感知器学习算法中考虑一次更新的影响,我们看到错分类模式对误差的贡献将会减少,因为根据式55有:
设置,并利用。当然,这并不意味着其他分类错误的模式对误差函数的贡献会减少。此外,权值向量的变化可能会导致一些先前正确分类的模式变成错误分类。因此感知器学习规则不能保证在每一阶段降低总误差函数。
但感知器收敛定理
(perceptron convergence theorem)指出,如果存在一个精确解(换句话说,如果训练数据集是线性可分的),那么感知器学习算法保证在有限的步骤中找到一个精确解。但是请注意,实现收敛所需要的步骤仍然是大量的,并且在实践中,直到实现收敛,我们将无法区分一个不可分离的问题和一个简单的收敛缓慢的问题。
即使当数据集是线性可分的,也可能有许多解决方案,而找到哪一个将取决于参数的初始化和数据点的呈现顺序。此外,对于不能线性可分的数据集,感知器学习算法将永远不会收敛。
除了学习算法的困难,感知器不提供概率输出,也不容易推广到类。但最重要的限制来自于这样一个事实,它是基于固定基函数的线性组合。
2 python复现
感知器算法感知器的灵感来自于被称为神经元的单个神经细胞的信息处理。
神经元通过树突接收输入信号,树突将电信号传递到细胞体。
以类似的方式,感知器从训练数据的例子中接收输入信号,我们将其加权并组合成一个称为激活的线性方程。
下面对感知机算法进行复现。
from random import seedfrom random import randrangefrom csv import reader# 1、make a prediction with weights# weights' the first number is biasdef predict(row, weights):"""
参考公式:
1.activation = sum(weight_i * x_i) + bias (式52)
2.prediction = 1.0 if activation >= 0.0 else 0.0 (式53)
"""
activation = weights[0]for i in range(len(row) - 1):
activation += weights[i + 1] * row[i]return 1.0 if activation >= 0.0 else 0.0# 2、estimate perceptron weights using stochastic gradient descentdef train_weights(train, l_rate, n_epoch):"""
参考公式:关键在于导数的计算
注意这里的误差采用的是平方误差和而不是感知机准则式54
1.w(t+1)= w(t) + learning_rate * (expected(t) - predicted(t)) * x(t)
2.bias(t+1) = bias(t) + learning_rate * (expected(t) - predicted(t))
"""
weights = [0.0 for i in range(len(train[0]))]for epoch in range(n_epoch):
sum_error = 0.0for row in train:
prediction = predict(row, weights)
error = row[-1] - prediction
sum_error += error ** 2
weights[0] = weights[0] + l_rate * errorfor i in range(len(row) - 1):
weights[i + 1] += weights[i + 1] + l_rate * error * row[i]
print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error))return weights# 3、perceptron algrithm on the sonar dataset# 3.1、load a csv filedef load_csv(filename):
dataset = []with open(filename, 'r') as file:
csv_reader = reader(file)for row in csv_reader:if not row:continue
dataset.append(row)return dataset# 3.2、convert string column to floatdef str_column_to_float(dataset, column):for row in dataset:
row[column] = float(row[column].strip())# 3.3、convert string column to integerdef str_column_to_integer(dataset, column):
class_values = [row[column] for row in dataset]
unique = set(class_values)
lookup = {}for i, value in enumerate(unique):
lookup[value] = ifor row in dataset:
row[column] = lookup[row[column]]return lookup# 3.4、split a dataset into k foldsdef cross_validation_split(dataset, n_folds):
dataset_split = []
dataset_copy = list(dataset)
fold_size = int(len(dataset) / n_folds)for i in range(n_folds):
fold = []while len(fold) index = randrange(len(dataset_copy))
fold.append(dataset_copy.pop(index))
dataset_split.append(fold)return dataset_split# 3.5、calculate accuracy percentagedef accuracy_metric(actual, predicted):return sum([actual[i] == predicted[i] for i in range(len(actual))]) / len(actual) * 100.0# 3.6、perceptron algrithm with stocastic gradient descentdef perceptron(train, test, l_rate, n_epoch):
weights = train_weights(train, l_rate, n_epoch)
predictions = []for row in test:
prediction = predict(row, weights)
predictions.append(prediction)return predictions# 3.7、evaluate an algrithm using a across validation splitdef evaluate_algrithm(dataset, algrithm, n_folds, *args):
folds = cross_validation_split(dataset, n_folds)
scores = []for fold in folds:
train_set = list(folds)
train_set.remove(fold)
train_set = sum(train_set, [])
test_set = []for row in fold:
row_copy = list(row)
test_set.append(row_copy)
row_copy[-1] = None
predicted = algrithm(train_set, test_set, *args)
actual = [row[-1] for row in fold]
accuracy = accuracy_metric(actual, predicted)
scores.append(accuracy)return scores# 4、test the perceptron algrithm on the sonar dataset
seed(1)# load and prepare data# 数据集:https://archive.ics.uci.edu/ml/datasets/Connectionist+Bench+(Sonar,+Mines+vs.+Rocks)# 下载时添加后缀.csv即可
filename = r'./sonar.all-data.csv'
dataset = load_csv(filename)for i in range(len(dataset[0]) - 1):
str_column_to_float(dataset, i)# connvert string class to intergers# ransform the target {R,M} to 0,1
str_column_to_integer(dataset, len(dataset[0]) - 1)# evaluate algrithm
n_folds = 3
l_rate = 0.01 # need to tune
n_epoch = 500
scores = evaluate_algrithm(dataset, perceptron, n_folds, l_rate, n_epoch)
print('Scores: %s' % scores)
print('Mean Accuracy: %.3f%%' % (sum(scores) / float(len(scores))))# 5、结果# ...# >epoch=498, lrate=0.010, error=55.000# >epoch=499, lrate=0.010, error=55.000# Scores: [56.52173913043478, 63.76811594202898, 39.130434782608695]# Mean Accuracy: 53.140%
参考资料
[1]Fisher线性判别分析(LDA): https://blog.csdn.net/mengjizhiyou/article/details/103309372
[2]广义模型与线性模型& 判别分析: https://blog.csdn.net/mengjizhiyou/article/details/83188432
[3]逻辑回归: https://blog.csdn.net/mengjizhiyou/article/details/103117274
更多推荐
所有评论(0)