李航机器学习 | (3) 统计学习方法(第2版)笔记 --- 感知机习题与编程作业

 

1. Minsky与Papert指出:感知机是线性模型,所以不能表示复杂的函数,如异或(XOR).验证感知机为什么不能表示异或。

首先写出异或函数对应的输入输出:

x^{(1)}x^{(2)}y
11-1
1-1+1
-11+1
-1-1-1

我们可以可视化上述实例及其标签:

import numpy as np
import matplotlib.pyplot as plt

x = np.array([[1,1],[1,-1],[-1,1],[-1,-1]])
y = np.array([-1,1,1,-1])

plt.scatter(x[:,0],x[:,1],c=y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.ylim(-2,2)
plt.xlim(-2,2)
plt.xticks([-2,-1,0,1,2])
plt.yticks([-2,-1,0,1,2])
plt.title('XOR')
plt.show()

显然异或问题是线性不可分的,感知机算法无法用一条直线把两类样本点完全分开。

 

2. 模仿上一节中的例题,构建从训练数据集求解感知机模型的例子。

import numpy as np
from sklearn.linear_model import  Perceptron

X_train = np.array([[3,3],[4,3],[1,1]])
y_train = np.array([1,1,-1])

#初始化感知机模型
perceptron_model = Perceptron()
#训练
perceptron_model.fit(X_train,y_train)
#打印学好的参数
print("w:",perceptron_model.coef_,"\nb:",perceptron_model.intercept_,"\n")

#在训练集上进行预测
res = perceptron_model.predict(X_train)
print(res)

 

3. 证明以下定理:样本集线性可分的充要条件是正实例点集所构成的凸壳与负实例点集所构成的凸壳互不相交。

在2维情况下,凸壳可用下面的图形来表示:

其中向量A,B,C,D,F可以看作是集合S中的元素,他们围成的整个多边形区域就是集合S的凸壳Conv(S),区域内所有的点或者向量都是Conv(S)中的元素。

线性可分的定义:

 

4. 思考感知机模型假设空间是什么?模型复杂度体现在哪?、

假设空间 {f|f=wx+b},即特征空间中的所有线性分类器。

模型的复杂度主要体现在实例特征向量x(x^{(1)},...,x^{(d)})的维度d上或者特征数量上。

 

5. 已知训练数据集D,其正实例点是x1=(3,3)T,x2=(4,3)T,负实例点是x3=(1,1)T:

1)试调用sklearn.linear_model 的Perceptron模块,对训练数据集进行分类,并对比不同学习率\eta对模型学习速度及结果的影响。

Perceptron模块/对象主要的方法或属性:

import numpy as np
from sklearn.linear_model import Perceptron

X_train = np.array([[3,3],[4,3],[1,1]])
y_train = np.array([1,1,-1])

#初始化感知机模型
perceptron_model = Perceptron()
#训练
perceptron_model.fit(X_train,y_train)

#打印学好的参数和迭代次数
print("w:",perceptron_model.coef_,"\nb:",perceptron_model.intercept_,"\nn_iter:",perceptron_model.n_iter_,"\n")

#在训练集上进行预测
res = perceptron_model.predict(X_train)
print(res)

#计算在训练集上的准确率
acc = perceptron_model.score(X_train,y_train)
print('correct accuracy:{:.0%}'.format(acc))

Perceptron模块/对象主要的参数:

设定tol=1e-3,max_iter=1000:

perceptron_model = Perceptron(tol=1e-3,max_iter=1000)

设置学习率:

perceptron_model = Perceptron(eta0=0.5,tol=1e-3,max_iter=1000)

w,b变成了原来的0.5倍。

perceptron_model = Perceptron(eta0=0.1,tol=1e-3,max_iter=1000)

w,b变成了原来的0.1倍。

改变学习率虽然w,b变了,但是他们之间的比例没有变,即表示的分离超平面是不变的,说明改变学习率对最终的结果没有影响,对收敛的速度会有影响。

原因在于,我们w,b的初始值为0,根据更新规则:

不管更新多少次,因为初始值为0,w,b都可以表示为\eta的倍数,而分离超平面的方程是wx+b=0,因为w,b都为\eta的倍数,所以可以约掉\eta,因此表示的分离超平面是不变的,说明改变学习率对最终的结果没有影响。如果w,b的初始值不为0,那么改变学习率对最终的结果是有影响的。

正则化:

可以选择使用l1或l2正则化,或者混合正则化(\lambda l_1+(1-\lambda)l_2)

