机器学习---3.逻辑回归

讲了回归,就不得不提到Logistic Regression

有的人叫它逻辑回归,也有人叫对数几率回归(西瓜书上的叫法)
提到逻辑回归,就相当于打开了一个新世界的大门,在之前我们只能通过一堆数据,预测某个未知值的值,这类问题也可以叫回归问题。今天这个小可爱虽然它叫逻辑回归,但是如果你以为它是用来解决回归问题的,那就大错特错了,它可是用来解决分类问题的哦,所以有了它我们就不再只能依赖数据得到数据了,还可以得到某种属性特点(离散型变量)

之前一直没有讲机器学习的一些专业名词,是我的错,呜呜呜。所以这次先来补充一点

机器学习的算法分类: 监督学习,非监督学习,增强学习,深度学习

监督学习: 监督学习是指给出的数据集中包含了事物各个属性以及事物的标签
比如咸度适中,鲜美度高的是好吃的,咸度特别咸的是不好吃的

非监督学习: 非监督学习就是指数据集中只有事物的各个属性,没有标签。比如给一堆只含有两个美女小姐姐的照片,每张照片没有对应的名字,但是你还是会根据两人容貌不一样,把照片分为两类,这就是非监督学习,所以一般分监督学习是用来把数据集分成不同簇(聚类)。

增强学习: 增强学习又叫强化学习,它和上面两类的算法不一样,它是最像小孩子成长的,如果它考试考的很优秀,就会给它一点好吃的奖励一下;但是如果做错事了,也会让它罚站惩罚一下;这样,久而久之的它就会知道在什么情况下怎么做是最正确的,所以它一般用于需要决策类的问题。

深度学习: 这个应该是目前最受欢迎的算法了吧,由一开始简单的神经网络发展到现在多层感知机,卷积神经网络……,慢慢模仿人脑,增加其中的隐含层,遗忘层等等;在这里主要还是介绍机器学习,至于深度学习看什么时候写完机器学习再开始写吧。不过在这里得感慨一件事,任何技术的进步真的离不开硬件的支持,还记得当时的tensorflow用的cpu,算个简单的神经网络耗时久而且电脑特别卡,后来有了gpu,那个速度快的真的不止一点,特别是你迭代次数多,模型复杂的情况。

anyway,深度学习也不是万能的,它的缺点也很明显,它不会去判断数据情况,会把数据中的不合理带入自己的“思维”。举个例子:假如我们给一堆数据给深度学习,让它来帮我们挑选最适合的公司求职者,职位呢是前台接待,但是呢由于人为或其他误差,给它训练的数据全是男性的数据,这样它得到的结果就会很倾向于选择男性求职者,那公司就可能失去美丽漂亮,业务能力又出众的小姐姐了,是不是很难受。而且对于它做出的决策不能给出道理,有点不讲道理的意思。

而监督学习又可以再分,主要是回归问题分类问题

所以我们可以依靠上面的概念绘制一张大致的图来表示,这里暂时不考虑深度学习。

数据集带有标签
数据集不带标签
会对模型进行奖励或惩罚
用于预测连续变量
用于对非连续性变量预测得到标签值从而分类
主要是分出不同的簇
机器学习
监督学习
非监督学习
强化学习
回归问题
分类问题
聚类问题

正式开始讲逻辑回归

前面说了逻辑回归是用来分类的,但是普通的回归得到的都是一个数值,那怎么用于分类呢?
首先再说一次之前的回归函数, h ( θ ) = θ T X h(θ)=θ^TX h(θ)=θTX,然后还有损失函数
J ( θ ) = 1 2 m ∑ ∫ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(θ)=\frac{1}{2m}∑\int_{i=1}^m(hθ(x^{(i)})−y^{(i)})^2 J(θ)=2m1i=1m(hθ(x(i))y(i))2
经过梯度下降使损失函数最小得到最后的回归方程。
那逻辑回归是怎么做到解决分类问题的,其实很简单,数学有很神奇的函数,对数几率函数,这也是为什么叫它对数几率回归的原因。而我们用到的就是sigmoid函数,它大概长这个亚子
在这里插入图片描述
在这里插入图片描述
这对于分类问题来说,无疑是个比较好的激活函数,因为我们可以由此得到一个阶跃函数
在这里插入图片描述
这就可以让我们把预测到的值变成0或者1,分别代表两类。(所以一般逻辑回归也只用于二分类,多分类问题还有其他的算法更合适)

