中企动力 > 头条 > python中平方

网站性能检测评分

注:本网站页面html检测工具扫描网站中存在的基本问题,仅供参考。

python中平方

一文介绍机器学习中基本的数学符号 公司视频课程

img

孔寻云

关注

在机器学习中,你永远都绕不过数学符号。

通常,只要有一个代数项或一个方程符号看不懂,你就完全看不懂整个过程是怎么回事了。这种境况非常令人沮丧,尤其是对于那些正在成长中的机器学习初学者来说更是如此。

如果你能了解一些基本的数学符号以及相关的小技巧,那你就在看懂机器学习方法的论文或书籍描述上前进了一大步。

在本教程中,你将学到机器学习技术描述中遇到的基本数学符号。

在学完整个教程后,你会知道:

算术符号,包括若干种乘法、指数、平方根以及对数数列和集合符号,包括索引、求和以及集合关系5 种当你看不明白数学符号的时候可以采用的应急方法

让我们开始学习吧!

机器学习中的基本数学符号

教程概览

本教程分为 7 个部分,分别是:

1. 看不懂数学符号的沮丧

2. 算术符号

3. 希腊字母

4. 数列符号

5. 集合符号

6. 其他符号

7. 更多帮助资源

看不懂数学符号的沮丧

你在阅读机器学习算法的相关内容时会遇到一些数学符号。举例来说,这些符号可能会被用来:

描述一个算法描述数据的预处理描述结果描述测试工具描述含义

你可能在论文、教科书、博文以及其他地方看到这些描述。相关代数项常常会给出完整定义,但你还是会看到不少陌生的数学符号。我曾多次深受其苦,简直太令人感到挫败了!

在本教程中,你会复习到一些帮助你看懂机器学习方法描述的基本数学符号。

算术符号

在本节中,我们将重温一些基础算数中你不太熟悉的符号,以及毕业之后一些可能遗忘的概念。

简单算术

算术的基本符号你已很熟悉。例如:

加法:1 + 1 = 2减法:2 – 1 = 1乘法:2 x 2 = 4除法:2 / 2 = 1

大多数的数学运算都有一个对应的逆运算,进行相反的运算过程;比如,减法是加法的逆运算,而除法是乘法的逆运算。

代数

我们常希望用更抽象的方式来描述运算过程,以将其与具体的数据或运算区分开来。因此代数的运用随处可见:也就是用大写和/或小写字母来代表一个项,或者一个数学符号体系中的概念。用希腊字母来代替英文字母也是很常见的用法。数学中的每一个领域都可能有一些保留字母,这些字母都会代表一个特定的东西。尽管如此,代数中的项总应在描述中被定义一下,如果作者没有去定义,那是他的问题,不是你的错。

乘法符号

乘法是一个常见的符号,有几种记法。一般是用一个小小的「ⅹ」或者星号「*」来代表乘法:

c = a x bc = a * b

你有时也会看到用一个点来代表乘法,比如:

c = a . b

这个式子其实和下式是一样的意思:

c = a x b

或者你可能会看到运算符被省略,先前被定义的代数项之间没有符号也没有空格,比如:

c = ab

这还是一样的意思。

指数和平方根

指数就是一个数字的幂次。这个符号写作正常大小的原数(底数)以及一个上标数(指数),例如:

2^3

这个表达式的计算结果就是 3 个 2 连乘,或者说是 2 的立方:

2 x 2 x 2 = 8

求一个数的幂,就默认是求它的平方。

2^2 = 2 x 2 = 4

平方运算的效果可以用开方来逆转。开方在数学中是在被开方的数字上面加一个开方符号,这里简单起见,直接用「sqrt()」函数来表示了。

sqrt(4) = 2

式中,我们知道了指数的结果 4,以及指数的次数 2,我们想算出指数的底数。事实上,开方运算可以是任意次指数的逆运算,只是开方符号默认次数为 2,相当于在开方符号的前面有一个下标的 2。我们当然可以试着写出立方的逆运算,也就是开立方符号:

2^3 = 83 sqrt(8) = 2

对数和 e

当我们求 10 的整数次幂的时候,我们常称之为数量级。

10^2 = 10 x 10 or 100

对这个运算求逆的另一方法是求这个运算结果(100)以 10 为底数的对数;用符号来表达的话就写作 log10()。

log10(100) = 2

这里,我们已知指数的结果和底数,而要求指数的次数。这让我们在数量级上轻松地缩放。除此之外,由于计算机中使用二进制数学,求以 2 为底数的对数也是常用的运算。例如:

2^6 = 64log2(64) = 6

还有一个非常常见的对数是以自然底数 e 为底数的。符号 e 是一个专有符号,代表一个特殊的数字或者说一个称为欧拉数的常数。欧拉数是一个无限不循环小数,可以追溯到无穷的精度。

e = 2.71828...

求 e 的幂被称为自然指数函数:

e^2 = 7.38905...

求自然对数的运算就是这个运算的逆运算,记作 ln():

ln(7.38905...) = 2

忽略更多数学细节,自然指数和自然对数在数学中非常有用,因为它们能用来抽象地描述某一系统的持续增长,比如说复利这样的指数级增长体系。

希腊字母

希腊字母在数学中用来代表变量、常数、函数以及其他的概念。比如说,在统计学中我们用小写的希腊字母 mu 来代表平均值,而小写的希腊字母 sigma 表示标准差。在线性回归中,我们用小写字母 beta 来代表系数,诸如此类。学会所有希腊字母的大小写以及怎么念会带来极大的帮助。

希腊字母表。

