【理论篇】实现逻辑回归与梯度下降(二)

连载的上一篇文章,我们实现了数据预处理与绘图的步骤。今天,小鱼将和大家一起实现逻辑回归的 4 个基础模块,为梯度下降策略做准备。

概率映射函数 sigmoid

Sigmoid 函数的公式为:

g(z) = \frac{1}{1+e^{-z}}

根据公式实现 sigmoid 方法:

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

Sigmode 函数的自变量取值为任意实数,值域为 [0,1] 。因此 Sigmode 函数可以将任意的值映射到 [0,1] 区间。我们在回归中得到的预测值,将其映射到 Sigmode 函数,即可完成由值到概率的转换,也就是分类任务。

  • g:\mathbb{R} \to [0,1]
  • g(0)=0.5
  • g(- \infty)=0
  • g(+ \infty)=1

使用上述实现的 sigmoid 函数绘图:

nums = np.linspace(-10, 10, 100)
fig,ax = plt.subplots(figsize=(12,4))
ax.plot(nums, sigmoid(nums))

Sigmoid 函数曲线如下:

计算预测值的模型 model

在线性回归中,我们使用特征参数和偏置项来计算预测值,其中,偏置项 θ₀ 可以视为 θ₀*1 ,即和一个恒为 1 的特征相乘。预测值的计算公式如下:

\begin{array}{ccc} \begin{pmatrix}\theta_{0} & \theta_{1} & \theta_{2}\end{pmatrix} & \times & \begin{pmatrix}1\\ x_{1}\\ x_{2} \end{pmatrix}\end{array}=\theta_{0}+\theta_{1}x_{1}+\theta_{2}x_{2}

使用 model 函数实现上述公式:

def model(X, theta):
    """返回预测结果值"""
    return sigmoid(np.dot(X, theta.T))

下面,我们来验证一下 model 函数的实现是否正确。首先,在 DataFrame 中第 0 列的位置插入名为 Ones 的全为 1 的新列,在计算预测值时,该列将和偏置项相乘:

df.insert(0, 'Ones', 1)
df.head()

接下来,定义特征矩阵 X ,真实值 y,以及特征参数 theta 。其中特征 X 为数据集中的前 3 列组成的 ndarray 数组:

>> orig_data = df.values
>> cols = orig_data.shape[1]
>> X = orig_data[:,0:cols-1]
>> X[:5]
array([[ 1.        , -1.60224763,  0.63834112],
       [ 1.        , -1.82625564, -1.2075414 ],
       [ 1.        , -1.53903969,  0.3612943 ],
       [ 1.        , -0.28210129,  1.0863683 ],
       [ 1.        ,  0.69152826,  0.49337794]])

真实值 y 为数据集中的最后一列,但必须是 2 维数组的形式,因此第二个维度也使用切片的形式定位:

>> y = orig_data[:,cols-1:cols]
>> y[:5]
array([[0.],
       [0.],
       [0.],
       [1.],
       [1.]])

特征参数 theta 在初始化时只需要定义为全 0 矩阵即可。注意:theta 必须为 2 维矩阵,并且第一个维度为 1 ,第二个维度的长度与特征的个数相等,此处为 3:

>> theta = np.zeros([1,3])
>> theta
array([[0., 0., 0.]])

X y theta 的形状:

>> X.shape, theta.shape, y.shape
((100, 3), (1, 3), (100, 1))

这样, Xtheta 的转置(3行1列)计算内积才可以得到 (100,1) 的预测值。

>> model(X, theta).shape
(100, 1)

计算平均损失 cost

在介绍逻辑回归时,我们推导出了如下的对数似然函数(负号表示梯度下降):

D(h_\theta(x), y) = -y\log(h_\theta(x)) - (1-y)\log(1-h_\theta(x))

求平均损失的公式就为:

J(\theta)=\frac{1}{n}\sum_{i=1}^{n} D(h_\theta(x_i), y_i)

下面,使用代码来实现上述公式:

def cost(X, y, theta):
    """根据参数计算平均损失"""
    left = np.multiply(-y, np.log(model(X, theta)))
    right = np.multiply(1-y, np.log(1-model(X, theta)))
    return np.sum(left-right) / len(X)

原始数据集使用默认参数的平均损失如下:

>> cost(X, y , theta)
0.6931471805599453

计算每个参数的梯度方向 gradient

梯度下降的关键步骤是在每个特征方向上求偏导,找到下山最快的方向。损失函数求偏导的公式如下:

\frac{\partial J}{\partial \theta_j}=-\frac{1}{m}\sum_{i=1}^m (y_i - h_\theta (x_i))x_{ij}

根据上述公式,实现计算梯度的函数 gradient

def gradient(X, y , theta):
    grad = np.zeros(theta.shape)
    error = (model(X, theta) - y).ravel()
    for i in range(len(theta.ravel())):
        term = np.multiply(error, X[:,i])
        grad[0, i] = np.sum(term) / len(X)
    return grad

上述求偏导的函数略显复杂,小鱼来为大家解释一下~

首先,因为我们要在每个特征方向上对 theta 求偏导,因此最终梯度的个数和特征参数的个数是一致的。故而使用 theta.shape 来初始化 gradient 数组:

grad = np.zeros(theta.shape)

在计算误差时,我们使用预测值 - 真实值,相当于将公式中的负号提到了括号里面。ravel 方法则可以将高位数组拉平,返回 1 维数组:

 error = (model(X, theta) - y).ravel()

最后,使用 for 循环计算每个特征参数的偏导数:

for i in range(len(theta.ravel())):
    term = np.multiply(error, X[:,i])
    grad[0, i] = np.sum(term) / len(X)

可以计算一下当前 theta 的梯度:

>> gradient(X, y, theta)
array([[-0.1       , -0.28122914, -0.25098615]])

有了梯度,下节我们就可以开始更新参数了:

即当前特征的参数 - 学习率 alpha * 当前特征参数对应的梯度。其中涉及到了学习率、每次迭代的样本个数以及梯度下降停止策略等,精彩内容下节奉上~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容