《暗时间》读书笔记(三)

第三篇——跟波利亚学解题

波利亚,数学家。数学问题中运用的各种方法,又何尝不是我们解各种学术or生活中问题的思维方式呢?

波利亚在书中提到的一些启发式思考方法:

  1. 时刻不忘未知量(即时刻别忘记你到底想要求什么,问题是什么)

  2. 用特例启发思考(泛化的问题往往无从下手,可以通过特例寻求一般性解答)

  3. 倒推法(利用结论蕴含的知识,智能搜索解空间)

  4. 试错

  5. 调整题目的条件(通过增删、改变条件,来发现条件与结论如何联系)

  6. 求解一个类似题目(抽象出来)

  7. 列出所有可能跟问题有关的定理或性质

  8. 考察反面,考察其他所有的情况

  9. 将问题泛化,并求解泛化后的问题

  10. 意识孵化法(要求吃透问题,激发潜意识对其不停思考)

  11. 烫手山芋法

    知识是一把双刃剑。如何在获取知识优势的同时,防止被知识束缚住?抽象。在吸收知识的时候抽象,对问题也是。对某一个对象,去枝减叶,从不同的抽象层面去掌握其知识信息,是启发思维和吸收知识的一大重要点。

    知识!知识!
    知识就是力量,这句话不是空穴来风。没有根基,任何探索都无法进行下去。

    作者提出了一个解题的好习惯,就是把解题的思考过程写在纸上。一步步的过程的记录,有利于记忆的缓存,更方便回溯和查错。因为每一个关键的一步或许都有另一种可能性,“一条路走到黑”是可以避免和修正的。这样,解题结束后,更有利于反思和总结收获。

    练习!练习!

如果你手里有一把锤子,所有东西看上去都像钉子。

如果你想钉一个钉子,所有东西看上去都像是锤子。

鱼是最后一个看到水的
人倾向于在既有框架下去解决问题,在这个过程中,还很难察觉到框架约束的存在。
think out of the box

知其所以然
凡事多问几个为什么,探索背后的原因。
思考问题的时候,我们的大脑中其实有一棵搜索树来寻求解答,当问题很复杂时它会是很庞大的。这个探索的过程即时所谓的思维过程。“如果说问题求解是一部侦探小说,那么算法只是结局而已,而思考过程才是情节。” 揣摩如何得到这样的解答的,可以理解到更深刻的东西,透析问题本质,把握解题精髓。

知道怎么做是从正确(高效)解法得到的,而知道为什么必须得那样则往往是从错误(低效)的解法中得到的。

Y Combinator

这部分好好看了几遍,梳理一下如下:

首先,关于lambda的基本语法:

定义lambda函数:
	lambda x y. x + y
或可以起一个名字:
	let Add = (lambda x y. x + y)
调用该函数:
	(Add 2 3)
	不过在下面为了方便起见,还是会写成Add(2, 3)这种形式

在lambda中可以递归吗?

理想想法:
	lambda n. If_Else n==0 1 n*<self>(n-1)
	<self>是指函数本身,然而lambda算子系统里面的lambda表达式(函数)是没有名字的

第一次尝试:
	let F = lambda n. If_Else n==0 1 n*F(n-1)
	但是let F只是一个语法糖的作用(使对象便于阅读和表达),在它所代表的lambda表达式还没有完全定义出来之前是不可以使用F这个名字的

第二次尝试:
	引入软件工程里面的一条黄金定律:“任何问题都可以通过增加一个间接层来解决。”
	既然不能直接填入<self>,可以增加一个参数:
		lambda self n. If_Else n==0 1 n*self(n-1)
	为简单起见,用let语句给该语句起个别名:
		let P = lambda self n. If_Else n==0 1 n*self(n-1)
	然后调用:P(P, 3)
	但是,这个函数包含两个参数,所以在If处需要修改需要修改:
		let P = lambda self n. If_Else n==0 1 n*self(self, n-1)
	调用时:P(P,3),即把自己作为P的第一个参数(此时P已经定义完毕了),这样self处就等于P本身了,也就实现了递归

不动点原理

虽然上面的例子成功了,但是很冗余。回顾那个失败的做法:
	let P = lambda self n. If_Else n==0 1 n*self(n-1) (*)
调用P(P, n)时,里面的self(n-1)会展开为P(n-1)。不能使用。
下一步,假设一个“真正”的递归阶乘函数:power(n),这样可以把power传给P:
	P(power, 3)
考虑一下power和P之间的关系,直接把power交给P
	P(power)
What's this?It's called partial evaluation(函数的部分求值)。得到的是“还剩一个参数待给的一个新的函数”,可以发现P(power)即为power本身的定义。

