【机器学习】LR(逻辑分类&softmax分类)—— python3 实现方案

包含sigmoid和softmax模型,优化算法为批量梯度下降法

使用数据是吴恩达机器学习第二第三节的作业。

import numpy as np
from sklearn import preprocessing
from sklearn import datasets


class LogisticRegression:
    def __init__(self, learning_rate=0.1, lamb=0.001, iters=1000, kernel='sigmoid'):
        self.learning_rate = learning_rate  # 学习速率,默认值为1
        self.lamb = lamb  # 正则化参数,默认值为1
        self.iters = iters  # 最大迭代次数
        self.kernel = kernel  # 内核函数,sigmoid或者softmax
        self.theta = np.zeros((1, 1))  # 声明参数是二维array格式
        self.cost = []  # 记录损失值

    @staticmethod
    def sigmoid(features, theta):
        """
        逻辑函数,用于二元分类,数据集均为np.array格式
        :param features: 特征集m*(n+1),m为样本数,n为特征数
        :param theta: 参数集k*(n+1),k为标签的类别数,n为特征数
        :return: 函数计算结果
        """
        inner = np.dot(features, theta.T)  # 计算内核
        return 1 / (1 + np.exp(-inner))

    @staticmethod
    def softmax(features, theta):
        """
        softmax函数,用于多元分类,数据集均为np.array格式
        :param features: 特征集m*(n+1),m为样本数,n为特征数
        :param theta: 参数集k*(n+1),k为标签的类别数,n为特征数
        :return: 函数计算结果
        """
        inner = features.dot(theta.T)
        return np.exp(inner) / np.sum(np.exp(inner), axis=1, keepdims=True)  # inner的格式为m*k,如此设置np.sum的参数,可使按行相加后的结果m*1

    def cal_cost(self, features, target, theta, lamb):
        """
        计算损失函数(对数损失),使用L2正则化
        :param features: 特征集m*(n+1),m为样本数,n为特征数
        :param target: 目标集m*k,k为类别数
        :param theta: 参数集k*(n+1),k为标签的类别数,n为特征数
        :param lamb: 正则化参数,默认值为1
        :return: 对数损失
        """
        m = features.shape[0]  # 样本数
        if self.kernel == 'sigmoid':
            inner = self.sigmoid(features, theta)  # softmax和sigmoid的损失函数格式上一致
        else:
            inner = self.softmax(features, theta)
        first = np.multiply(-target, np.log(inner))  # 前半部分
        second = np.multiply((1 - target), np.log(1 - inner))  # 后半部分
        reg = lamb / (2 * m) * np.sum(np.power(theta[:, 1:], 2))  # 正则化
        return np.sum(first - second) / m + reg

    def training(self, features, target):
        """
        使用批量梯度下降算法优化
        :param features: 特征集m*n,m为样本数,n为特征数
        :param target: 目标集m*k,k为类别数
        :return: 更新参数和损失值,无返回
        """
        features = np.insert(features, 0, 1, axis=1)  # 特征集增加一列x0,且令x0=1,以便于矩阵运算
        m, n = features.shape
        k = target.shape[1]  # 目标类别数
        self.theta = np.zeros((k, n))  # 此时n=特征数+1
        for _ in range(self.iters):  # 梯度下降
            if self.kernel == 'sigmoid':
                inner = self.sigmoid(features, self.theta)
            else:
                inner = self.softmax(features, self.theta)

            error = inner - target  # 误差
            grad = error.T.dot(features) / m + self.lamb / m * self.theta  # 计算梯度
            grad[:, 0] = np.sum(error, axis=0) / m  # 上一步对所有theta都进行了正则化,这一步重新计算theta0的梯度,以取消正则化
            self.theta -= self.learning_rate * grad  # 更新theta
            self.cost.append(self.cal_cost(features, target, self.theta, self.lamb))  # 添加当前损失值
        return

    def predict(self, features, threshold=0.5):
        """
        根据输入特征集和参数theta,输出预测值
        :param features: 待测样本1*n,n为特征数
        :param threshold: 阀值,默认值为0.5,大于0.5输出正类别,反之负类别.仅当kernel=sigmoid时使用
        :return: 若kernel=sigmoid,输出1或0(表示正类别或负类别);若干kernel=softmax,输出概率最大类别的索引,m*1
        """
        features = np.insert(features, 0, 1, axis=1)
        if self.kernel == 'sigmoid':
            inner = self.sigmoid(features, self.theta)
            return [1 if i[0] >= threshold else 0 for i in inner]
        else:
            inner = self.softmax(features, self.theta)
            return np.argmax(inner, axis=1)  # 概率最大类别的索引


