您的位置:首页 > 其它

机器学习作业1 - 对率回归(逻辑回归)

2017-09-28 21:06 239 查看

使用10折交叉验证法和留一法评测对率回归分类器

标题有点长哈……这是第一次作业,来自周志华《机器学习》作业3.4,题目如下:

选择两个UCI数据集,比较10折交叉验证法和留一法所估计出的对率回归(逻辑回归)的错误率。

那么,首先下载数据。实验中我使用的是 IrisWine 这两个数据集,前者简单点,后者复杂点。要注意的是,这两个数据集都是3个分类,为了偷个懒,我就把第三个分类删了,保留前两个分类。

分类器

对率回归分类器还是很简单的,大体思路如下:

假设输入数据维度 m,我们保存一个权重向量,在计算的时候直接计算 m 和权重向量的点积,然后将点积结果加上偏置值,最后将计算结果通过 Sigmoid 函数,并输出预测结果。

为了方便起见,可以把偏置值一起放到权重向量中去,此时只要在数据中加上常数1即可,设加上常数以后的数据维度为 m + 1,则权重向量维度也为 m + 1。接下来给出损失函数如下。关于该函数的推导过程,斯坦福大学机器学习课程–逻辑回归算法 这篇博文已经写的非常详细了,大家可以直接看看。

L(θ)=−1m∑i=1m[yilogh0(xi)+(1−yi)log(1−h0(xi))]

那么,现在的目标是使得损失函数最小,因为损失函数越小代表着我们模型的预测结果越准确。接下来使用梯度下降法,基本思想是:在损失函数的结果中,对权重向量的每个元素求偏导,并按照比例(学习速率)对权重进行修改。这样一来,权重将向着减少损失函数值的方向发展。具体的推导过程同样可见上面那篇博文。分类器代码如下:

import numpy as np

class Classifier(object):
def __init__(self, attr_count, learn_rate=0.05):
self.__attr_count__ = attr_count
self.__learn_rate__ = learn_rate
self.__weight__ = np.zeros(shape=[attr_count + 1], dtype=np.float32)

def fit(self, value, label):
value = np.append(value, [1.0])
linear_result = np.dot(value, self.__weight__)
sigmoid_result = 1.0 / (np.exp(-linear_result) + 1.0)
for idx in range(self.__attr_count__ + 1):
update_val = (sigmoid_result - label) * value[idx]
self.__weight__[idx] -= self.__learn_rate__ * update_val

def classify(self, value):
value = np.append(value, [1.0])
linear_result = np.dot(value, self.__weight__)
if (1.0 / (np.exp(-linear_result) + 1.0)) > 0.5:
return 1
else:
return 0


准备数据

训练数据的准备很简单,直接使用 Python 的文件操作,读入数据文件即可。其中涉及到一些数组的切片操作,为了提高学习效率,在训练之前使用 numpy 打乱了数据集。

if __name__ == '__main__':
# 读入并打乱 Wine 数据集
data_str = open('Data/wine.data').readlines()
np.random.shuffle(data_str)
# 使用数组切片操作,分离数据和标签
wine_value = np.ndarray([len(data_str), 13], np.float32)
wine_label = np.ndarray([len(data_str)], np.int32)
for outer_idx in range(len(data_str)):
data = data_str[outer_idx].strip('\n').split(',')
wine_value[outer_idx] = data[1:]
wine_label[outer_idx] = data[0]
# 进行训练和测试
test_main(wine_value, wine_label, 13)


训练和验证

因为之前的分类器已经提供好了训练和测试的函数,所以直接调用即可。接下来使用10折交叉验证法和留一法进行验证。

10折交叉验证法:将数据等分为10份,每次用其中9份训练,剩下1份测试,然后统计10次测试的评价错误率。

留一法:将数据分为 k 份(k为数据大小),每次用 k - 1 条数据训练,用1条测试,统计总体错误率。