维基百科词条「数学、科学及工程中的希腊字母」是个非常有用的使用指南(https://en.wikipedia.org/wiki/Greek_letters_used_in_mathematics,_science,_and_engineering),因为上面列出来了在数学和科学不同领域内每一个希腊字母的常见用法。

数列符号

机器学习中的符号常用来描述数列运算。一个数列可以是一列数据,或者代数项。

索引

读懂数列符号的关键是要弄明白数列中的索引符号。一般来说符号中会明确数列的起点和终点,比如从 1 到 n,这里的 n 是数列的长度。在数列中的项都会用一个诸如 i、j、k 的下标来作为索引,就像数组的符号一样。比如说,a_i 就是数列 a 中的第 i 个元素。如果数列是二维的,那就需要用到 2 个索引;比如:b_{i,j} 就是数列 b 的第 i 行, 第 j 列的元素。

数列运算

我们也可以对一个数列进行数学运算。有两类运算时常被用到,所以有专门的简写运算符来表示它们:累加和累乘。

数列累加

对一个数列的累加用大写的希腊符号 sigma 来表示,而累加的内容则用变量名来表示,同时在 sigma 符号的下面明确开始的索引(如 i=1),在 sigma 符号的上面明确结束的索引(如 n)。

Sigma i = 1, n a_i

这就是数列 a 的第一个元素到第 n 个元素的累加。

数列累乘

数列的累乘是用大写的希腊字母 pi 来表示的。而对累乘范围的描述方式与数列累加类似,开始的索引写在符号下面,结束的索引在符号上面。

Pi i = 1, n a_i

这就是数列 a 的第一个元素到第 n 个元素的累乘。

集合符号

一个集合就是一组互不相同的元素的整体。在定义机器学习中的一些代数项的时候我们可能会遇到集合符号。

数字集合

你最常见的集合是数字集合,比如说有的代数项会定义在整数集或实数集内。这些常见的数字集合包括:

所以自然数的集合: N所有整数的集合: Z所有实数的集合: R

当然还有很多其他的数字集合,你可以参考维基百科中的「特殊集合」词条。我们在定义代数项的时候常指的是实值或者实数,而不是浮点数。浮点数在计算机运算中实际上是离散的数字。

集合关系

在定义代数项的时候常会看到集合关系符号,集合关系符号看起来就像是一个大写的「E」一样。

1 a E R

这表示定义 a 属于 R 集,或者说 a 属于实数集。同样,也有许多集合运算符;常见的两个集合运算符包括:

并集, 就是把两个集合的元素都包含进来:A U B交集,就是只包括同时出现在两个集合中的元素:A ^

更多相关内容可以参考维基百科中的「集合」词条:https://en.wikipedia.org/wiki/Set_(mathematics)。

其他符号

本节中我会列出一些较常见的其他符号。一种常见的情况是我们会先抽象地定义一个方法,然后用单独的符号来重新定义一个具体的实现。比如,如果我们在估计一个变量 x,可以在 x 上加一些符号来代表这些估计,比如:

x-bar(x 上方有一横)x-prime(x 右上角有一小撇)x-hat(x 上方有一折线)

同一个符号在诸如数学的子领域或不同对象的语境下可能含义不同。比如说,|x|就是个很容易令人不解的符号,在不同的情况下可以指:

|x|: x 的绝对值.|x|: 向量 x 的长度.|x|: 集合 x 的势.

本教程只提及了基础的数学符号。有很多数学的子学科与机器学习更相关,需要更详细地复习一下。包括:

线性代数统计学概率论微积分

可能还有一些多变量分析和信息论的内容。

5 个在数学符号方面寻求帮助的小建议

本部分将列示一些当你被机器学习中的数学符号折磨时可以用到的小建议。

考虑一下作者

你在阅读的论文或者书籍总有一个作者。这个作者可能犯错,可能有疏忽,也可能是因为他们自己也不明白自己在写什么,才让你如此迷惑。从符号的限制中逃离片刻,然后想想作者的目的。他们到底想把什么讲清楚?也许你甚至可以用电子邮件、Twitter、Facebook、领英等方式来联系作者让他帮你解释清楚。你放心,大多数学者都希望其他人能够理解并好好利用他们的研究成果。

上维基百科查一查

维基百科上有符号列表,可以帮助你缩小符号含义的可能范围。我建议你从这两个词条开始:

「数学符号表」(https://en.wikipedia.org/wiki/List_of_mathematical_symbols)「数学、科学和工程中的希腊字母」(https://en.wikipedia.org/wiki/Greek_letters_used_in_mathematics,_science,_and_engineering)

用代码简述出来

数学运算不过就是对数据进行函数处理。把你读到的任何东西都用变量、for-循环等写成伪代码展示出来。这个过程中你可能打算使用某个脚本语言来处理自己随意写出来的数组,或者甚至一张 Excel 表格的数据。

当你阅读并理解了文章中的技术改进,那你随之写出来的核心代码才会取得更好的结果,最终经过不断的改进,你就会写出一个小小的原型机,可以自己玩耍了!我一度不相信这个方法行得通,直到看到一个学者仅用几行 MATLAB 代码和随意编写的数据就写出了一篇非常复杂的论文的核心代码。这令我大吃一惊,因为我以前一直坚信机器学习的系统必须完整地编写出来并且使用真实数据才能运行,所以要学习任何一篇文章只有找到原始的代码和数据这一条路可走。但是我真的错了。不过话说回来,那个学者真的是个天才。

现在我一直都在用这种方法学习机器学习,不过我是用 Python 写出新学到的技巧的核心代码。

换条路试试

有一个我在搞懂新技术时常用的小技巧,即找到所有引用了包含该技术的论文的其他论文,看看其他人如何演绎、解释这个新技术时常能够解除我在读原始描述产生的误解。不过这个办法不总是有效,反而会更加迷惑,引入了更多令人误解的方法和新符号。但是总体来说,这个办法还是有效的。

在网上向大神请教

说实话,有很多线上论坛里的人们很愿意向别人解释数学。你可以在屏幕上截张困扰你的符号图,写清楚出处和链接,然后连同你的困惑一起发布在问答网站上。推荐以下两个入门网站:

https://math.stackexchange/https://stats.stackexchange/

你都有哪些弄明白数学符号的小技巧呢?不妨在评论区留言。

推荐阅读

如果你想进一步深入了解,这一部分会告诉你更多相关资源。

Section 0.1. Reading Mathematics, Vector Calculus, Linear Algebra, and Differential Forms, 2009:http://math.cornell.edu/~hubbard/readingmath.pdfThe Language and Grammar of Mathematics, Timothy Gowers:http://assets.press.princeton.edu/chapters/gowers/gowers_I_2.pdfUnderstanding Mathematics, a guide, Peter Alfeld:https://math.stackexchange/

总结

在本教程中,你了解了在阅读机器学习相关技术时可能会遇到的基础数学符号。具体来说,你学到了:

算数符号,包括各种乘法、指数、平方根以及对数。数列和集合符号,包括索引、累加以及集合关系。5 个当你在理解数学符号遇到困难时可以帮到你的小技巧。

跟着Sutton经典教材学强化学习中的蒙特卡罗方法 推广视频课程

img

清秋节

关注

大数据文摘出品

作者:Ray Zhang

编译:halcyon、龙牧雪

用动态规划去解决强化学习的相关问题基本够了,但还是有很多限制。比如,你知道现实世界问题的状态转移概率吗?你能从任意状态随机开始吗?你的MDP是有限的吗?

好消息是,蒙特卡罗方法能解决以上问题!蒙特卡罗是一种估计复杂的概率分布的经典方法。本文部分内容取自Sutton的经典教材《强化学习》,并提供了额外的解释和例子。

初探蒙特卡罗

蒙特卡罗模拟以摩纳哥的著名赌场命名,因为机会和随机结果是建模技术的核心,它们与轮盘赌,骰子和老虎机等游戏非常相似。

相比于动态规划,蒙特卡罗方法以一种全新的方式看待问题,它提出了这个问题:我需要从环境中拿走多少样本去鉴别好的策略和坏的策略?

这一次,我们将再引入回报的概念,它是长期的预期收益:

有时,如果环节不收敛,那么我们使用折扣因子:

我们将这些回报Gt和可能的At联系起来试图推导出:

根据大数定律,当N逼近∞时,我们能够得到准确的期望。我们记i次模拟下标为i。

现在,如果这是一个马尔科夫决策过程(MDP)(99%的强化学习问题都是),那么我们知道它展现出了强马尔科夫性质,也即:

有了这些,我们可以很容易推导得到这样一个事实,即期望中的

是完全无关的,从现在开始,我们将使Gs指示从某个状态开始的回报(移动那个状态到t=0)。

解决值函数的一种经典方式是对第一次s的发生的回报进行采样,也叫首次访问蒙特卡罗预测。那么一个找到最优V的一个有效的算法如下:

pi=init_pi()returns=defaultdict(list)for i in range(NUM_ITER):episode=generate_episode(pi)#(1) G=np.zeros(|S|) prev_reward=0 for (state,reward) in reversed(episode): reward+=GAMMA*prev_reward #breaking up replaces s eventually, #so we get first-visit reward. G[s]=reward prev_reward=reward for state in STATES: returns[state].append(state) V={state:np.mean(ret) for state, ret in returns.items()}

另一种方法是每次访问蒙特卡罗预测,也就是你在每个环节中每一次发生s的回报都进行采样。在两种情况下,估计均成平方收敛于期望。

在蒙特卡罗方法的背景下,策略迭代的核心问题是,正如我们之前说过的,如何确保探索和开采?

一种补救大状态空间探索的方法是,明确我们从一个特定的状态开始并采取特定的行动,对所有可能性采用轮循方式对它们的回报采样。这假定我们可以从任何状态出发,在每一环节的开始采取所有可能的行动,这在很多情况下不是一个合理的假设。然而对于像21点纸牌游戏这样的问题,这是完全合理的,这意味着我们可以很容易地解决我们的问题。

在以下代码中,我们只需要对我们之前的代码(1)做一个快速的补丁:

# Before(Start at some arbitrary s_0,a_0)episode=generate_episode(pi)# After(Start at some specifics s,a)episode=generate_episode(pi,s,a)# loop through s, a at every iteration.

在线策略ε-贪婪策略

如果我们不能假设我们可以从任何状态开始并采取任意行动那怎么办呢?好吧,那么,只要我们不要太贪婪或者探索所有的状态无穷次,我们仍然可以保证收敛,对吗?

以上是在线策略方法的主要属性之一,在线策略方法试图去改善当前运行试验的策略,与此同时,离线策略方法试图改善一种不同于正在运行试验的策略的策略。

说到这里,我们要规则化“不要太贪婪”。一种简答的方法是使用我们之前学过的k臂老虎机-ε-贪婪方法。回顾一下,我们以ε的概率从一个给定状态下所有行动的均匀分布中挑选,以1-ε的概率我们选argmaxtq(s,a)行动。

现在我们问:对于蒙特卡罗方法,这是否收敛到最优π*?答案是它会收敛,但不是收敛到那个策略。

我们从q和一个ε-贪婪策略π(s)开始:

再一次,我们得到这个结论ε-贪婪策略,跟其他贪婪策略一样,对于Vπ执行单调的改进。如果我们回退到所有的时间步,那么我们得到:

这就是我们想要的收敛性。

然而,我们需要去发现这个策略实际上收敛到什么。显然,即使最优策略是确定性的,我们的策略也被迫是随机的,不能保证收敛到π*。然而,我们可以修订我们的问题:

假定不是我们的策略保持以概率ε的随机性一致选择行动,而是环境不管我们的策略的规定随机选择一个行动,那么,我们能够确保一个最优解。证明的大纲在(1)中显示,如果等式成立,那么我们π=π,因此我们有Vπ=Vπ于环境,这个等式在随机性下是最优的。

离线策略:重要性采样

让我们介绍一些新的术语!

π是我们的目标策略。我们正努力优化它的预期回报。b是我们的行为策略。我们使b产π以后会用到的数据。π(a|s)>0b(a|s)>0 a∈A。这是收敛的概念。

离线策略方法通常有2个或者多个智能体,其中一个智能体产生另一个智能体需要的数据,我们分别叫它们行为策略和目标策略。离线策略方法比在线策略方法更异想天开,就像神经网络之于线性模型更异想天开。离线策略方法往往更强大,其代价是产生更高的方差模型和较慢的收敛性。

现在,让我们讨论重要性采样。

重要性采样回答了这个问题:“给定Eπ[G],Eπ[G]是什么?”换句话说,你怎样使用从b的采样中获得的信息去决定π的期望结果。

一种你能想到的直观方法就是:“如果b选择a很多,π选a很多,那么b的行为对于决π的行为是很重要的!”,相反:“如果b选择a很多,π不曾选择a,那么b在a上的行为π在a上的行为没有什么重要性”,很有道理,对吧?

所以这差不多就知道重要性采样的比率是什么概念了。给定一个轨迹

,在给定策略π的条件下,这条准确的轨迹发生的概率为:

π和b之间的比率是:

普通的重要性采样

现在,有很多方法可以利用

给我们一个Eπ[G]的很好的估计。最基础的方法是利用普通的重要性采样。假定我们采样了N个环节:

定义S的第一次到达时间为:

我们想要估计Vπ(s),那么我们可以使用经验均值去通过首次访问方法估计值函数:

当然,这可以很容易地推广到每次访问方法,但是我想用最简单的形式来表达我的意思。这说明我们需要不同的方式来衡量每一环节的收益,因为对于π更容易发生的轨迹相比那些永远不会发生的需要赋予更多的权重。

这种重要性采样的方法是一种无偏估计量,但它存在极大的方差问题。假定第k个环节的重要性比率

是1000,这个数很大,但是确实可能发生。这是不是意味着奖励也要1000倍甚至更多呢?如果我们只有一个环节,我们的估计是准确的。从长远来看,因为我们有一个乘法关系,导致比率可能会爆炸式增长或者消失。这对于估计来说,有点令人担忧。

加权重要性采样

为了减小方差,一种简单直观的方法就是减少估计的大小,通过除以重要比率的大小的总和(有点像柔性最大激活函数):

这叫做加权重要性采样,它是一种有偏估计(偏差渐进趋于0),但是减小了方差。在此之前,我们能够得到一个普通估计量的病态无界方差,但是这里的每个元素的最大权值都是1,通过此限制了方差有界。Sutton建议,在实践中,总是使用加权重要性采样比较好。

增值实现

与许多其它采样技术一样,我们可以逐步实现它。假设我们使用上一节的加权重要性采样方法,那么我们可以得到一些如下形式的采样算法:

其中Wk可以是我们的权重。

我们想基于Nn来构造Nn+1,这是可行的。记Cn为

,我们会以如下方式持续更新这个计算和:

Cn的更新规则非常明显:

现在Vn是我们的值函数,但是一个非常相似的类比也可以应用到我们的行为Qn。

当我们更新值函数的时候,我们也能更新我们的策略π,我们能够用虽旧但是很好用argmaxtq(s,a)来更新π。

折扣意识重要性采样

到目前为止,我们已经计算了回报,并采样了回报得到了我们的估计。然而我们忽视了G的内部结构。它真的只是折扣奖励的求和,我们未能将它纳入到比率中ρ。折扣意识重要性采样将γ建模为终止的概率。环节的概率在一些时间步t终止,因此必须是一个几何分布geo(γ):

全部回报可以认为是对随机变量Rt求期望:

可以构造一个任意的裂项求和如下:

以此类推,我们可以看到,令k从x处开始,那么我们有γx

将上式代入G得到:

这将导致Rt项中的等效系数1,γ,γ2等。这就意味着,我们现在能够分解Gt,并且在重要性采样比率中使用折扣。

现在,回忆我们之前得到的:

如果我们扩展G,我们会有:

注意我们是怎样在所有的回报中使用相同的比率的。一些回报,Gt.t+1,被整个轨迹的重要性比率相乘,这在模型假设:γ是终止概率下是不正确的。直观上,我们想要给Gt.t+1Pt.t+1,这很容易:

啊,好多了!这样,每个部分回报都有他们正确的比率,这极大解决了无界方差问题。

单个奖励重要性采样

另一种缓解p和它的方差问题的方式,我们可以将G分解为各个奖励,然后做一些分析,让我们研究一下Pt.T-1Gt.T:

对于每一项,我们有Pt.T-1γkRt+k+1。扩展p,我们发现:

在没有常数γk的情况下求期望:

记住E(AB)=E(A)E(B)当且仅当它们是独立的。显然根据马尔科夫性质,任意π(Ai|Si)和b(Ai|Si)都是独立于Rt+k+1,(如果i≥t+k+1),且

(b也一样)。由此我们能够将它们分离出来,从而得到:

这个式子看起来也许非常丑,但是我们发现:

所以我们可以完全忽略后半部分,从而得到:

这是什么意思呢?我们完全可以用期望来表示最初的和:

这又一次将减少我们估计量的偏差。

Python中的在线策略模型

因为蒙特卡罗方法通常都是相似的结构。我在Python中创建了一个离散蒙特卡罗类,可以用来插入和运行。

代码下载:

https://github/OneRaynyDay/MonteCarloEngine

"""General purpose Monte Carlo model for training on-policy methods."""from copy import deepcopyimport numpy as npclass FiniteMCModel:def __init__(self, state_space, action_space, gamma=1.0, epsilon=0.1): """MCModel takes in state_space and action_space (finite) Arguments --------- state_space: int OR list[observation], where observation is any hashable type from env's obs. action_space: int OR list[action], where action is any hashable type from env's actions. gamma: float, discounting factor. epsilon: float, epsilon-greedy parameter. If the parameter is an int, then we generate a list, and otherwise we generate a dictionary. >>> m = FiniteMCModel(2,3,epsilon=0) >>> m.Q [[0, 0, 0], [0, 0, 0]] >>> m.Q[0][1] = 1 >>> m.Q [[0, 1, 0], [0, 0, 0]] >>> m.pi(1, 0) 1 >>> m.pi(1, 1) 0 >>> d = m.generate_returns([(0,0,0), (0,1,1), (1,0,1)]) >>> assert(d == {(1, 0): 1, (0, 1): 2, (0, 0): 2}) >>> m.choose_action(m.pi, 1) 0 """ self.gamma = gamma self.epsilon = epsilon self.Q = None if isinstance(action_space, int): self.action_space = np.arange(action_space) actions = [0]*action_space # Action representation self._act_rep = "list" else: self.action_space = action_space actions = {k:0 for k in action_space} self._act_rep = "dict" if isinstance(state_space, int): self.state_space = np.arange(state_space) self.Q = [deepcopy(actions) for _ in range(state_space)] else: self.state_space = state_space self.Q = {k:deepcopy(actions) for k in state_space} # Frequency of state/action. self.Ql = deepcopy(self.Q) def pi(self, action, state): """pi(a,s,A,V) := pi(a|s) We take the argmax_a of Q(s,a). q[s] = [q(s,0), q(s,1), ...] """ if self._act_rep == "list": if action == np.argmax(self.Q[state]): return 1 return 0 elif self._act_rep == "dict": if action == max(self.Q[state], key=self.Q[state].get): return 1 return 0 def b(self, action, state): """b(a,s,A) := b(a|s) Sometimes you can only use a subset of the action space given the state. Randomly selects an action from a uniform distribution. """ return self.epsilon/len(self.action_space) + (1-self.epsilon) * self.pi(action, state) def generate_returns(self, ep): """Backup on returns per time period in an epoch Arguments --------- ep: [(observation, action, reward)], an episode trajectory in chronological order. """ G = {} # return on state ...

如何利用自然语言处理构建基于内容的电影推荐系统 推广视频课程

img

假象

关注

本文来自阿里云云栖社区,未经许可禁止转载。

更多资讯,尽在云栖科技快讯~

来科技快讯看新闻鸭~

快点关注我认识我爱上我啊~~~

摘要: 本文教你如何构建属于你自己的推荐系统,不容错过。

“empty brown theater chairs” by Tyler Callahan on Unsplash

你是否有过这样的疑惑:为什么Netflix,Amazon,Google总能推荐到你比较感兴趣的产品?我们有时会对互联网上的产品进行评分,以此体现我们对产品的偏好,同时,推荐系统会利用我们分享的数据,生成推荐结果。主流的推荐系统算法大致分为两类:基于用户历史数据的协同过滤算法和基于内容数据的过滤算法。两者的区别其实从名称上便可看出,但接下来我们将以电影推荐为例进一步阐述二者之间的不同。

协同过滤(Collaborative filters)

协同过滤依赖用户的历史评分数据,为用户推荐自己未曾看过,而与自己相似的用户已经观看过的电影。为了确定两个用户之间是否相似,协同过滤会结合用户所看过的电影以及他们对电影的评分。

Collaborative-based filter.

协同过滤算法的准确性依赖于用户对产品的历史评分,但并非所有的用户都会持续不断的对产品进行评价,有一些用户甚至未曾评价过任何产品。协同过滤算法的另一个特点是能提供多样化的建议,根据应用场景的不同,对推荐系统的评价也不尽相同。举个例子,假设用户A非常喜欢反乌托邦电影和黑色喜剧,用户B也喜欢反乌托邦电影,但从来没有看过黑色喜剧。协同过滤算法将根据用户A和用户B对反乌托邦电影的喜爱,为用户B推荐黑色喜剧。这个推荐结果将会产生两种影响:用户B也非常喜欢黑色喜剧,则推荐成功;如若用户B喜欢轻喜剧,那么推荐是不成功的。

基于内容的过滤(Content-based filters)

Content-based filter.

基于内容的推荐不再涉及其他用户,只根据我们自身的喜爱,简单的选择内容相似的项目进行推荐。

相比协同过滤算法,基于内容的推荐减少了推荐的多样性,但用户是否对项目进行了评分便不再影响推荐结果。还是前一个例子,也许用户B潜意识里也喜欢黑色喜剧,但除非他自己决定主动尝试,否则他永远也不会知道自己的这个喜好,因为基于内容的推荐只会继续推荐反乌托邦或同种类型的电影。以电影为例,在计算相似度的时候,除了考虑片名,还可以考虑导演,主要演员等因素。

到目前为止,我已多次提及到相似度(similarity)这个词,但是它究竟是什么呢?相似度是我们在计算用户之间或者项目之间的相似性时可以使用的度量标准之一。它虽然不可量化,但却是可以通过计算得到。在构建基于内容的推荐系统之前,我将简明地对相似度的概念做一个讲解。

余弦相似度(Cosine similarity)

向量可以是二维,三维甚至n维的。让我们以二维向量为例回顾一下点积(dot product)。两个向量之间的点积等于其中一个向量在另一个向量上的投影。因此,两个相同向量(即相同分量)之间的点积等于该向量模的平方,而如果这两个向量垂直,则点积为零。通常,对于n维向量,点积的计算公式如下所示。

Dot product.

点积在计算相似度时非常重要,因为它与相似度直接相关。两个向量u和v之间相似度是由它们之间的点积和它们自身的模的比值定义的。

Similarity.

透过相似度的定义我们可以看出,如果两个向量相同,相似度为1,如果两个向量是正交的,相似度为0。换句话说,相似度是一个在0和1之间有界的数,它反应了这两个向量的相似程度。

下面进入实战阶段。

1. 数据收集

实验数据来自IMDB数据集,本次只选取了前250个高评分电影。数据集列表有250行(250部电影),38列。在构建模型的时候,我们只考虑了电影导演、主要演员、电影类型和电影情节这几类特征。

部分数据如下图所示:

我们将每一部包含上述特征的电影作为一列,以便能更好的进行向量化。我们还会使用到自然语言处理,将文字转换为向量能帮助我们更好的计算余弦相似度。

接下来,我们将对数据进行清洗。

2. 数据清洗(Data cleaning)

nltk(natural language toolkit)是一套基于python的自然语言处理工具集,它能够帮助我们从文本中提取关键字,甚至可以为每个字打分。我们将使用Rake功能从Plot列中提取出关键字,相较于使用完整的句子对电影情节进行描述,我更青睐于使用一些与电影情节最相关的词语。为此,我在Plot列中,对每行都使用了Rake功能,将获取到的关键词独立作为新的一列,命名Key_words。

除了Plot列,还需要对其余列的数据进行清洗。同时,为了避免重复,需要对所有的内容进行小写转换,并且将所有的名和姓合并到一个单词中。试想:如果电影A的导演是Danny Boyle,而电影B的主要演员是Danny DeVito,那么电影A和B会因为Danny而拥有较高的相似度,但这并不是我们想要的。

在进行了所有的清理和合并之后,我将索引重新分配到movie title列,下图是为向量化准备的Dataframe。

3. 建模(Modeling)

为了充分利用NLP挖掘电影之间的相似性,我们需要将文字转为词向量。我更倾向于使用CountVecorizer而非TfIdfVecorizer,因为我只需要一个简单的频率计数器来统计bag_of_words列中的每个单词。Tf-Idf认为字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。这不适用于我们今天所讲的应用场景,毕竟每个单词对于相似度的衡量都非常重要。一旦我们得到了包含每个单词计数的矩阵,便可应用cosine_similarity函数对相似度进行计算。

相似度矩阵如下图所示:

Similarity matrix.

对角线上的值都为1,因为每部电影在和自己比较时是完全相似的。同时,这是一个对称矩阵,因为电影A和B与电影B与A之间的相似度是相同的。

接下来,我们将电影标题作为输入,返回前10个类似的电影作为推荐结果。此外,我们还给电影标题加上了数字索引,以匹配相似矩阵到实际电影标题的索引。实际上,函数一旦接收到输入,就会检测出与所输入的电影相对应的行中最大的10个数字,获取相应的索引并将其与电影标题系列匹配,以返回推荐的电影列表。当函数选取10个最高的相似度值时,丢弃了单位值,这样就不会返回与输入相同的电影标题。

4. 推荐系统测试(Testing the recommender)

由于我们只是用了包含250部电影的数据集,所构建的推荐系统性能有限。在测试的时候,输入了我喜爱的电影“Fargo”,下图为推荐的前10部电影。

Movies recommended because I like Fargo.

我对推荐结果是满意的,从导演和情节上可以看出它们与我喜爱的电影有一些相似之处。上面列表中有我已经看过的电影,我喜欢它们就像我喜欢“Fargo”一样,接下来我会去看列表中我还没有看过的那几部电影。

机器学习大牛最常用的5个回归损失函数,你知道几个? 企业视频课程

img

雷雷

关注

大数据文摘出品

编译:Apricock、睡不着的iris、JonyKai、钱天培

“损失函数”是机器学习优化中至关重要的一部分。L1、L2损失函数相信大多数人都早已不陌生。那你了解Huber损失、Log-Cosh损失、以及常用于计算预测区间的分位数损失么?这些可都是机器学习大牛最常用的回归损失函数哦!

机器学习中所有的算法都需要最大化或最小化一个函数,这个函数被称为“目标函数”。其中,我们一般把最小化的一类函数,称为“损失函数”。它能根据预测结果,衡量出模型预测能力的好坏。

在实际应用中,选取损失函数会受到诸多因素的制约,比如是否有异常值、机器学习算法的选择、梯度下降的时间复杂度、求导的难易程度以及预测值的置信度等等。因此,不存在一种损失函数适用于处理所有类型的数据。这篇文章就讲介绍不同种类的损失函数以及它们的作用。

损失函数大致可分为两类:分类问题的损失函数和回归问题的损失函数。在这篇文章中,我将着重介绍回归损失。

本文出现的代码和图表我们都妥妥保存在这儿了:

https://nbviewer.jupyter.org/github/groverpr/Machine-Learning/blob/master/notebooks/05_Loss_Functions.ipynb

分类、回归问题损失函数对比

均方误差

均方误差(MSE)是最常用的回归损失函数,计算方法是求预测值与真实值之间距离的平方和,公式如图。

下图是MSE函数的图像,其中目标值是100,预测值的范围从-10000到10000,Y轴代表的MSE取值范围是从0到正无穷,并且在预测值为100处达到最小。

MSE损失(Y轴)-预测值(X轴)

平均绝对值误差(也称L1损失)

平均绝对误差(MAE)是另一种用于回归模型的损失函数。MAE是目标值和预测值之差的绝对值之和。其只衡量了预测值误差的平均模长,而不考虑方向,取值范围也是从0到正无穷(如果考虑方向,则是残差/误差的总和——平均偏差(MBE))。

MAE损失(Y轴)-预测值(X轴)

MSE(L2损失)与MAE(L1损失)的比较

简单来说,MSE计算简便,但MAE对异常点有更好的鲁棒性。下面就来介绍导致二者差异的原因。

训练一个机器学习模型时,我们的目标就是找到损失函数达到极小值的点。当预测值等于真实值时,这两种函数都能达到最小。

下面是这两种损失函数的python代码。你可以自己编写函数,也可以使用sklearn内置的函数。

# true: Array of true target variable# pred: Array of predictionsdef mse(true, pred):return np.sum((true - pred)**2)def mae(true, pred):return np.sum(np.abs(true - pred))# also available in sklearnfrom sklearn.metrics import mean_squared_errorfrom sklearn.metrics import mean_absolute_error

下面让我们观察MAE和RMSE(即MSE的平方根,同MAE在同一量级中)在两个例子中的计算结果。第一个例子中,预测值和真实值很接近,而且误差的方差也较小。第二个例子中,因为存在一个异常点,而导致误差非常大。

左图:误差比较接近 右图:有一个误差远大于其他误差

从图中可以知道什么?应当如何选择损失函数?

MSE对误差取了平方(令e=真实值-预测值),因此若e>1,则MSE会进一步增大误差。如果数据中存在异常点,那么e值就会很大,而e则会远大于|e|。

因此,相对于使用MAE计算损失,使用MSE的模型会赋予异常点更大的权重。在第二个例子中,用RMSE计算损失的模型会以牺牲了其他样本的误差为代价,朝着减小异常点误差的方向更新。然而这就会降低模型的整体性能。

如果训练数据被异常点所污染,那么MAE损失就更好用(比如,在训练数据中存在大量错误的反例和正例标记,但是在测试集中没有这个问题)。

直观上可以这样理解:如果我们最小化MSE来对所有的样本点只给出一个预测值,那么这个值一定是所有目标值的平均值。但如果是最小化MAE,那么这个值,则会是所有样本点目标值的中位数。众所周知,对异常值而言,中位数比均值更加鲁棒,因此MAE对于异常值也比MSE更稳定。

然而MAE存在一个严重的问题(特别是对于神经网络):更新的梯度始终相同,也就是说,即使对于很小的损失值,梯度也很大。这样不利于模型的学习。为了解决这个缺陷,我们可以使用变化的学习率,在损失接近最小值时降低学习率。

而MSE在这种情况下的表现就很好,即便使用固定的学习率也可以有效收敛。MSE损失的梯度随损失增大而增大,而损失趋于0时则会减小。这使得在训练结束时,使用MSE模型的结果会更精确。

根据不同情况选择损失函数

如果异常点代表在商业中很重要的异常情况,并且需要被检测出来,则应选用MSE损失函数。相反,如果只把异常值当作受损数据,则应选用MAE损失函数。

推荐大家读一下这篇文章,文中比较了分别使用L1、L2损失的回归模型在有无异常值时的表现。

文章网址:

http://rishy.github.io/ml/2015/07/28/l1-vs-l2-loss/

这里L1损失和L2损失只是MAE和MSE的别称。

总而言之,处理异常点时,L1损失函数更稳定,但它的导数不连续,因此求解效率较低。L2损失函数对异常点更敏感,但通过令其导数为0,可以得到更稳定的封闭解。

二者兼有的问题是:在某些情况下,上述两种损失函数都不能满足需求。例如,若数据中90%的样本对应的目标值为150,剩下10%在0到30之间。那么使用MAE作为损失函数的模型可能会忽视10%的异常点,而对所有样本的预测值都为150。

这是因为模型会按中位数来预测。而使用MSE的模型则会给出很多介于0到30的预测值,因为模型会向异常点偏移。上述两种结果在许多商业场景中都是不可取的。

这些情况下应该怎么办呢?最简单的办法是对目标变量进行变换。而另一种办法则是换一个损失函数,这就引出了下面要讲的第三种损失函数,即Huber损失函数。

Huber损失,平滑的平均绝对误差

Huber损失对数据中的异常点没有平方误差损失那么敏感。它在0也可微分。本质上,Huber损失是绝对误差,只是在误差很小时,就变为平方误差。误差降到多小时变为二次误差由超参数δ(delta)来控制。当Huber损失在[0-δ,0+δ]之间时,等价为MSE,而在[-∞,δ]和[δ,+∞]时为MAE。

Huber损失(Y轴)与预测值(X轴)图示。真值取0

这里超参数delta的选择非常重要,因为这决定了你对与异常点的定义。当残差大于delta,应当采用L1(对较大的异常值不那么敏感)来最小化,而残差小于超参数,则用L2来最小化。

为何要使用Huber损失?

使用MAE训练神经网络最大的一个问题就是不变的大梯度,这可能导致在使用梯度下降快要结束时,错过了最小点。而对于MSE,梯度会随着损失的减小而减小,使结果更加精确。

在这种情况下,Huber损失就非常有用。它会由于梯度的减小而落在最小值附近。比起MSE,它对异常点更加鲁棒。因此,Huber损失结合了MSE和MAE的优点。但是,Huber损失的问题是我们可能需要不断调整超参数delta。

Log-Cosh损失

Log-cosh是另一种应用于回归问题中的,且比L2更平滑的的损失函数。它的计算方式是预测误差的双曲余弦的对数。

Log-cosh损失(Y轴)与预测值(X轴)图示。真值取0

优点:对于较小的x,log(cosh(x))近似等于(x^2)/2,对于较大的x,近似等于abs(x)-log(2)。这意味着‘logcosh’基本类似于均方误差,但不易受到异常点的影响。它具有Huber损失所有的优点,但不同于Huber损失的是,Log-cosh二阶处处可微。

为什么需要二阶导数?许多机器学习模型如XGBoost,就是采用牛顿法来寻找最优点。而牛顿法就需要求解二阶导数(Hessian)。因此对于诸如XGBoost这类机器学习框架,损失函数的二阶可微是很有必要的。

XgBoost中使用的目标函数。注意对一阶和二阶导数的依赖性

但Log-cosh损失也并非完美,其仍存在某些问题。比如误差很大的话,一阶梯度和Hessian会变成定值,这就导致XGBoost出现缺少分裂点的情况。

Huber和Log-cosh损失函数的Python代码:

# huber lossdef huber(true, pred, delta):loss = np.where(np.abs(true-pred) < delta , 0.5*((true-pred)**2), delta*np.abs(true - pred) - 0.5*(delta**2))return np.sum(loss)# logcosh lossdef logcosh(true, pred): loss = np.log(np.cosh(pred - true))return np.sum(loss)

分位数损失

在大多数现实世界预测问题中,我们通常希望了解预测中的不确定性。清楚预测的范围而非仅是估计点,对许多商业问题的决策很有帮助。

当我们更关注区间预测而不仅是点预测时,分位数损失函数就很有用。使用最小二乘回归进行区间预测,基于的假设是残差(y-y_hat)是独立变量,且方差保持不变。

一旦违背了这条假设,那么线性回归模型就不成立。但是我们也不能因此就认为使用非线性函数或基于树的模型更好,而放弃将线性回归模型作为基线方法。这时,分位数损失和分位数回归就派上用场了,因为即便对于具有变化方差或非正态分布的残差,基于分位数损失的回归也能给出合理的预测区间。

下面让我们看一个实际的例子,以便更好地理解基于分位数损失的回归是如何对异方差数据起作用的。

分位数回归与最小二乘回归

左:b/wX1和Y为线性关系。具有恒定的残差方差。右:b/wX2和Y为线性关系,但Y的方差随着X2增加。(异方差)

橙线表示两种情况下OLS的估值

分位数回归。虚线表示基于0.05和0.95分位数损失函数的回归

附上图中所示分位数回归的代码:

https://github/groverpr/Machine-Learning/blob/master/notebooks/09_Quantile_Regression.ipynb

理解分位数损失函数

如何选取合适的分位值取决于我们对正误差和反误差的重视程度。损失函数通过分位值(γ)对高估和低估给予不同的惩罚。例如,当分位数损失函数γ=0.25时,对高估的惩罚更大,使得预测值略低于中值。

γ是所需的分位数,其值介于0和1之间。

分位数损失(Y轴)与预测值(X轴)图示。Y的真值为0

这个损失函数也可以在神经网络或基于树的模型中计算预测区间。以下是用Sklearn实现梯度提升树回归模型的示例。

使用分位数损失(梯度提升回归器)预测区间

上图表明:在sklearn库的梯度提升回归中使用分位数损失可以得到90%的预测区间。其中上限为γ=0.95,下限为γ=0.05。

对比研究

为了证明上述所有损失函数的特点,让我们来一起看一个对比研究。首先,我们建立了一个从sinc(x)函数中采样得到的数据集,并引入了两项人为噪声:高斯噪声分量εN(0,σ2)和脉冲噪声分量ξBern(p)。

加入脉冲噪声是为了说明模型的鲁棒效果。以下是使用不同损失函数拟合GBM回归器的结果。

连续损失函数:(A)MSE损失函数;(B)MAE损失函数;(C)Huber损失函数;(D)分位数损失函数。将一个平滑的GBM拟合成有噪声的sinc(x)数据的示例:(E)原始sinc(x)函数;(F)具有MSE和MAE损失的平滑GBM;(G)具有Huber损失的平滑GBM,且δ={4,2,1};(H)具有分位数损失的平滑的GBM,且α={0.5,0.1,0.9}。

仿真对比的一些观察结果:

MAE损失模型的预测结果受脉冲噪声的影响较小,而MSE损失函数的预测结果受此影响略有偏移。Huber损失模型预测结果对所选超参数不敏感。分位数损失模型在合适的置信水平下能给出很好的估计。

最后,让我们将所有损失函数都放进一张图,我们就得到了下面这张漂亮的图片!它们的区别是不是一目了然了呢~

一个完整的机器学习项目在Python中的演练(二) 公司视频课程

img

布鞋

关注

译者 | 磐石

出品 | 磐创AI技术团队

【磐创AI导读】:本文主要介绍了本系列的第三项特征工程与特征选择。欢迎大家关注我们的公众号:磐创AI。

大家往往会选择一本数据科学相关书籍或者完成一门在线课程来学习和掌握机器学习。但是,实际情况往往是,学完之后反而并不清楚这些技术怎样才能被用在实际的项目流程中。就像你的脑海中已经有了一块块”拼图“(机器学习技术),你却不知道如何讲他们拼起来应用在实际的项目中。如果你也遇见过同样的问题,那么这篇文章应该是你想要的。本系列文章将介绍一个针对真实世界实际数据集的完整机器学习解决方案,让您了解所有部分如何结合在一起。

本系列文章按照一般机器学习工作流程逐步进行:

1. 数据清洗与格式处理

2. 探索性数据分析

3. 特征工程和特征选取

4. 机器学习模型性能指标评估

5. 微调最佳模型(超参数)

6. 在测试集上评估最佳模型

7. 解释模型结果

8. 总结分析

通过完成所有流程,我们将看到每个步骤之间是怎么联系起来的,以及如何在Python中专门实现每个部分。该项目可在GitHub上可以找到,附实现过程。第二篇文章将详细介绍第三个步骤,其余的内容将在后面的文章中介绍。

特征工程和特征选择

特征工程和特征选择虽然是完成机器学习项目中很小的一个环节,但它模型最终的表现至关重要。在特征工程与特征选择阶段做的工作都会准时在模型的表现上得以体现。首先,让我们来了解一下这两项任务是什么:

特征工程:特征工程是一项获取原始数据并提取或创建新特征的过程。也就是说可能需要对变量进行转换。例如通过取自然对数、取平方根或者对分类变量进行独热(one-hot)编码的方式以便它们可以在模型中更好的得以利用。通常来说,特征工程就是通过对原始数据的一些操作构建额外有效特征的过程。(详细介绍可参考:https://machinelearningmastery/discover-feature-engineering-how-to-engineer-features-and-how-to-get-good-at-it/)特征选择:特征选择是一项选择数据中与任务最相关的特征的过程。在特征选择的过程中,我们通过删除无效或重复的数据特征以帮助模型更好地学习和总结数据特征并创建更具可解释性的模型。通常来说,特征选择更多的是对特征做减法,只留下那些相对重要的特征。(详细介绍可参考:https://machinelearningmastery/an-introduction-to-feature-selection/)

因为机器学习模型只能从我们提供的数据中学习特征,所以确保数据包含我们任务的所有相关信息至关重要。如果我们没有给模型提供正确的数据,那么机器学习模型将不会达到我们所期望的表现。

在本项目中,我们将按照以下步骤完成特征工程:

独热(one-hot)编码分类变量(borough和 property use type)对数值变量做自然对数转换并作为新特征添加到原始数据中

独热(one-hot)编码对于在模型训练中包含分类变量是必要的。例如:机器学习算法无法理解“办公室”这种建筑类型,因此如果建筑物是办公室,则必须对其进行将其记录为1,否则将其记录为0。

添加转换的特征可以使我们的模型学习到数据中的非线性关系。取平方根、取自然对数或各种各样的数值转换是数据科学中特征转换的常见做法,并通过领域知识或在多次实践中发现最有效的方法。这里我们将对所有数值特征取自然对数并添加到原始数据中。

下面的代码实现了数值特征选择并对这些特征进行了取对数操作,选择两个分类变量并对这些特征进行独热(one-hot)编码、然后将两列特征连接在一起。这一系列操作可以通过pandas库很快捷的实现。

完成上述操作之后,我们有110列(features)、总共超过11,000个对象(buildings)。但是,这些特征并非所有都能够对预测能源之星得分(ENERGY STAR Score)有用,所以接下来我们将通过特征选择去除一些变量。

特征选择

在上面做特征工程的过程之后得到的数据中的110列特征,许多都是多余或重复的,因为它们彼此高度相关。

例如,下图是Site EUI与Weather Norm EUI相关系数为0.997的情况。

那些相互之间有很强关联性的特征被称为共线(collinear)https://en.wikipedia.org/wiki/Multicollinearity,而且消除这些“特征对”中的一个变量通常可以使机器学习模型更鲁棒并且具有更强的可解释性。(需要注意的一点是,现在是在讨论特征与其他特征的相关性,而不是与目标的相关性。)

有许多方法可以计算特征之间的共线性(collinearity),其中最常见的是方差膨胀因子(VIF)。在本项目中,我们将使用相关系数来识别和删除共线特征。如果它们之间的相关系数大于0.6,我们将放弃一对特征中的一个。

也许你会认为这个值(0.6)是随便定义的,其实并不是,而是通过多次尝试不同的阈值比较后得到的。使用0.6这个值可以产生了最好的模型。机器学习是一个经验性领域,通常是通过试验发现性能最好参数组合。选择特征后,我们剩下64列特征和1列目标特征(能源之星得分)。

建立基线

我们现在已经完成了数据清洗,探索性数据分析和特征工程,开始建立模型之前还需要做最后一步:建立一个初步的基线(baseline)。这实际上是设置一项可以用来核对我们最终模型的实际表现的预估表现。我们可以通过拿最终模型表现与预估模型表现做比较反过来评测此次项目的整体思路。如果机器学习模型的最终表现没有超越我们的预估表现,那么我们可能不得不得出如下结论:

使用机器学习的方法无法解决此问题。或者我们可能需要尝试其它不同的方法。

对于回归问题,一个合理的基线是通过预估测试集中所有示例的运行结果为训练集中目标结果的中值。这种方式建立的基线为对比模型表现结果设定了一个相对较低的门槛。

我们将使用的度量标准是平均绝对误差(mae)--计算出预测的平均绝对误差。其实存在很多种回归问题的度量指标,但我喜欢Andrew Ng的建议去选择一个指标然后一直在以后模型评估中使用它。平均绝对误差(mae)是一个不错的选择,它不仅容易计算并且可解释性强。

在计算基线之前,我们需要将我们的数据分成一个训练集和一个测试集:

1. 训练集的作用就是通过给模型提供有标签的数据来训练模型能力,换句话说就是训练集既能“提供问题”又能“提供答案”。旨在让模型学习特征与目标之间的映射。

2. 测试集的作用是用来评估训练好模型。评估过程中不允许模型查看测试集的标签,只能使用特征进行预测。我们可以通过对比测试集的预测值与标签真实值来评估模型的表现。换句话说就是测试集只“提供问题”给模型不“提供答案”。

我们将使用70%的数据进行训练,30%用于测试:

计算基线并得出预估表现值(mae):

通过计算得出预估模型表现为66,在测试集中的误差约为25左右(分值:1-100)。这是一个很容易达到的性能。

结论

在前两篇的分析中,我们走过了一个完整机器学习项目的前三个步骤。在明确定义问题之后,我们:

1. 清洗并格式化了原始数据

2. 执行探索性数据分析以了解数据集

3. 转换出了一系列我们将用于模型的特征

4. 建立了可以判断整个机器学习算法的基线。

接下来将展示如何使用Scikit-Learn评估机器学习模型,选择最佳模型和微调超参数来优化模型。

酷叮猫少儿编程讲堂——Python 寻找aabb完全平方数 营销视频课程

img

凌鞅

关注

某个数如果是另一个整数的完全平方,那么我们就称这个数为完全平方数,也叫做平方数。比如:0,1,4,9,16,25,36等。 我们的任务是找到形如aabb的这样的完全平方数 (即前两位相等,后两位也相等)。

[分析]

算法一: 用0~9之间的数字组合出aabb这样的数字,再对其进行开方,平方运算,从而验证aabb是否为完全平方数。

算法二:我们对1~100之内的数进行平方运算得到10000以内的完全平方数,再对其进行拆解,找到形如aabb的数

运行结果如下图:

代码如下:

# 算法一for a in range(1,10):for b in range(0,10): aabb = a*1100 + b*11 # 不一定是平方数,但里面有平方数 c = int(aabb**0.5 + 0.5) # 验证。对aabb进行开方运算,并进行四舍五入取整 if c**2==aabb: print("完全平方数{}, 开方后得到 {}".format(aabb, c)) print("{1} x {1} = {0}".format(aabb,c) )

第二种算法请大家自行设计,相信你一定可以想到办法.

入门|数据科学初学者必知的NumPy基础知识 营销视频课程

img

凝旋

关注

本文介绍了一些 NumPy 基础知识,适合数据科学初学者学习掌握。

NumPy(Numerical Python)是 Python 中的一个线性代数库。对每一个数据科学或机器学习 Python 包而言,这都是一个非常重要的库,SciPy(Scientific Python)、Mat-plotlib(plotting library)、Scikit-learn 等都在一定程度上依赖 NumPy。

对数组执行数学运算和逻辑运算时,NumPy 是非常有用的。在用 Python 对 n 维数组和矩阵进行运算时,NumPy 提供了大量有用特征。

这篇教程介绍了数据科学初学者需要了解的 NumPy 基础知识,包括如何创建 NumPy 数组、如何使用 NumPy 中的广播机制、如何获取值以及如何操作数组。更重要的是,大家可以通过本文了解到 NumPy 在 Python 列表中的优势:更简洁、更快速地读写项、更方便、更高效。

本教程将使用 Jupyter notebook 作为编辑器。

让我们开始吧!

安装 NumPy

如果你已经装有 Anaconda,那么你可以使用以下命令通过终端或命令提示符安装 NumPy:

conda install numpy

如果你没有 Anaconda,那么你可以使用以下命令从终端上安装 NumPy:

pip install numpy

安装好 NumPy 后,你就可以启动 Jupyter notebook 开始学习了。接下来从 NumPy 数组开始。

NumPy 数组

NumPy 数组是包含相同类型值的网格。NumPy 数组有两种形式:向量和矩阵。严格地讲,向量是一维数组,矩阵是多维数组。在某些情况下,矩阵只有一行或一列。

首先将 NumPy 导入 Jupyter notebook:

import numpy as np

从 Python 列表中创建 NumPy 数组

我们先创建一个 Python 列表:

my_list = [1, 2, 3, 4, 5]

通过这个列表,我们可以简单地创建一个名为 my_numpy_list 的 NumPy 数组,显示结果:

my_numpy_list = np.array(my_list)my_numpy_list #This line show the result of the array generated

刚才我们将一个 Python 列表转换成一维数组。要想得到二维数组,我们要创建一个元素为列表的列表,如下所示:

second_list = [[1,2,3], [5,4,1], [3,6,7]]new_2d_arr = np.array(second_list)new_2d_arr #This line show the result of the array generated

我们已经成功创建了一个有 3 行 3 列的二维数组。

使用 arange() 内置函数创建 NumPy 数组

与 Python 的 range() 内置函数相似,我们可以用 arange() 创建一个 NumPy 数组。

my_list = np.arange(10)#ORmy_list = np.arange(0,10)

这产生了 0~10 的十个数字。

要注意的是 arange() 函数中有三个参数。第三个参数表示步长。例如,要得到 0~10 中的偶数,只需要将步长设置为 2 就可以了,如下所示:

my_list = np.arange(0,11,2)

还可以创建有 7 个 0 的一维数组:

my_zeros = np.zeros(7)

也可以创建有 5 个 1 的一维数组:

my_ones = np.ones(5)

同样,我们可以生成内容都为 0 的 3 行 5 列二维数组:

two_d = np.zeros((3,5))

使用 linspace() 内置函数创建 NumPy 数组

linspace() 函数返回的数字都具有指定的间隔。也就是说,如果我们想要 1 到 3 中间隔相等的 15 个点,我们只需使用以下命令:

lin_arr = np.linspace(1, 3, 15)

该命令可生成一维向量。

与 arange() 函数不同,linspace() 的第三个参数是要创建的数据点数量。

在 NumPy 中创建一个恒等矩阵

处理线性代数时,恒等矩阵是非常有用的。一般而言,恒等矩阵是一个二维方矩阵,也就是说在这个矩阵中列数与行数相等。有一点要注意的是,恒等矩阵的对角线都是 1,其他的都是 0。恒等矩阵一般只有一个参数,下述命令说明了要如何创建恒等矩阵:

my_matrx = np.eye(6) #6 is the number of columns/rows you want

用 NumPy 创建一个随机数组成的数组

我们可以使用 rand()、randn() 或 randint() 函数生成一个随机数组成的数组。

使用 random.rand(),我们可以生成一个从 0~1 均匀产生的随机数组成的数组。

例如,如果想要一个由 4 个对象组成的一维数组,且这 4 个对象均匀分布在 0~1,可以这样做:

my_rand = np.random.rand(4)

如果我们想要一个有 5 行 4 列的二维数组,则:

my_rand = np.random.rand(5, 4)my_rand

使用 randn(),我们可以从以 0 为中心的标准正态分布或高斯分布中产生随机样本。例如,我们这样生成 7 个随机数:

my_randn = np.random.randn(7)my_randn

绘制结果后会得到一个正态分布曲线。

同样地,如需创建一个 3 行 5 列的二维数组,这样做即可:

np.random.randn(3,5)

最后,我们可以使用 randint() 函数生成整数数组。randint() 函数最多可以有三个参数:最小值(包含),最大值(不包含)以及数组的大小。

np.random.randint(20) #generates a random integer exclusive of 20np.random.randint(2, 20) #generates a random integer including 2 but excluding 20np.random.randint(2, 20, 7) #generates 7 random integers including 2 but excluding 20

将一维数组转换成二维数组

先创建一个有 25 个随机整数的一维数组:

arr = np.random.rand(25)

然后使用 reshape() 函数将其转换为二维数组:

arr.reshape(5,5)

注意:reshape() 仅可转换成行列数目相等,且行列数相乘后要与元素数量相等。上例中的 arr 包含 25 个元素,因此只能重塑为 5*5 的矩阵。

定位 NumPy 数组中的最大值和最小值

使用 max() 和 min() 函数,我们可以得到数组中的最大值或最小值:

arr_2 = np.random.randint(0, 20, 10)arr_2.max() #This gives the highest value in the arrayarr_2.min() #This gives the lowest value in the array

使用 argmax() 和 argmin() 函数,我们可以定位数组中最大值和最小值的索引:

arr_2.argmax() #This shows the index of the highest value in the array arr_2.argmin() #This shows the index of the lowest value in the array

假设存在大量数组,而你需要弄清楚数组的形态,你想知道这个数组是一维数组还是二维数组,只需要使用 shape 函数即可:

arr.shape

从 NumPy 数组中索引/选择多个元素(组)

在 NumPy 数组中进行索引与 Python 类似,只需输入想要的索引即可:

my_array = np.arange(0,11)my_array[8] #This gives us the value of element at index 8

为了获得数组中的一系列值,我们可以使用切片符「:」,就像在 Python 中一样:

my_array[2:6] #This returns everything from index 2 to 6(exclusive)my_array[:6] #This returns everything from index 0 to 6(exclusive)my_array[5:] #This returns everything from index 5 to the end of the array.

类似地,我们也可以通过使用 [ ][ ] 或 [,] 在二维数组中选择元素。

使用 [ ][ ] 从下面的二维数组中抓取出值「60」:

two_d_arr = np.array([[10,20,30], [40,50,60], [70,80,90]])two_d_arr[1][2] #The value 60 appears is in row index 1, and column index 2

使用 [,] 从上面的二维数组中抓取出值「20」:

two_d_arr[0,1]

也可以用切片符抓取二维数组的子部分。使用下面的操作从数组中抓取一些元素:

two_d_arr[:1, :2] # This returns [[10, 20]]two_d_arr[:2, 1:] # This returns ([[20, 30], [50, 60]])two_d_arr[:2, :2] #This returns ([[10, 20], [40, 50]])

我们还可以索引一整行或一整列。只需使用索引数字即可抓取任意一行:

two_d_arr[0] #This grabs row 0 of the array ([10, 20, 30])two_d_arr[:2] #This grabs everything before row 2 ([[10, 20, 30], [40, 50, 60]])

还可以使用 &、|、<、> 和 == 运算符对数组执行条件选择和逻辑选择,从而对比数组中的值和给定值:

new_arr = np.arange(5,15)new_arr > 10 #This returns TRUE where the elements are greater than 10 [False, False, False, False, False, False, True, True, True, True]

现在我们可以输出符合上述条件的元素:

bool_arr = new_arr > 10new_arr[bool_arr] #This returns elements greater than 10 [11, 12, 13, 14]new_arr[new_arr>10] #A shorter way to do what we have just done

组合使用条件运算符和逻辑运算符,我们可以得到值大于 6 小于 10 的元素:

new_arr[(new_arr>6) & (new_arr<10)]

预期结果为:([7, 8, 9])

广播机制

广播机制是一种快速改变 NumPy 数组中的值的方式。

my_array[0:3] = 50#Result is:[50, 50, 50, 3, 4, 5, 6, 7, 8, 9, 10]

在这个例子中,我们将索引为 0 到 3 的元素的初始值改为 50。

对 NumPy 数组执行数学运算

arr = np.arange(1,11)arr * arr #Multiplies each element by itselfarr - arr #Subtracts each element from itselfarr + arr #Adds each element to itselfarr / arr #Divides each element by itself

我们还可以对数组执行标量运算,NumPy 通过广播机制使其成为可能:

arr + 50 #This adds 50 to every element in that array

NumPy 还允许在数组上执行通用函数,如平方根函数、指数函数和三角函数等。

np.sqrt(arr) #Returns the square root of each elementnp.exp(arr) #Returns the exponentials of each elementnp.sin(arr) #Returns the sin of each elementnp.cos(arr) #Returns the cosine of each elementnp.log(arr) #Returns the logarithm of each elementnp.sum(arr) #Returns the sum total of elements in the arraynp.std(arr) #Returns the standard deviation of in the array

我们还可以在二维数组中抓取行或列的总和:

mat = np.arange(1,26).reshape(5,5)mat.sum() #Returns the sum of all the values in matmat.sum(axis=0) #Returns the sum of all the columns in matmat.sum(axis=1) #Returns the sum of all the rows in mat

现在,这篇 NumPy 教程进入了尾声!希望对大家有所帮助。

如何在Python中从零开始实现随机森林 公司视频课程

img

最后

关注

更多腾讯海量技术文章,请关注云+社区:https://cloud.tencent/developer

决策树可能会受到高度变异的影响,使得结果对所使用的特定测试数据而言变得脆弱。

根据您的测试数据样本构建多个模型(称为套袋)可以减少这种差异,但是树本身是高度相关的。

随机森林是套袋(方法)的延伸,除了基于多个测试数据样本构建树木之外,它还限制了可用于构建树木的特征,使得树木间具有差异。这反过来可以提升算法的表现。

在本教程中,您将了解如何在Python中从头开始实现随机森林算法。

完成本教程后,您将知道:

套袋决策树和随机森林算法的区别。

如何构造更多方差的袋装决策树。

如何将随机森林算法应用于预测建模问题。

让我们开始吧。

2017年1月更新:将cross_validation_split()中fold_size的计算更改为始终为整数。修复了Python 3的问题。

2017年2月更新:修复了build_tree中的错误。

2017年8月更新:修正了基尼计算中的一个错误,增加了群组大小(基于迈克尔!)。

如何在Python中从头开始实现随机森林

注:图片来自 InspireFate Photography,保留部分权利。

描述

本节简要介绍本教程中使用的随机森林算法和Sonar数据集。

随机森林算法

决策树涉及从数据集中(利用)贪婪选择选取最佳分割点过程中的每一步。

如果不精简(该算法),此算法容易使决策树出现高方差。这种高方差(结果)可以通过创建包含测试数据集中(多个)不同的实例(问题的不同观点)的多重树,接着将实例所有的可能结果结合,这种方法简称为bootstrap聚合或套袋。

套袋的局限性在于,它使用相同的贪婪算法来创建每棵树,这意味着在每棵树中可能会选择相同或非常相似的分割点,使得不同的树非常相似(树将被关联)。这反过来又使他们的预测相似,从而缩减了最初寻求的差异。

我们可以通过贪婪算法在创建树时在每个分割点评估的特征(行)来限制决策树不同。这被称为随机森林算法。

像装袋一样,测试数据集的多个样本在被采集后,接着在每个样本上训练不同的树。不同之处在于在每一点上,拆分是在数据中进行并添加到树中的,且只考虑固定的属性子集。

对于分类问题,我们将在本教程中讨论的问题的类型——分割中输入特点数的平方根值对为分割操作考虑的属性个数的限制。

这一小变化的结果是树之间变得更加不同(不关联),作为结果会有更加多样化的预测,这样的结果往往好于一个单独的树或者单独套袋得到的结果。

声纳数据集

我们将在本教程中使用的数据集是Sonar数据集。

这是一个描述声纳声音从不同曲面反弹后返回(数据)的数据集。输入的60个变量是声呐从不同角度返回的力度值。这是一个二元分类问题,需要一个模型来区分金属圆柱中的岩石。这里有208个观察对象。

这是一个很好理解的数据集。所有变量都是连续的且范围一般是0到1。输出变量是“Mine”字符串中的“M”和“rock”中的“R”,需要转换为整数1和0。

通过预测在数据集(“M”或“mines”)中观测数最多的类,零规则算法可以达到53%的准确度。

您可以在UCI Machine Learning repository了解关于此数据集的更多信息。

下载免费的数据集,并将其放置在工作目录中,文件名为sonar.all-data.csv。

教程

本教程分为2个步骤。

计算分割。

声纳数据集案例研究。

这些步骤为您需要将随机森林算法应用于自己的预测建模问题奠定了基础。

1.计算分割

在决策树中,通过利用最低成本找到指定属性和该属性的值方法来确定分割点。

对于分类问题,这个成本函数通常是基尼指数,它计算分割点创建的数据组的纯度。基尼指数为0是完美纯度,其中在两类分类问题的情况下,将类别值完全分成两组。

在决策树中找到最佳分割点涉及到为每个输入的变量评估训练数据集中每个值的成本。

对于装袋和随机森林,这个程序是在测试数据集的样本上执行的,并且是可替换的。更换取样意味着同一行(数据)会不止一次的被选择并将其添加到取样中。

我们可以优化随机森林的这个程序。我们可以创建一个输入属性样本来考虑,而不是在搜索中枚举输入属性的所有值。

这个输入属性的样本可以随机选择而不需要替换,这意味着每个输入属性在查找具有最低成本的分割点的过程中只被考虑一次。

下面是实现此过程的函数名称get_split()。它将数据集和固定数量的输入要素作为输入参数进行评估,此数据集可能是实际测试数据集的一个样本。

helper函数test_split()用于通过候选分割点拆分数据集,gini_index()用于根据创建的行组来计算给定拆分的花费。

我们可以看到,通过随机选择特征索引并将其添加到列表(称为特征)来创建特征列表,然后枚举该特征列表并且将测试数据集中的特定值评估作为分割点。

现在我们知道如何修改决策树算法以便与随机森林算法一起使用,我们可以将它与一个bagging实现一起使用,并将其应用于现实生活中的数据集。

2.声纳数据集案例研究

在本节中,我们将把随机森林算法应用到声纳数据集。

该示例假定数据集的CSV副本位于当前工作目录中,文件名为sonar.all-data.csv。

首先加载数据集,将字符串值转换为数字,并将输出列从字符串转换为0和1的整数值。这可以通过使用帮助器函数load_csv(),str_column_to_float()和str_column_to_int()来加载和预备数据集。

我们将使用k-fold交叉验证来估计未知数据的学习模型的性能。这意味着我们将构建和评估k个模型,并将性能估计为平均模型误差。分类准确性将用于评估每个模型。这些工具或是算法在cross_validation_split(),accuracy_metric()和evaluate_algorithm()辅助函数中提供。

我们也将使用适合套袋包括辅助功能分类和回归树(CART)算法的实现)test_split(拆分数据集分成组,gini_index()来评估分割点,我们修改get_split()函数中讨论在前一步中,to_terminal(),split()和build_tree()用于创建单个决策树,预测()使用决策树进行预测,subsample()创建训练数据集的子采样,以及bagging_predict()用决策树列表进行预测。

开发了一个新的函数名称random_forest(),首先根据训练数据集的子样本创建一个决策树列表,然后使用它们进行预测。

正如我们上面所说的,随机森林和袋装决策树之间的关键区别是对树的创建方式中的一个小的改变,这里是在get_split()函数中。

完整的例子如下所示。

使用k值5进行交叉验证,给定每个倍数值为208/5 = 41.6或者在每次迭代中刚好超过40个记录被计算。

构建深度树的最大深度为10,每个节点的最小训练行数为1。训练数据集样本的创建大小与原始数据集相同,这是随机森林算法的默认期望值。

在每个分割点处考虑的特征的数量被设置为sqrt(num_features)或者sqrt(60)= 7.74被保留为7个特征。

对一套有着3种不同数量的树木(示例)进行评测在此过程中进行比较,结果表明随着更多树木的添加,(处理)技能也随之提升。

运行该示例将打印每个折叠的分数和每个配置的平均分数。

扩展

本节列出了您可能有兴趣探索的关于本教程的扩展。

算法优化。发现教程中使用的配置有一些试验和错误,但没有进行优化。尝试更多的树木,不同数量的特征,甚至不同的树形配置来提高性能。

更多的问题。将该技术应用于其他分类问题,甚至将其应用于回归,具有新的成本函数和结合树预测的新方法。

你有没有尝试这些扩展? 在下面的评论中分享你的经验。

评论

在本教程中,您了解了如何从头开始实现随机森林算法。

具体来说,你了解到:

随机森林和Bagged决策树的区别。

如何更新决策树的创建以适应随机森林过程。

如何将随机森林算法应用于现实世界的预测建模问题。

翻译人:一只懒惰的小白,该成员来自云+社区翻译社

原文链接:https://machinelearningmastery/implement-random-forest-scratch-python/

原文作者:Jason Brownlee

img

在线咨询

建站在线咨询

img

微信咨询

扫一扫添加
动力姐姐微信

img
img

TOP