P(power) = power	
以上,对于函数P来说,power就是一个不动点。power此时是不存在的,如何找到它?
我们看到,对于伪递归的P,存在一个power,满足P(power) = power;注意,这里的伪递归是指(*)。对任一伪递归F(伪递归如何得到——是为了解决lambda函数不能引用自身的问题,于是给理想的f加一个self参数从而得到的),必存在一个理想f(F就是从这个理想f演变而来的),满足F(f) = f.

现在,问题归结为如何针对F找到对应的f。假设有一个神奇的函数Y,有
	Y(F) = f
结合上面的F(f) = f,得到:
	Y(F) = f = F(f) = F(Y(F))
不过如何构造这个Y又成了难题。

再次回顾伪递归的求阶乘函数:
	let P = lambda self n. If_Else n==0 1 n*self(n-1) (*)
又根据不动点原理:
	power = P(power)
如何实现一个能够自己调用自己的power?上面提到的方法,增加一个间接层:
	let power_gen = lambda self. P(self(self))
递归调用:
	power_gen(power_gen) ==> P(power_gen(power_gen))
现在,把power_gen(power_gen)当成整体看,不妨令为power:
	power = P(power)
	
总结:对于给定的P,只要构造出一个相应的power_gen如下:
	let power_gen = lambda self. P(self(self))
power_gen(power_gen)即为我们寻找的不动点

铸造Y Combinator

Y Combinator只要生成一个形如power_gen的lambda函数,然后把它应用到自身:

let Y = lambda F.
let f_gen = lambda self. F(self(self))
return f_gen(f_gen)

解释:Y是一个lambda函数,它接受一个伪递归F,在内部生成一个f_gen,然后把f_gen应用到它自身,得到的f_gen(f_gen)就是F的不动点了。而根据不动点的性质,F的不动点也就是那个对应于F的真正的递归函数。

哥德尔的不完备性定理

哥德尔证明出,任何足够强到蕴涵了皮亚诺算术系统(PA)的一致(即无矛盾)的系统都是不完备的,所谓不完备,也就是说在系统内存在一个为真但无法在系统内推导出的命题。

需要构造一个为真但无法在T内推倒(证明)的命题。

N(n) is unprovable in T  

其中n是自由变量,为一个自然数,一旦给定,公式就变成一个明确的命题。N是一个公式(哥德尔的证明第一部分就是把公式编码)。“is unprovable in T”是可以用形式语言表达的:一个形式系统中的符号数目时有限的,它们构成这个形式系统的符号表;依次枚举所有串,列举所有良构的公式(well formed formula,简称wff);这样,枚举出所有可由T推导出的定理;本质上,该句即为“不存在一个自然数S,它所解码出来的wff序列以X为终结”。

哥德尔的公式变成了:

UnPr(N(n))  

首先我们把这个公式简记为G(n)——由于G内有一个自由变量n,所以G不是命题,谈不上真假:

G(n): UnPr(N(n))  

又由于G也是wff,所以它也有自己的编码g,当然g是一个自然数。现在我们把g作为G的参数,也就是把自由变量n替换为g,我们得到一个真正的命题:

G(g): UnPr(G(g))  

这就证明了哥德尔的第一不完备性定理。还有一个推论,称为第二不完备性定理:
任一个系统T内无法证明这个系统本身的一致性。

从哥德尔公式到Y Combinator

回顾哥德尔命题的构造:

G(n): UnPr(N(n))  

其中UnPr可以泛化为一个一般的谓词P:

G(n): P(N(n))  

也就是说,对于任意一个单参的谓词P,都存在上面这个哥德尔公式。然后算出这个哥德尔公式的自然数编码g并把它扔给G,就得到:

G(g): P(G(g))

这个形式也就是Y Combinator的构造,精妙绝伦!

对角线方法——停机问题的深刻含义

通过对角线方法证明图灵机无法判断所有的停机行为:
从反证开始,假设存在这样一个图灵机,能判断任何程序在任何输入上是否停机。由于所有图灵机构成的集合是一个可列集,所以可以自然列出下表,表示每个图灵机分别在每一个可能的输入下的输出,N表示无法停机:

	1	2	3	4	...  
M1	N	1	N	N	...  
M2	2	0	N	0	...  
M3	0	1	2	0	...
...

Mi表示编码为i 的图灵机,第一行代表的是输入数据。我们刚才假设存在这样一饿图灵机H,它能够判断任何程序在任何输入上能否停机,换句话说,H(i,j)能够给出“Mi(j)”是N还是给出一个具体结果。

现在运用康托尔德对角线方法,构造一个新的图灵机P,P在输入i上的输出根Mi(i)不一样。构造出的图灵机P如下:

P(i):
if (H(i, i) == 1) then	//  Mi(i) halts
	return 1 + Mi(i)
else 	// if H(i, i) == 0 (M(i) doesn't halt)
	return 0

现在,我们注意到P本身就是一个图灵机,而我们上面已经列出了所有的图灵机,所以必然存在一个k,使得Mk = P。而两个图灵机相等当且仅当它们对于所有的输入都相等,也就是说对于任取的n,有Mk(n) = P(n),现在令n=k,得到Mk(k) = P(k),根据上面给出的P的定义,这实际上就是:

Mk(k) = P(k) = 
	1+Mk(k) if Mk(k) halts
	0 if Mk(k) doesn't halt

这个式子显然矛盾。于是我们得出,不存在那样的H。

这个对角线方法实际上说明了,无论多聪明的H,总存在一个图灵机的停机行为是它无法判断的。这跟哥德尔定理“无论多‘完备’的形式化公理系统,都存在一个‘哥德尔命题‘是无法在系统内推导出来的”从本质上其实是一模一样的。

数学之美番外篇

快排为什么那样快

不论是猜数字,还是称球,我们选取策略的本质都可以概括为“让未知世界无机可乘”。它是没有弱点的,答案的任何一个分支都是等概率的。

称球问题有一个更本质的思路。
回顾猜数字游戏,为保证任何情况下以最少次数猜中,我们的策略是每次都排除恰好一半的可能性。类比到称球问题上:坏球可能是12个球中的任意一个,这就是12种可能性;每种可能性下坏球可能轻也可能重。于是答案有24种可能性。用天平称球,就等同于对这24种可能性发问,由于天平的输出结果有三种“平衡、左倾、右倾”,这就相当于可以讲所有的可能性切成三份。如此,理论上三次是完全可以称出来的。

而关于快排为什么那么快。可以设想有n个数字,它们的排列方法为n!种。基于比较算法的话,每次比较得出两种大小关系,最理想的情况是把解空间去掉一半。所以它的复杂度为log(2)n!,即nlog(2)n。

信息论

关于信息论,重要的是一种看问题的本质视角:看排序和猜数字问题,都是通过问问题来缩小/排除(narrow down)结果的可能性空间,这样一来就会发现,“最好的问题”就是那些能够均分所有可能性的问题,因为那样不管答案如何,都能排除掉k-1/k种可能性。

平凡而又神奇的贝叶斯方法

贝叶斯方法是由“逆概”引出的。背后的深刻原因在于,现实世界本身是不确定的,人类的观察能力是有局限性的。这个时候,我们就需要提供一个假设。1、算出各种不同猜测的可能性大小;2、算出最靠谱的猜测是什么。

公式:
P(B|A) = P(AB) / P(A)

关于拼写纠正
对于一个词库中不存在的单词D,如何判断用户想打的是什么单词(可能是h1,h2,,,)?
我们需要计算 P(h|D), 运用贝叶斯公式:P(h|D) = P(h) * P(D|h) / P(D)
由于P(D)是一样的,可以忽略。所以 P(h|D) 正比于 P(h) 和 P(D|h) 。抽象含义是:对于给定观测数据,一个猜测(假设)是好是坏,取决于“这个猜测本身独立的可能性大小(先验概率,Prior)”和“这个猜测生成我们观测到的数据的可能性大小(似然,Likelihood)”的乘积。

模型比较与奥卡姆剃刀

为什么不能只看最大似然?第一,不能提供决策的全部信息;第二,猜测本身的可能性也许就非常低。

观测数据总是有各种误差,所以如果过分寻求能够完美解释观测数据的模型,就会落入所谓的数据过配(overfitting)的境地,一个过配的模型试图连误差(噪音)都去解释(实际上噪音又是不需要解释的),显然就过犹不及了。

所谓奥卡姆剃刀的精神就是说:如果两个理论具有相似的解释力度,那么优先选择那个更简单的(往往也正是更平凡的,更少繁复的,更常见的)。

过分匹配的另一个原因在于当观测的结果并不是因为误差而显得“不精确”,而是因为真实世界中对数据的结果产生贡献的因素太多,不是你的模型(仅抽取了几个重要因素)所能解释的

无处不在的贝叶斯

  1. 中文分词
  2. 统计机器翻译
  3. 贝叶斯图像识别
  4. EM算法与基于模型的聚类

聚类是一种无指导的机器学习问题,问题描述:给你一堆数据点,让你将它们最靠谱地分成一堆一堆的。例如书中举的例子,就是根据给出来的那些点,算出这两个正态分布的核心在什么位置,以及分布的参数是多少。但是怎么分?EM算法就是,先随机整一个值出来,再根据变化调整,不断迭代相互推导,最终收敛到一个解。

  1. 最大似然与最小二乘
posted @ 2016-03-06 11:34  Christen  阅读(231)  评论(0编辑  收藏  举报