逻辑回归实现多分类(Logistics Regression)

一、简介

    线性回归大家都知道,通过训练数据集拟合出一条线性函数,预测函数为Y = θ.T*X,那么线性回归的问题在哪呢?如果有离群点或者自变量比较大的点,它会很大程度上影响拟合函数,所以将线性的预测函数加一层衣服,变为非线性,这样,离群点也就基本不会影响我们的预测函数了。通过数学家的研究,选定的非线性化函数为sigmod函数,g(z) = \frac{1}{1+e^{-z}},这个函数的值域为(0,1),接下面我们直接结合代码给大家讲解利用逻辑回归实现多分类的问题。

二、分析及代码

 1.首先我们读取数据集以数组返回

def load_mnist(path, kind='train'):
    """Load MNIST data from `path`"""
    labels_path = os.path.join(path,
                               '%s-labels-idx1-ubyte'
                               % kind)
    images_path = os.path.join(path,
                               '%s-images-idx3-ubyte'
                               % kind)
    with open(labels_path, 'rb') as lbpath:
        magic, n = struct.unpack('>II',
                                 lbpath.read(8))
        labels = np.fromfile(lbpath,
                             dtype=np.uint8)

    with open(images_path, 'rb') as imgpath:
        magic, num, rows, cols = struct.unpack('>IIII',
                                               imgpath.read(16))
        images = np.fromfile(imgpath,
                             dtype=np.uint8).reshape(len(labels), 784)
    return images, labels

2.对数据进行预处理,预处理包括给特征给上x0的偏置项,并进行归一化处理


    def DataPreProcess(self, data):
        n = data.shape[0]
        b = np.array([1 for i in range(n)])
        data = np.c_[b, data]  # 给每个样本加个常数项
        data = (data - np.mean(data)) / np.std(data)  # 数据归一化
        return data

3.由于是多分类,我们的类别有10个类,所以需要训练10个分类器,每个分类器都是一个二分类器,例如:对于数字0的分类器来说,我们将标签为0的数据的标签重新改成正类1,将非0标签对应的数据的标签改为负类0,即变为一个二分类问题,其他分类器一样,将标签是对应分类的类别的标签改为1, 其他置为0。python实现如下:

    def TransforTwoClassify(self, label):
        y_temp = copy.deepcopy(self.y_train)  # 对于每个分类器的临时标签,将10分类改为2分类
        for i in range(60000):
            if y_temp[i] != label:
                y_temp[i] = 0
            else:
                y_temp[i] = 1
        return y_temp

4.接下来就是训练网络了,逻辑回归采用的损失函数是交叉熵函数,利用梯度下降更新参数,采用正则化来防止过拟合。


    def training(self):
        Theta, H = [], []
        m = 60000
        alpha, times = 0.001, 1000       # 学习率和迭代次数
        # lamb = np.exp(-18)                         # 正则化惩罚参数,防止过拟合
        lamb = 0.01
        L = []
        for label in range(self.classNum):
            y_temp = self.TransforTwoClassify(label)     # 二分类的标签集合
            theta = self.InitParameter()
            loss = []
            for i in range(times):
                z = np.matmul(self.X_train, theta)  # z:(60000,) 即60000维的向量
                h = 1 / (1 + np.exp(-z))
                J = 1 / m * np.sum(-y_temp * np.log(h) - (1 - y_temp) * np.log(1 - h))+ lamb/(2*m)*np.sum(theta**2)
                # J = 1 / m * np.sum(-y_temp * np.log(h) - (1 - y_temp) * np.log(1 - h))
                loss.append(J)
                theta[0] -= alpha/m*(h-y_temp).dot(self.X_train[:, 0])
                theta[1:] -= alpha*(1/m*(h-y_temp).dot(self.X_train[:, 1:]) + lamb*theta[1:]/m)
                # theta = theta - alpha * (1 / m * (h - y_temp).dot(self.X_train))
            Theta.append(theta)
            L.append(loss)
        L = np.array(L)
        np.savetxt("L.txt", L, fmt='%f', delimiter=',')
        Theta = np.array(Theta)
        # Theta = np.loadtxt('Theta.txt', delimiter=',')
        z = np.matmul(self.X_test, Theta.T)  # z:(10000,10) 即60000维的向量
        h = 1/(1 + np.exp(-z))
        predict = h.argmax(axis=1)
        ans = np.sum(predict==self.y_test)          # 求分类正确的个数
        print(ans/10000, ans)
        print(predict, self.y_test)
        np.savetxt("Theta.txt", Theta, fmt='%f', delimiter=',')
        for i in range(10):
            ax2 = plt.subplot(2, 5, i+1)
            ax2.plot(L[i])  # 损失函数和迭代次数的图像
        plt.show()

目前准确率是百分之八十多,如果增加训练次数,,可以达到90%以上

你可能感兴趣的:(机器学习)