使用简单的循环语句即可实现上述方法:

def test_main(value, label, attr_count):
batch_size = len(value) // 10
total_correct_times = 0
for idx in range(10):
print('10折交叉验证:当前第 %d 次' % (idx + 1))
correct_times = 0
classifier = LinearClassifier.Classifier(attr_count)
value_train = np.append(value[0:idx * batch_size], value[(idx + 1) * batch_size:], axis=0)
label_train = np.append(label[0:idx * batch_size], label[(idx + 1) * batch_size:], axis=0)
value_test = value[idx * batch_size:(idx + 1) * batch_size]
label_test = label[idx * batch_size:(idx + 1) * batch_size]
for repeat in range(TRAIN_TIMES):
for sub_idx in range(len(value_train)):
classifier.fit(value_train[sub_idx], label_train[sub_idx])
for sub_idx in range(len(value_test)):
result = classifier.classify(value_test[sub_idx])
if result == label_test[sub_idx]:
correct_times += 1
total_correct_times += correct_times
print('准确率:%.2f%%\n' % (correct_times * 100 / len(value_test)))
print('10折交叉验证结束,平均准确率:%.2f%%\n' % (total_correct_times * 100 / len(value)))
total_times = len(value)
correct_times = 0
for idx in range(total_times):
print('留一法第 %d 次,共 %d 次' % (idx, total_times))
classifier = LinearClassifier.Classifier(attr_count)
value_train = np.append(value[0:idx], value[(idx + 1):], axis=0)
label_train = np.append(label[0:idx], label[(idx + 1):], axis=0)
value_test = value[idx]
label_test = label[idx]
for repeat in range(TRAIN_TIMES):
for sub_idx in range(len(value_train)):
classifier.fit(value_train[sub_idx], label_train[sub_idx])
result = classifier.classify(value_test)
if result == label_test:
correct_times += 1
print('留一法验证结束,准确率:%.2f%%' % (correct_times * 100 / total_times))


运行结果

代码在 Python 3.5 环境中执行结果如下:

使用 wine.data 进行验证

10折交叉验证:当前第 1 次

准确率:84.62%

10折交叉验证:当前第 2 次

准确率:84.62%

10折交叉验证:当前第 3 次

准确率:92.31%

10折交叉验证:当前第 4 次

准确率:92.31%

10折交叉验证:当前第 5 次

准确率:69.23%

10折交叉验证:当前第 6 次

准确率:84.62%

10折交叉验证:当前第 7 次

准确率:69.23%

10折交叉验证:当前第 8 次

准确率:92.31%

10折交叉验证:当前第 9 次

准确率:84.62%

10折交叉验证:当前第 10 次

准确率:92.31%

10折交叉验证结束,平均准确率:84.62%

开始使用留一法验证

留一法验证结束,准确率:83.85%

使用 iris.data 进行验证

10折交叉验证:当前第 1 次

准确率:100.00%

10折交叉验证:当前第 2 次

准确率:100.00%

10折交叉验证:当前第 3 次

准确率:100.00%

10折交叉验证:当前第 4 次

准确率:100.00%

10折交叉验证:当前第 5 次

准确率:100.00%

10折交叉验证:当前第 6 次

准确率:100.00%

10折交叉验证:当前第 7 次

准确率:100.00%

10折交叉验证:当前第 8 次

准确率:100.00%

10折交叉验证:当前第 9 次

准确率:100.00%

10折交叉验证:当前第 10 次

准确率:100.00%

10折交叉验证结束,平均准确率:100.00%

开始使用留一法验证

留一法验证结束,准确率:100.00%

从结果可见,10折交叉验证法和留一法结果基本一致,而 Iris 数据集由于数据维度较低,预测效果明显好于 Wine 数据集。

详细代码和数据文件请访问:

https://coding.net/u/dapanbest/p/MLHomeworks/git/tree/master/LinearModel

完结撒花!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: