当前位置 博文首页 > 清风紫雪:机器学习十讲-第三讲分类

    清风紫雪:机器学习十讲-第三讲分类

    作者:清风紫雪 时间:2021-02-09 00:25

    感知机

    原理

     

     

     下面用一个 perception 函数实现上述算法。为了深入观察算法运行过程,我们保留了每一轮迭代的参数 ww,并对每一轮迭代中随机选取的样本也进行了记录。所以,perception 函数返回三个取值: 最终学习到的参数 w, 每轮迭代的参数 W, 每轮迭代随机选取的样本 mis_samples 。

    代码实现

    def perception(X,y,learning_rate,max_iter=1000):
        w = pd.Series(data=np.zeros_like(X.iloc[0]),index=X.columns) # 初始化参数 w0
        W = [w] # 定义一个列表存放每次迭代的参数
        mis_samples = [] # 存放每次误分类的样本
        
        for t in range(max_iter):
            
            # 2.1 寻找误分类集合 M
            m = (X.dot(w))*y #yw^Tx < 0 的样本为误分类样本
            X_m = X[m <= 0]  # 误分类样本的特征数据
            y_m = y[m <= 0]  # 误分类样本的标签数据
            
            if(len(X_m) > 0): # 如果有误分类样本,则更新参数;如果不再有误分类样本,则训练完毕。
                # 2.2 从 M 中随机选取一个样本 i 
                i = np.random.randint(len(X_m))
                mis_samples.append(X_m.iloc[i,:])
                # 2.3 更新参数 w 
                w = w + learning_rate * y_m.iloc[i]*X_m.iloc[i,:]
                W.append(w)
            else: 
                break
                
        mis_samples.append(pd.Series(data=np.zeros_like(X.iloc[0]),index=X.columns))
        return w,W,mis_samples
    w_percept,W,mis_samples = perception(data[["x1","x2","ones"]], data["label"],1,max_iter=1000)

    将学习到的感知机的决策直线可视化,观察分类效果。

    x1 = np.linspace(-6, 6, 50)
    x2 = - (w_percept[0]/w_percept[1])*x1 - w_percept[2]/w_percept[1]
    plt.figure(figsize=(8, 8)) #设置图片尺寸
    
    plt.scatter(data_pos["x1"],data_pos["x2"],c="#E4007F",marker="^") # 类别为1的数据绘制成洋红色
    plt.scatter(data_neg["x1"],data_neg["x2"],c="#007979",marker="o") # 类别为-1的数据绘制成深绿色
    plt.plot(x1,x2,c="gray") # 画出分类直线
    
    plt.xlabel("$x_1$") #设置横轴标签
    plt.ylabel("$x_2$") #设置纵轴标签
    plt.title('手动实现的感知机模型')
    plt.xlim(-6,6) #设置横轴显示范围
    plt.ylim(1,5) #设置纵轴显示范围
    plt.show()

    展示:

     

     

     逻辑回归

    原理

     

     

     代码实现

    梯度下降法求解逻辑回归

    import numpy as np
    # 定义梯度下降法求解的迭代公式
    def logistic_regression(X,y,learning_rate,max_iter=1000):
        # 初始化w
        w = np.zeros(X.shape[1])
        for t in range(max_iter):      
            # 计算yX
            yx = y.values.reshape((len(y),1)) * X 
            # 计算1 + e^(yXW)
            logywx = (1 +  np.power(np.e,X.dot(w)*y)).values.reshape(len(y),1) 
            w_grad = np.divide(yx,logywx).sum()
            # 迭代w
            w = w + learning_rate * w_grad    
        return w

    我们将数据及标签带入上面定义的函数,学习率设为 0.5 ,迭代次数为1000次,输出训练好的参数,并将分类结果进行可视化。

    # 输出训练好的参数
    w = logistic_regression(data[["x1","x2","ones"]], data["label"],0.5,max_iter=1000)  
    print(w)
    
    # 可视化分类结果
    x1 = np.linspace(-6, 6, 50)
    x2 = - (w[0]/w[1])*x1 - w[2]/w[1]
    
    plt.figure(figsize=(8, 8))
    plt.scatter(data_pos["x1"],data_pos["x2"],c="#E4007F",marker="^") # 类别为1的数据绘制成洋红色
    plt.scatter(data_neg["x1"],data_neg["x2"],c="#007979",marker="o") # 类别为-1的数据绘制成深绿色
    plt.plot(x1,x2,c="gray")
    
    plt.xlabel("$x_1$")
    plt.ylabel("$x_2$")
    plt.xlim(-6,6)
    plt.ylim(1,5)
    plt.show()

     

     

     

    随机梯度下降法求解逻辑回归

     

     

     

    # 定义随机梯度下降法求解的迭代公式
    def logistic_regression_sgd(X,y, learning_rate, max_iter=1000): 
        # 初始化w
        w = np.zeros(X.shape[1])
        for t in range(max_iter):
            # 随机选择一个样本
            i = np.random.randint(len(X))
            # 计算yx
            yixi = y[i] * X.values[i]
             # 计算1 + e^(yxW)
            logyiwxi = 1 +  np.power(np.e, w.T.dot(X.values[i])*y[i])
            w_grad = yixi / logyiwxi
            
            # 迭代w
            w = w + learning_rate * w_grad  
            
        return w

    我们将学习率设为 0.5,迭代次数为1000次,并输出训练好的参数,将分类结果可视化。

    # 输出训练好的参数
    w = logistic_regression_sgd(data[["x1","x2","ones"]], data["label"],0.5,max_iter=1000)  
    print(w)
    
    # 可视化分类结果
    x1 = np.linspace(-6, 6, 50)
    x2 = - (w[0]/w[1])*x1 - w[2]/w[1]
    
    plt.figure(figsize=(8, 8))
    plt.scatter(data_pos["x1"],data_pos["x2"],c="#E4007F",marker="^") # 类别为1的数据绘制成洋红色
    plt.scatter(data_neg["x1"],data_neg["x2"],c="#007979",marker="o") # 类别为-1的数据绘制成深绿色
    plt.plot(x1,x2,c="gray")
    
    plt.xlabel("$x_1$")
    plt.ylabel("$x_2$")
    plt.xlim(-6,6)
    plt.ylim(1,5)
    plt.show()

     

     

     

    向量机

    原理

     

     

     代码实现

    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    # 定义函数
    def linear_svm(X,y,lam,max_iter=2000):  
        w = np.zeros(X.shape[1]) # 初始化w
        support_vectors = [] # 创建空列表保存支持向量
        
        for t in range(max_iter): # 进行迭代
            
            learning_rate = 1/(lam * (t + 1)) # 计算本轮迭代的学习率
            i = np.random.randint(len(X)) # 从训练集中随机抽取一个样本
            ywx = w.T.dot(X.values[i])*y[i]  # 计算y_i w^T x_i
            
            if ywx < 1:# 进行指示函数的判断
                w = w - learning_rate * lam*w + learning_rate * y[i] * X.values[i] # 更新参数       
            else:
                w = w - learning_rate * lam*w # 更新参数
        for i in range(len(X)):
            ywx = w.T.dot(X.values[i])*y[i]  # 计算y_i w^T x_i
            if ywx <= 1: # 根据样本是否位于间隔附近判断是否为支持向量
                support_vectors.append(X.values[i])
        
        return w,support_vectors

    需要注意的是,线性支持向量机的正则化项通常不包括截距项,我们可以将数据进行中心化,再调用上述代码。

    # 对训练集数据进行归一化,则模型无需再计算截距项
    X = data[["x1","x2"]].apply(lambda x: x - x.mean())
    # 训练集标签
    y = data["label"]
    w,support_vectors = linear_svm(X,y, lam=0.05, max_iter=5000)

    将得到的超平面可视化,同时将两个函数间隔为 1 的线也绘制出来。对于所有不满足约束的样本,使用圆圈标记出来。

    # 创建绘图框
    plt.figure(figsize=(8, 8))
    # 绘制两类样本点
    X_pos = X[ y==1 ]
    X_neg = X[ y==-1 ]
    plt.scatter(X_pos["x1"],X_pos["x2"],c="#E4007F",marker="^") # 类别为1的数据绘制成洋红色
    plt.scatter(X_neg["x1"],X_neg["x2"],c="#007979",marker="o") # 类别为-1的数据绘制成深绿色
    
    # 绘制超平面
    x1 = np.linspace(-6, 6, 50)
    x2 = - w[0]*x1/w[1]
    plt.plot(x1,x2,c="gray")
    
    # 绘制两个间隔超平面
    plt.plot(x1,-(w[0]*x1+1)/w[1],"--",c="#007979")
    plt.plot(x1,-(w[0]*x1-1)/w[1],"--",c="#E4007F")
    
    # 标注支持向量
    for x in support_vectors:
        plt.plot(x[0],x[1],"ro", linewidth=2, markersize=12,markerfacecolor='none')
        
    # 添加轴标签和限制轴范围
    plt.xlabel("$x_1$")
    plt.ylabel("$x_2$")
    plt.xlim(-6,6)
    plt.ylim(-2,2)

     

     

     实例-新闻主题分类

    步骤

    读取数据

    raw_train = pd.read_csv("./input/chinese_news_cutted_train_utf8.csv",sep="\t",encoding="utf8")
    raw_test = pd.read_csv("./input/chinese_news_cutted_test_utf8.csv",sep="\t",encoding="utf8")

    查看训练集的前5行。

    raw_train.head()

     

     为了简单,我们这里先只考虑二分类,我们选取主题为"科技"和“文化”新闻。

    raw_train_binary = raw_train[((raw_train["分类"] == "科技") | (raw_train["分类"] == "文化"))]
    raw_test_binary = raw_test[((raw_test["分类"] == "科技") | (raw_test["分类"] == "文化"))]

    下一篇:没有了