西瓜书3.3 尝试解题(python)对率回归 极大似然估计
数据如下:
x01=[0.697,0.774,0.634,0.608,0.556,0.403,0.481,0.437,0.666,\
0.243,0.245,0.343,0.639,0.657,0.360,0.593,0.719]
x02=[0.460,0.376,0.264,0.318,0.215,0.237,0.149,0.211,0.091,\
0.267,0.057,0.099,0.161,0.198,0.370,0.042,0.103]
y=[1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0]
x01表示密度,x02表示含糖率,y标志瓜的好坏(1为好,0为坏)
这道题的目的是实现对率回归,那么从3.3节看起。
可以看到我们要求的其实是一个系数序列ω和一个偏差b。简单看过对率回归的介绍后,直接来看推导过程。
将前面的3.19稍微改写一下就可以得到3.22,而由于又有p(y=1|x)+p(y=0|x)=1,所以可以得到3.23和3.24这样的式子。
3.19:ln(y/(1-y))=ωΤx+b
3.22:ln p(y=1|x)/p(y=0|x) =ωΤx+b
按照提示,跳到7.2查看极大似然估计。第一句话指出在估计参数前要假定其具有某种确定的概率分布形式,而在这一题中
我们的概率分布形式就是对率函数,使用极大似然估计就是根据已知的样本来估计参数,解释一下类条件概率指的是在
某种前提下发生某一事件的概率,则P(x|θc)的具体含义就是参数向量为θc时事件x的发生概率。需要厘清一下“概率”和“似然”的区别,
简单来讲概率就是在给定参数时事件发生的可能性,而似然就是在已知随机事件后、概率分布的参数为某一值的可能性(相对于其他
参数取值而言)。具体的解释指路大佬的博客:https://blog.csdn.net/songyu0120/article/details/85059149 讲得非常详尽易懂
而7.9告诉我们的就应当是,已知发生c类事件时,参数θ的值为θc的概率等于参数值为θc时每一个c类事件发生的概率的乘积,
理所当然的,对问题而言最合适的θc就是使7.9式等号右侧的值最大的那个。而7.10中的对数转换操作原理就是将乘法转化为加法,
从而有效防止下溢(超出数据类型所能表示的最小数字),而对数的转换也不会带来信息的损失。
再回到3.25就能看明白它的含义了:对于给定的数据集{(xi,yi)} i∈(1,m) 和一组参数集(ω,b),每个样本属于其真实标记的概率p
的累乘就是这组参数集的似然。而在式中使用了对数似然来防止下溢。
3.25到3.26的操作只是进行了符号的合并简化以及将两种情况的概率巧妙地分离开。
而将3.23与3.34的p1、p0式子代入3.26后,分类讨论y=0、y=1的情况而后观察,就可以把结果合并为3.27的形式,再取负就得到3.27。
因为取负了,所以本来我们要求的是式子的最大值现在变成求式子的最小值。书上应用的是牛顿法。
牛顿法,其核心思想就是泰勒展开。首先讲讲其在方程求解中的应用,然后理解其在最优化的应用会方便很多。
在求解方程的求根公式很复杂甚至没有求根公式时,可以利用牛顿法进行迭代求解,过程就是利用泰勒公式在x0处展开到
一阶,使f(x)=f(x0)+(x-x0)f'(x0)=0,求得一个x1使f(x)比较接近于0,显然,要是我们重复使用这个方法也就是迭代,我们就可以
得到更加准确的答案直到最后在f(x*)=0收敛。
在最优化问题中,如果我们要求一个函数的极大极小问题,显然可以转化为求解函数导数=0的问题,那么就可以使用牛顿法
在方程求解中的方法。因为要求一阶导数的结果等于0,所以对原函数进行两阶泰勒展开,得到
f(x+△x)=f(x+△x)+f'(x+△x)△x+f''(x+△x)△x²/2,两侧对△x求导,在△x无限趋近于0的时候,就可以忽略函数中的△x,从而得到
f'(x)+f''(x)△x=0。则△x=-f'(x)/f''(x)。把△x视作Xn+1(第n+1个迭代解)与Xn(第n个迭代解)的差值,我们就可以得到
迭代解的更新公式,Xn+1=Xn-f'(x)/f''(x)。用矩阵计算代换就可以得到3.29。其中一阶项和二阶项的计算方法都在后面给出,
那么我们只要使用编程实现就行了。
首先,为了方便起见我们要引入numpy这个库来进行矩阵计算,所以对于数据集我们要做一些改动:
x=np.array([[0.697,0.774,0.634,0.608,0.556,0.403,0.481,0.437,0.666,\
0.243,0.245,0.343,0.639,0.657,0.360,0.593,0.719],
[0.460,0.376,0.264,0.318,0.215,0.237,0.149,0.211,0.091,\
0.267,0.057,0.099,0.161,0.198,0.370,0.042,0.103],\
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]])
y=np.array([1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0])
before=np.array([[0],[0],[1]])
将x的数据合并并加入一行1,这个操作对应于3.25和3.26之间那段中的操作,before矩阵就是参数的数据集合,我们不妨设起始参数为0,0,1。
编写程序时要时刻记住x、y、before在书上推导过程中都是单列矩阵,但操作中我们的一些操作会使之变成行矩阵,在后续计算中要及时转置
回来。比如:
np.array([x[:,i]])
这样的操作,目的是从x中取出第i列作为一个单独矩阵,取出后默认是行矩阵,要及时转置。
清楚这点后着手编写各部分的代码。
首先是一阶导的计算:
def fd():
b1 = 0
for i in range(17):
k=np.exp(np.dot(before.T,np.array([x[:,i]]).T))
b1=b1-np.array([x[:,i]])*( y[i]-(k/(1+k)))
return b1
而后是二阶导的计算:
def sd():
b2 = 0
for i in range(17):
k = np.exp(np.dot(before.T,np.array([x[:,i]]).T))
b2=b2+np.dot(np.array([x[:,i]]).T,np.array([x[:,i]])) * (k/(1+k)) * (1-(k/(1+k)))
return b2
最后是主函数,偷个懒不追求最终结果是否收敛的话,限定一个迭代次数上限就完事:
k=1000
while(k):
k-=1
b1=fd()
b2=sd()
before=before-np.dot(linalg.inv(b2),b1.T) print(before)
如果要寻求更精确的结果,可以稍微修改主函数的内容:
mae=0
ima=0
n=0
while(1):
ima=0
for i in range(17):
k=np.dot(before.T,np.array([x[:,i]]).T)
ima=ima+(-y[i]*k+np.log(1+np.exp(k)))
if(np.abs(ima-mae)<=0.001):
break
mae=ima
n=n+1
b1=fd()
b2=sd()
before=before-np.dot(linalg.inv(b2),b1.T)
print('迭代次数:',n)
print('最终参数:',before)
其实就是每次计算出3.27式的值并且在和前次差值小于等于0.00001时退出并输出结果。
结果:
迭代次数: 4
最终参数: [[ 3.15832738]
[12.52119012]
[-4.42886222]]
完整代码:
import math
import numpy as np
from numpy import linalg x=np.array([[0.697,0.774,0.634,0.608,0.556,0.403,0.481,0.437,0.666,\
0.243,0.245,0.343,0.639,0.657,0.360,0.593,0.719],
[0.460,0.376,0.264,0.318,0.215,0.237,0.149,0.211,0.091,\
0.267,0.057,0.099,0.161,0.198,0.370,0.042,0.103],\
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]])
y=np.array([1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0])
before=np.array([[0],[0],[1]]) def fd():
b1 = 0
for i in range(17):
k=np.exp(np.dot(before.T,np.array([x[:,i]]).T))
b1=b1-np.array([x[:,i]])*( y[i]-(k/(1+k)))
return b1 def sd():
b2 = 0
for i in range(17):
k = np.exp(np.dot(before.T,np.array([x[:,i]]).T))
b2=b2+np.dot(np.array([x[:,i]]).T,np.array([x[:,i]])) * (k/(1+k)) * (1-(k/(1+k)))
return b2 mae=0
ima=0
n=0
while(1):
ima=0
for i in range(17):
k=np.dot(before.T,np.array([x[:,i]]).T)
ima=ima+(-y[i]*k+np.log(1+np.exp(k)))
if(np.abs(ima-mae)<=0.000001):
break
mae=ima
n=n+1
b1=fd() b2=sd()
before=before-np.dot(linalg.inv(b2),b1.T) print('迭代次数:',n)
print('最终参数:',before)
西瓜书3.3 尝试解题(python)对率回归 极大似然估计的更多相关文章
- python实现简单决策树(信息增益)——基于周志华的西瓜书数据
数据集如下: 色泽 根蒂 敲声 纹理 脐部 触感 好瓜 青绿 蜷缩 浊响 清晰 凹陷 硬滑 是 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 是 乌黑 蜷缩 浊响 清晰 凹陷 硬滑 是 青绿 蜷缩 沉闷 清晰 ...
- 决策树ID3原理及R语言python代码实现(西瓜书)
决策树ID3原理及R语言python代码实现(西瓜书) 摘要: 决策树是机器学习中一种非常常见的分类与回归方法,可以认为是if-else结构的规则.分类决策树是由节点和有向边组成的树形结构,节点表示特 ...
- 朴素贝叶斯python代码实现(西瓜书)
朴素贝叶斯python代码实现(西瓜书) 摘要: 朴素贝叶斯也是机器学习中一种非常常见的分类方法,对于二分类问题,并且数据集特征为离散型属性的时候, 使用起来非常的方便.原理简单,训练效率高,拟合效果 ...
- 孤荷凌寒自学python第五十九天尝试使用python来读访问远端MongoDb数据服务
孤荷凌寒自学python第五十九天尝试使用python来读访问远端MongoDb数据服务 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第五天.今天的感觉是,mongoDB数 ...
- 孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库
孤荷凌寒自学python第五十七天初次尝试使用python来连接远端MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第三天.感觉这个东西学习起来还是那么困 ...
- 孤荷凌寒自学python第五十二天初次尝试使用python读取Firebase数据库中记录
孤荷凌寒自学python第五十二天初次尝试使用python读取Firebase数据库中记录 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数 ...
- 孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库
孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数据库服 ...
- 周志华-机器学习西瓜书-第三章习题3.5 LDA
本文为周志华机器学习西瓜书第三章课后习题3.5答案,编程实现线性判别分析LDA,数据集为书本第89页的数据 首先介绍LDA算法流程: LDA的一个手工计算数学实例: 课后习题的代码: # coding ...
- LASSO回归与L1正则化 西瓜书
LASSO回归与L1正则化 西瓜书 2018年04月23日 19:29:57 BIT_666 阅读数 2968更多 分类专栏: 机器学习 机器学习数学原理 西瓜书 版权声明:本文为博主原创文章,遵 ...
- 决策树 机器学习,西瓜书p80 表4.2 使用信息增益生成决策树及后剪枝
使用信息增益构造决策树,完成后剪枝 目录 使用信息增益构造决策树,完成后剪枝 1 构造决策树 1 根结点的选择 色泽 信息增益 根蒂 信息增益 敲声 信息增益 纹理 信息增益 脐部 信息增益 触感 信 ...
随机推荐
- Postman中添加多个Cookie
在接口测试中,很多接口都是需要登录后才能获取到数据的.如何标识登录状态呢?有些app用token,有些app用Cookie.通过Fiddler抓包看到,我涯使用的是Cookie的方式,而且是有多个Co ...
- centos7.2下配置DNS服务器
https://baijiahao.baidu.com/s?id=1748980460185046641&wfr=spider&for=pc 1.安装bind(服务器) yum -y ...
- 微信小程序笔记_02
在微信小程序中使用Echarts组件 github源码地址:https://github.com/ecomfe/echarts-for-weixin gitcode源码地址:https://gitco ...
- 220205_问题解决_python批量创建变量及赋值
220205_问题解决_python批量创建变量及赋值 当想要创建大量 变量名 有规律的变量.并为其有规律的赋值时,可以使用exec() 函数. exec 执行储存在字符串或文件中的 Python 语 ...
- C++之split字符串分割
在C++中没有直接对应的split函数,字符串分割可借助以下方法实现: 1.借助strtok函数 函数原型:char * strtok (char *str, char * delim); 函数功能: ...
- ID生成器实现方式的优缺点比较以及最优的ID生成器原理剖析
引用:https://blog.csdn.net/luoyang_java/article/details/90679456 本文的重点主要是ID发号器相关的知识,介绍了雪花算法,以及他的基本原理和实 ...
- Java基于ssm师生实验课-实验室-实验设备预约系统源码
简介 java+ssm开发的实验课实验设备实验室预约系统,老师可预约实验设备和实验室,然后发布实验课和上传实验附件.学生可以报名实验课,也可以自己预约实验室(部分实验室对学生开放)做实验.学生做完实验 ...
- 暴雪、迪士尼大佬用什么画画?RayLink远控软件助力解锁远程创作
CG绘画从业者,如原画师.插画师.漫画家.设计师等,一定对数位板\数位屏不陌生,数位板\数位屏是完成CG绘画作品的重要绘图工具之一. 从画画小白到数字绘画大神,从0基础插画培训班学生到国际知名游戏.动 ...
- 【剑指Offer】【数组】顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1 ...
- c中遍历lua的表
//遍历lua表,index为表在栈中的位置 void traverse_table(lua_State* L, int index) { lua_pushnil(L); stack_dump(L); ...