实现起来就是用sigmoid函数代替之前的回归函数
在这里插入图片描述
最后计算得到
在这里插入图片描述
对于参数的估计就要用到极大似然法
在这里插入图片描述

理论讲的差不多了,自己写点代码试试

用到的数据集是机器学习最常用的数据集之一----Iris(鸢尾花)数据集
具体数据集的介绍我就不多说了,因为实在是用的太多了,直接撸代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris #sklearn自带数据集,直接导入下载
from sklearn.linear_model import LogisticRegression


#导入数据集,并查看
iris=load_iris()

X = iris.data[:, :2]
Y = iris.target

lr = LogisticRegression(C=1e5)
lr.fit(X, Y)
# 生成两个网格矩阵
h = 0.02
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
 
# 预测
Z = lr.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
 
# 绘制
plt.figure(1, figsize=(8, 6))
plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
plt.scatter(X[:50, 0], X[:50, 1], color = 'red', marker = 'o', label = 'setosa')
plt.scatter(X[50:100, 0], X[50:100, 1], color = 'blue', marker = 'x', label = 'versicolor')
plt.scatter(X[100:, 0], X[100:, 1], color = 'green', marker = 's', label = 'Virginica')
 
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.xticks(())
plt.yticks(())
plt.legend(loc=2)
plt.show()

在这里插入图片描述

上面是用sklearn的做的,下面我们自己写代码来实现一下iris数据集和癌症数据集的分类

这里借鉴了两位大佬的代码
https://blog.csdn.net/juwikuang/article/details/90319273
https://blog.csdn.net/DwyanePeng/article/details/100534721

from sklearn.metrics import accuracy_score
 
class LogisticRegression(object):
    def __init__(self):
        """初始化Logistic Regression模型"""
        self.coef = None
        self.intercept = None
        self._theta = None
 
    def sigmoid(self, t):
        return 1. / (1. + np.exp(-t))
 
    def fit(self, X_train, y_train, alpha=0.01, n_iters=1e4):
        """使用梯度下降法训练LR模型"""
        assert  X_train.shape[0] == y_train.shape[0] #判断长度是否相等
 
        def J(theta, X_b, y):
            y_hat = self.sigmoid(X_b.dot(theta))
            try:
                return -np.sum(y * np.log(y_hat) + (1-y) * np.log(1 - y_hat))
            except:
                return float('inf')
 
        def dJ(theta, X_b, y):
            #求导后公式
            return X_b.T.dot(self.sigmoid(X_b.dot(theta)) - y) / len(y)
 
        def gradient_descent(X_b, y, initial_theta, alpha, n_iters=1e4, epsilon=1e-8):
            theta = initial_theta
            cur_iter = 0
 
            while cur_iter < n_iters:
                gradient = dJ(theta, X_b, y)
                last_theta = theta
                theta = theta - alpha * gradient
                if abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon:
                    break
                cur_iter += 1
            return theta
 
        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
        initial_theta = np.zeros(X_b.shape[1])
        self._theta = gradient_descent(X_b, y_train, initial_theta, alpha, n_iters)
 
        #截距
        self.intercept = self._theta[0]
        #x_i前的参数
        self.coef = self._theta[1:]
 
        return self
 
    def predict_proba(self, X_predict):
        """给定待预测数据集X_predict, 返回表示X_predict的结果概率向量"""
        assert self.intercept is not None and self.coef is not None
        assert X_predict.shape[1] == len(self.coef)
        X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
        return self.sigmoid(X_b.dot(self._theta))
 
    def predict(self, X_predict):
        """给定待预测数据集X_predict, 返回表示X_predict的结果向量"""
        assert self.intercept is not None and self.coef is not None
        assert X_predict.shape[1] == len(self.coef)
        prob = self.predict_proba(X_predict)
        return np.array(prob >= 0.5, dtype='int')
 
    def score(self, X_test, y_test):
        """根据测试数据集X_test和y_test确定当前模型的准确度"""
        y_predict = self.predict(X_test)
        return accuracy_score(y_test, y_predict)
 
    def __repr__(self):
        return "LogisticRegression()"

    
#取鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target
#筛选特征
X = X[y<2, :2]
y = y[y<2]

 
#切分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
 
