1. 程式人生 > >自然語言處理(NLP) - 數學基礎(1) - 排列組合

自然語言處理(NLP) - 數學基礎(1) - 排列組合

正如我在<自然語言處理(NLP) - 數學基礎(1) - 總述>一文中所提到的NLP所關聯的概率論(Probability Theory)知識點是如此的多, 飯只能一口一口地吃了, 我們先開始最為大家熟知和最基礎的知識點吧, 排列組合.

 

雖然排列組合這個知識點大家是相當地熟知, 也是相當地基礎, 但是卻是十分十分十分地重要.

NLP屆掌門人斯坦福大學的Daniel Jurafsky(D. 朱夫斯凱)和科羅拉多大學James H. Martin(J. H. 馬丁)在其NLP鉅作《自然語言處理綜論》一書第二版第5頁中提到:“幾乎所有的語音處理和語言處理問題都可以這樣來表述: 對於某個歧義的輸入給出N個可能性, 選擇其中概率最高的一個.”

現在讓我們來看看排列組合概念的定義吧: 所謂排列,就是指從給定個數的元素中取出指定個數的元素進行排序。所謂組合則是指從給定個數的元素中僅僅取出指定個數的元素,不考慮排序。

See, 與掌門人上面這句話相比, 是如此的相似!

 

排列組合有兩條基本原理組成:

  1. 加法原理(分類計數法)- 做一件事,完成它可以有n類辦法,在第一類辦法中有m1種不同的方法,在第二類辦法中有m2種不同的方法,……,在第n類辦法中有mn種不同的方法,那麼完成這件事共有N=m1+m2+m3+…+mn種不同方法。每一種方法都能夠直接達成目標。
  2. 乘法原理(分步計數法). 做一件事,完成它需要分成n個步驟,做第一步有m1種不同的方法,做第二步有m2種不同的方法,……,做第n步有mn種不同的方法,那麼完成這件事共有N=m1×m2×m3×…×mn種不同的方法。

如何區分這兩個原理呢? 

要做一件事,完成它若是有n類辦法,是分類問題,第一類中的方法都是獨立的,則使用加法原理;做一件事,需要分n個步驟,步與步之間是連續的,只有將分成的若干個互相聯絡的步驟,依次相繼完成,這件事才算完成,則使用乘法原理。

完成一件事的分“類”和“步”是有本質區別的,因此也就將兩個原理區分開來了。

 

根據以上原理衍生出很多方法, 包括且不限於:

  1. 捆綁法. 指在解決對於某幾個元素要求相鄰問題時,先整體考慮,將相鄰元素視作一個整體參與排序,然後再單獨考慮這個整體內部各元素間順序。注意:其首要特點是相鄰,其次捆綁法一般都應用在不同物體的排序問題中。
  2. 插空法. 某些元素不相鄰的排列組合問題,即不鄰問題,可採用插空法,即在解決對於某幾個元素要求不相鄰的問題時,先將其它元素排好,再將指定的不相鄰的元素插入已排好元素的間隙或兩端位置,從而將問題解決的策略。用這種方法解題思路清晰、簡便易懂。
  3. 插板法. 指在解決若干相同元素分組,要求每組至少有一個元素,採用將比所需分組數目少1的板插入元素之間形成分組的解題策略。

 

因為本節是第一節, 所以在做習題和程式碼示例之前, 我們需要去安裝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即可"並不衝突, 因為:

  1. 現有云和庫API是由各自的廠商和開發者寫的, 會有各種差異. 而數學庫卻是不會有差異的, 用A廠商寫出的庫去算1+2會等於3, 換了B廠商寫出的庫去算1+2一樣會等於3.
  2. 從下面的習題答案和對應的程式碼示例看到, 正確的解題思路才是關鍵, 解題思路對了接下來的求解就可以扔給Python對應的方法了. 然而解題思路卻是要穿透現有云和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.mathplanet.com/education/pre-algebra/probability-and-statistic/combinations-and-permutations

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歲失業其中兩個原因就是第一大學教材越到後面越先進, 後來甚至用上了英語原版的教材. 第二就是當年讀書的英語教學水平遠差於現在的英語教學水平, 從而導致三到五年工作經驗的程式設計師無論是理論基礎還是英語水平都超越了十幾年工作經驗的程式設計師. 

不過沒關係啦, 雖然落後了, 努力再追上不就行