mxs 2019-12-15
正如我在<自然语言处理(NLP) - 数学基础(1) - 总述>一文中所提到的NLP所关联的概率论(Probability Theory)知识点是如此的多, 饭只能一口一口地吃了, 我们先开始最为大家熟知和最基础的知识点吧, 排列组合.
虽然排列组合这个知识点大家是相当地熟知, 也是相当地基础, 但是却是十分十分十分地重要.
NLP届掌门人斯坦福大学的Daniel Jurafsky(D. 朱夫斯凯)和科罗拉多大学James H. Martin(J. H. 马丁)在其NLP巨作《自然语言处理综论》一书第二版第5页中提到:“几乎所有的语音处理和语言处理问题都可以这样来表述: 对于某个歧义的输入给出N个可能性, 选择其中概率最高的一个.”
现在让我们来看看排列组合概念的定义吧: 所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。所谓组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。
See, 与掌门人上面这句话相比, 是如此的相似!
排列组合有两条基本原理组成:
如何区分这两个原理呢?
要做一件事,完成它若是有n类办法,是分类问题,第一类中的方法都是独立的,则使用加法原理;做一件事,需要分n个步骤,步与步之间是连续的,只有将分成的若干个互相联系的步骤,依次相继完成,这件事才算完成,则使用乘法原理。
完成一件事的分“类”和“步”是有本质区别的,因此也就将两个原理区分开来了。
根据以上原理衍生出很多方法, 包括且不限于:
因为本节是第一节, 所以在做习题和代码示例之前, 我们需要去安装Python 3和对应的开发工具Visual Studio Code, 同时建议先照着Getting Started with Python in VS Code过一遍. (预计耗时要1-3个小时,包括update Xcode, 要注意安排好时间).
如果是时间赶, 可以使用python online editor去做. https://www.tutorialspoint.com/python/index.htm
从学术和参加算法比赛的角度来讲, 我们应该尽量不要用任何库. 然而现在我是从工程的角度出发, 所以我会使用到大名鼎鼎的NLP工具包NLTK以及Python里的数学库Scipy 和 itertools (虽然本节不会用全三个库, 但是以后的章节会全用到的)
这点和前文所讲的"AI并不只是调现有云和库API即可"并不冲突, 因为:
在开始写代码做习题之前我们先按照如下链接去热身和确认环境是好的:
https://blog.csdn.net/qq_41185868/article/details/79682406 安装Python的Scipy包
如果遇到ssl证书问题则参考这篇文章去解决https://www.cnblogs.com/jiyanjiao-702521/p/9960071.html
如果还是遇到错误, 那就去按照https://www.jianshu.com/p/dbf20c6792fe 这篇文章一劳永逸的解决问题, 不过需要下载Anaconda, 大概要五六百M, 记得是要用bash安装. 安装完之后就可以sudo conda install scipy了, 然后再用Anaconda navigator去lanunch VS Code.
https://www.geeksforgeeks.org/permutation-and-combination-in-python/
https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.perm.html
https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.comb.html
https://www.nltk.org/api/nltk.html#nltk.probability.ConditionalFreqDist 里的nltk.util.choose(n, k) (本节不会用到, 以后章节会)
然后开始做题
捆绑法
题目: 六个元素进行排列, 其中指定的两个元素必须要排在一起, 总共有多少种排法?
答案: 这指定的两个元素需要捆绑成一个元素进行排列, 然后这捆绑在一起的元素内部在进行排列. 最后使用分步计数法(即乘法原理)进行相乘. 所以应该是n5.5 X n2.2 = 240种
代码实现:
from scipy.special import perm result = perm(5, 5, exact=True) * perm(2,2, exact=True) print(result)
插空法
题目: 对6个A元素和4个B元素进行排列, 任意两个B元素不得相邻, 总共有多少种排法?
答案: 因为B元素不得相邻, 则需要使用插空法, 先排6个A元素A6,6 , 在6+1个空位置中再对4个B元素进行排列 a 4 7, 最后使用分步计数法(即乘法原理)进行相乘得出为604800种
代码实现
from scipy.special import perm result = perm(6, 6, exact=True) * perm(7,4, exact=True) print(result)
插板法
题目:将8个完全相同的元素分成3组, 每组至少要有一个元素, 总共有多少排法?
答案: 首先因为元素是完全相同的, 所以不需要排列, 因此这是个组合问题. 然后使用插板法, 将n个相同元素分成m组, 且每组必须有元素就相当于在n-1个空中插m-1个板, C2,7 共21种 (不是42种是因为是求解组合而不是排列)
代码实现
from scipy.special import comb result = comb(7, 2, exact=True) print(result)
如果时间紧急没有办法装Python环境这怎么办?
So easy, 使用https://www.calculator.net/permutation-and-combination-calculator.html 进行在线求解就行了,.
或者使用手机或者iPad下载microsoft math resolver去求解即可.
以上两个事实再次证明了, 正确的解题思路才是关键, 只要解题思路正确了, 后面的求解过程是很方便很easy的. 这点不就是我在<2019年总结>一文中所说到的”做正确的事情, 然后正确的做事, 比勤劳更重要”的体现吗?
不过再次提醒学术和要面试的同学们, 不要学我把求解过程扔给计算机, 这样会让你面试挂的. 我是从纯工程角度出发的.
有用链接:
https://betterexplained.com/articles/easy-permutations-and-combinations/
https://www.csharp-console-examples.com/loop/foreach-statement/permutation-and-combination-calculator-in-c/ 这是一个C#的排列组合的简单示例,
https://www.beatthegmat.com/mba/2009/10/12/permutations-and-combinations-an-easy-method
https://study.com/academy/lesson/permutation-combination-problems-practice.html
https://www.wikihow.com/Calculate-Combinations
https://www.mathsisfun.com/combinatorics/combinations-permutations.html
为了方便搜索资料, 现在列出本节所用到的英文术语名词:
概率论 - Probability Theory
排列组合 - permutation and combination
加法原理(分类计数法)- Addition rule 或者Addition theorem 或者Addition Principle
乘法原理(分步计数法)- Multiplication rule 或者Multiplication theorem或者Multiplication Principle
捆绑法 - bonding method (百度百科上的翻译是错的, 这才是对的)
插空法 - Interpolation method
插板法 - plate insertion method (目前尚存疑)
感悟:
真的是长江后浪推前浪啊, 现在的本科生直接就用英语原版的数学教材, 一旦毕业再工作个三五年就能秒杀很多十几年经验的人. 中国很多程序员35岁失业其中两个原因就是第一大学教材越到后面越先进, 后来甚至用上了英语原版的教材. 第二就是当年读书的英语教学水平远差于现在的英语教学水平, 从而导致三到五年工作经验的程序员无论是理论基础还是英语水平都超越了十几年工作经验的程序员.
不过没关系啦, 虽然落后了, 努力再追上不就行了啦