#调用自己写的逻辑回归函数
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
k,b=log_reg.coef,log_reg.intercept

print("最后的模型得分为:%s" % log_reg.score(X_test, y_test))
print("最后的预测值为:", log_reg.predict_proba(X_test))


xx =np.linspace(4.0,8.5,10)
yy=-(b+k[0]*xx)/k[1]

#绘制图像
plt.figure()
plt.plot(xx,yy,'green')
plt.scatter(X[y == 0, 0], X[y == 0, 1], color="red")
plt.scatter(X[y == 1, 0], X[y == 1, 1], color="blue")
plt.show()

在这里插入图片描述

开始处理癌症数据集

#导入癌症数据集
dataset = sklearn.datasets.load_breast_cancer()
data = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
data['cancer'] = [dataset.target_names[t] for t in dataset.target]

#查看数据
data.info()
data.head()

在这里插入图片描述

#设置训练数据
X = dataset.data
y = dataset.target
n_features = X.shape[1]

#对数据归一化处理
std=X.std(axis=0)
mean=X.mean(axis=0)
X_norm = (X - mean) / std

def add_ones(X):
    ones=np.ones((X.shape[0],1))
    X_with_ones=np.hstack((ones, X))
    return X_with_ones

X_with_ones = add_ones(X_norm)


#sigmoid函数
def sigmoid(x):
    z=1.0/(1.0+np.exp(-x))
    z=z.reshape(z.shape[0],1)
    return z

#画出sigmoid函数的图像
x=np.arange(-10,10,0.1)
h=sigmoid(x)
plt.plot(x,h)
plt.axvline(0.0,color='k')
plt.axhline(y=0.5,ls='dotted',color='k')
plt.yticks([0.0,0.5,1.0])
plt.title(r'sigmoid函数曲线',fontsize=15)
plt.text(5,0.8,r'$y=\frac{1}{1+e^{-z}}$',fontsize=18)
plt.show()

在这里插入图片描述

#模型
def model(theta, X):
    z = np.sum(theta.T * X, axis=1)
    return sigmoid(z)

#cross_entropy
def cross_entropy(y, y_hat):
    n_samples = y.shape[0]
    return sum(-y*np.log(y_hat)-(1-y)*np.log(1-y_hat))/n_samples

#损失函数
def cost_function(theta, X, y):
    y_hat = model(theta, X)
    return cross_entropy(y, y_hat)

#优化函数
def optimize(theta,X,y):
    n = X.shape[0]
    alpha = 1e-1
    y_hat = model(theta,X)
    dtheta = (1.0/n) * ((y_hat-y)*X)
    dtheta = np.sum(dtheta, axis=0)
    dtheta=dtheta.reshape((31,1))
    theta = theta - alpha * dtheta
    return theta

#模型评估
def predict_proba(theta, X):
    y_hat=model(theta, X)
    return y_hat

def predict(X, theta):
    y_hat=predict_proba(theta,X)
    y_hard=(y_hat > 0.5) * 1
    return y_hard

def accuracy(theta, X, y):
    y_hard=predict(X, theta)
    count_right=sum(y_hard == y)
    return count_right*1.0/len(y)


#迭代
def iterate(theta,X,y,times):
    costs = []
    accs = []
    for i in range(times):
        theta = optimize(theta,X,y)
        costs.append(cost_function(theta, X, y))
        accs.append(accuracy(theta, X, y))

    return theta, costs, accs

X_train, X_test, y_train, y_test = train_test_split(X_with_ones, y, test_size = 0.3, random_state=12345)
y_train=y_train.reshape((y_train.shape[0],1))
y_test=y_test.reshape((y_test.shape[0],1))

theta = np.ones((n_features+1,1))
theta, costs, accs = iterate(theta, X_train, y_train, 1500)

plt.plot(costs)

在这里插入图片描述

print("模型最终损失率为:{},模型的准确率为:{}".format(costs[-1], accs[-1]))
print("测试集上的准确率为:",accuracy(theta, X_test, y_test))

模型最终损失率为:[0.0489982],模型的准确率为:[0.99246231]
测试集上的准确率为: [0.97660819]

结束

可以看出逻辑回归对于二分类的问题还是能得到比较高的准确率,那对于多分类呢?别急,以后还有很多其他分类算法呢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shelgi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值