def test_sigmoid():  # 使用sklearn生成的双类别数据测试sigmoid
    features, target = datasets.make_classification(n_samples=300)
    target = target.reshape(target.shape[0], 1)

    lr = LogisticRegression()
    lr.training(features, target)
    predict = lr.predict(features)  # 获取最大预测索引
    correct = [0 if a ^ b else 1 for a, b in zip(predict, target)]
    accuracy = correct.count(1) / len(correct)  # 计算准确度
    print('accuracy={}%'.format(accuracy * 100))


def test_softmax():
    """使用鸢尾花进行测试的时候,可以做到93%的预测准确率
    使用sklearn生成的多类别数据测试softmax,当类别增多时,准确率迅速下降,原因可能是生成的数据不存在良好的线性关系
    """
    # features, target = datasets.make_classification(n_samples=5000, n_informative=4, n_classes=5)
    dataset = datasets.load_iris()  # 鸢尾花数据集
    features, target = dataset['data'], dataset['target']
    target = target.reshape(-1, 1)
    enc = preprocessing.OneHotEncoder()
    target_train = enc.fit_transform(target).toarray()  # 对目标集独热编码

    lr = LogisticRegression(learning_rate=0.001, lamb=0, iters=5000, kernel='softmax')
    lr.training(features, target_train)
    predict = lr.predict(features)
    correct = [1 if a == b else 0 for a, b in zip(predict, target)]  # 本例中,索引值正好等于原数据
    accuracy = correct.count(1) / len(correct)
    print('accuracy={}%'.format(accuracy * 100))


test_sigmoid()
test_softmax()

 

PyTorch是一个流行的深度学习框架,用于实现各种机器学习模型,包括softmax回归。softmax回归常用于分类任务,它将每个输入映射到概率分布上,表示样本属于各个类别的可能性。 以下是在PyTorch中实现简单softmax回归的基本步骤: 1. 导入所需库: ```python import torch from torch import nn ``` 2. 定义模型:创建一个只有一个权重的线性层,然后跟一个Softmax函数作为激活, Softmax函数会把输出转换成概率分布。 ```python class SoftmaxRegression(nn.Module): def __init__(self, input_size, output_size): super(SoftmaxRegression, self).__init__() self.linear = nn.Linear(input_size, output_size) def forward(self, x): out = self.linear(x) return torch.softmax(out, dim=1) # dim=1 表示沿着第二个维度(列)计算softmax ``` 3. 初始化模型和优化器: ```python input_size = ... # 根据数据集特征确定 output_size = ... # 类别数 model = SoftmaxRegression(input_size, output_size) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 使用随机梯度下降优化器 ``` 4. 训练过程: ```python for epoch in range(num_epochs): # Forward pass: 前向传播计算预测值 outputs = model(inputs) # Compute loss loss = nn.CrossEntropyLoss()(outputs, labels) # Backward and optimize optimizer.zero_grad() # 清零梯度 loss.backward() optimizer.step() # 更新参数 ``` 5. 测试模型: ```python with torch.no_grad(): # 禁止追踪梯度,仅用于测试阶段 predictions = model(test_data) _, predicted_labels = torch.max(predictions.data, 1) # 获取最大概率对应的类别 ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值