正则化是为了防止过拟合(减小权值/参数),L1正则化会使权重/参数更稀疏;L2正则化会使权重/参数更均匀。

perceptron_model = Perceptron(penalty="l1",eta0=1,tol=1e-3,max_iter=1000)

perceptron_model = Perceptron(penalty="l2",eta0=1,tol=1e-3,max_iter=1000)

正则化系数控制惩罚或约束力度,过小无约束效力;过大约束太狠,可能会出现欠拟合(模型过于简单,参数会变得很小)。

perceptron_model = Perceptron(penalty="l2",alpha=0.0001,eta0=1,tol=1e-3,max_iter=1000)

perceptron_model = Perceptron(penalty="l2",alpha=0.1,eta0=1,tol=1e-3,max_iter=1000)

2) 用python 自编程实现感知机模型,对训练数据集进行分类,并对比误分类点选择次序不同对最终结果的影响。可采用函数式编程或面向对象的编程。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

class MyPerceptron:
    def __init__(self):
        self.w=None
        self.b=0
        self.l_rate=1

    def fit(self,X_train,y_train):
        #用样本点的特征数更新初始w,如x1=(3,3)T,有两个特征,则self.w=[0,0]
        #尽量使用二维数组来表示行向量/列向量
        self.w=np.zeros(X_train.shape[1]).reshape(-1,1)
        i=0
        while i<X_train.shape[0]:
            X=X_train[i]
            y=y_train[i]
            # 如果y*(wx+b)≤0 说明是误判点,更新w,b
            if y*(np.dot(X, self.w) + self.b) <= 0:
                self.w = self.w + self.l_rate * y*X.reshape(-1,1)
                self.b = self.b + self.l_rate * y
                i=0 #如果是误判点,从头进行检测
            else:
                i+=1

def draw(X,w,b):
    #产生分离超平面上的两点
    X_new=np.array([[0], [6]])
    y_predict=-b-(w[0]*X_new)/w[1]
    #绘制训练数据集的散点图
    plt.plot(X[:2,0],X[:2,1],"g*",label="1")
    plt.plot(X[2:,0], X[2:,1], "rx",label="-1")
    #绘制分离超平面
    plt.plot(X_new,y_predict,"b-")
    #设置两坐标轴起止值
    plt.axis([0,6,0,6])
    #设置坐标轴标签
    plt.xlabel('x1')
    plt.ylabel('x2')
    #显示图例
    plt.legend()
    #显示图像
    plt.show()

#也可以使用等高线图 通过生成网格的方式 渲染出决策边界
def visual(X,w,b,label):

    h = .01
    # 生成网格点
    min1 = np.min(X[:, 0]) - 0.5
    max1 = np.max(X[:, 0]) + 0.5
    min2 = np.min(X[:, 1]) - 0.5
    max2 = np.max(X[:, 1]) + 0.5
    xx, yy = np.meshgrid(np.arange(min1, max1, h), np.arange(min2, max2, h))  # 在x,y轴上以0.02为间隔,生成网格点

    # 计算每个网格点在判别函数下的值
    Z = np.concatenate([xx.ravel().reshape(-1, 1), yy.ravel().reshape(-1, 1)],
                       axis=1)
    res = Z.dot(w)+b

    res[res <= 0] = -1
    res[res > 0] = 1

    res = res.reshape(xx.shape)  # 转型为网格的形状

    # 绘制决策边界
    plt.contourf(xx, yy, res, alpha=0.5, cmap=ListedColormap(('red', 'blue')))
    # 添加图例 注释
    plt.xlabel('x1')
    plt.ylabel('x2')

    # 绘制数据点
    for i, j in enumerate(np.unique(label)):
        plt.scatter(X[label == j, 0], X[label == j, 1], c=ListedColormap(('red', 'blue'))(i),
                    label=str(j))

    plt.legend()
    plt.show()

def main():
    # 构造训练数据集
    X_train=np.array([[3,3],[4,3],[1,1]])
    y_train=np.array([1,1,-1])
    # 构建感知机对象,对数据集继续训练
    perceptron=MyPerceptron()
    perceptron.fit(X_train,y_train)
    print(perceptron.w)
    print(perceptron.b)
    # 结果图像绘制
    #draw(X_train,perceptron.w,perceptron.b)
    visual(X_train,perceptron.w,perceptron.b,y_train)


if __name__=="__main__":
    main()

3) 对比传统感知机算法及其对偶形式的运行速度。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值