過程選擇模型

前段時間看到趙玉平老師講的關於相親選擇的問題,感覺比較有趣,希望通過概率模擬驗證一下該方法的有效性。

原鏈接如下,感興趣可先了解原講解:管理學博士是怎麼硬核相親的,過程太真實了,最後居然選到這麼好的“對象”!強烈建議大家學學…… %相親    https://v.douyin.com/RWQQnC4/

1.問題重述

1.1原問題描述

各位同學是我的媒人,每位同學爲趙老師介紹一個男朋友,寫下一個數字代表該男生的質量。每次見一個人,單方向不可重複。如決定要則結束,如決定不要則繼續。

總結方法:先選4位同學(共12人)進行詢問,記住其中的最大值,然後再從其他同學中詢問,當得到大於前面所述最大值,則決定要。

1.2數學模型

現將原問題抽象爲以下數學過程

  1. 隨機生成n個數字;
  2. 將n個數字依次輸入模型中,當決定選擇其中某一個數字時(記爲第k個,k<n)過程停止;
  3. 目標是使選出的數字儘可能大,儘可能在n個數字中排在前列。

策略是:

  1. 記n個數字的前a(a<n,a/n=r)箇中的最大值爲m;
  2. 從第a+1個數字開始,若小於等於第a個數則捨棄,若大於第a個數字則選擇;
  3. 若直到最後一個數仍未出現大於第a個數的,則選擇最後一個數。

該過程中存在這樣一個問題:即這n個隨機數服從什麼分佈。先假設其服從0到100之間的均分分佈。

2.過程實現

設n=100,a=33,模擬如下。

import numpy as np

class choose:
    def __init__(self,nums):
        # nums代表提供的數字集
        self.nums = nums
        self.n=len(nums)
    def get_max(self,a):
        # 從前a個數中選出一個最大的,記爲max_num
        self.a = a
        self.max_num = max(self.nums[0:a])
    def decide(self):
        self.flag = 0
        for i in range(self.a,self.n):
            # 如果遇到更大的數則選取
            if self.nums[i]>self.max_num:
                self.choice = self.nums[i]
                self.flag = i
        # 如全程未遇到更大的數則只能選擇最後一個
        if self.flag == 0:
            self.choice = self.nums[self.n-1]
    def show(self):
        print('共有%d個數字,其中的最大值是%f,選擇的數字是%f,排第%d位' % 
              (self.n, max(self.nums), self.choice, sum(c.nums>c.choice)+1))
        if self.flag == 0:
            print('在後續數字中未找到更大的,故最終在所有數字中選擇了最後一個')
        else:
            print('選擇了第%d個數字' % (self.flag+1))

n=100
a=33
nums=np.random.uniform(0, 100, size=n)
c=choose(nums)
c.get_max(a)
c.decide()
c.show()

模擬幾次,結果如下:

共有100個數字,其中的最大值是96.647844,選擇的數字是96.647844,排第1位
選擇了第64個數字
共有100個數字,其中的最大值是99.571219,選擇的數字是65.277241,排第31位
在後續數字中未找到更大的,故最終在所有數字中選擇了最後一個
共有100個數字,其中的最大值是97.931539,選擇的數字是41.759912,排第50位
在後續數字中未找到更大的,故最終在所有數字中選擇了最後一個
共有100個數字,其中的最大值是99.566610,選擇的數字是99.566610,排第1位
選擇了第73個數字
共有100個數字,其中的最大值是98.271705,選擇的數字是98.271705,排第1位
選擇了第82個數字

可以發現,在5次模擬中有3次選到了全局最大,效果不錯,但也有兩次在後續數字中未找到更大的。

直接進行100000次模擬,觀察情況:

choices = []
rank = []
fail = 0
for i in range(0,100000):
    if i%1000==0:
        print(i)
    nums=np.random.uniform(0, 100, size=n)
    c=choose(nums)
    c.get_max(a)
    c.decide()
    choices.append(c.choice)
    rank.append(sum(c.nums>c.choice)+1)
    if c.flag == 0:
        fail += 1

觀察選出的數字的分佈:

import matplotlib.pyplot as plt
plt.hist(choices,100)

可以看到,大部分落在90~100之間,落在99~100之間的概率爲0.28,效果較好,平均值np.mean(choices)=82.01201051783117。

觀察選出的數字在原100個數字中的位次的分佈:

plt.hist(rank,100)

可以看到,大部分位次落在0~10之間,選到最大值(排第1位)的概率爲0.37。平均值np.mean(rank)=18.16273,平均相對位次0.18。

3.敏感性分析

當參數發生變化時,該方法是否仍能有較好的效果。

3.1小樣本

現實情況中我們的精力有限,往往沒有那麼多的選擇機會,那麼,當n減少時(a/n=r近似不變),會發生什麼。

n=50,a=17。進行100000次模擬,平均位次10.10,平均相對位次0.20。

n=10,a=3。進行100000次模擬,平均位次3.03,平均相對位次0.30。

n=5,a=2。進行100000次模擬,平均位次2.2,平均相對位次0.44。

隨着n的減小,能夠取得的平均相對位次的變化情況如下圖。

可見隨着n的減小,該方法的效果變差,但由於樣本少,該現象情有可原。

3.2策略值r

保持n=100不變,觀察r的變化對結果的影響,對r從0.1到0.9取9個值,每個值模擬10000次。

n=100
rs=np.linspace(0.1, 0.9, 9)
m_choices=[]
m_rank=[]
m_fail=[]
for r in rs:
    print(r)
    a=int(round(n*r))
    choices = []
    rank = []
    fail = 0
    for i in range(0,10000):
        nums=np.random.uniform(0, 100, size=n)
        c=choose(nums)
        c.get_max(a)
        c.decide()
        choices.append(c.choice)
        rank.append(sum(c.nums>c.choice)+1)
        if c.flag == 0:
            fail += 1
    
    m_choices.append(np.mean(choices))
    m_rank.append(np.mean(rank))
    m_fail.append(fail)

r對選擇結果的影響:

plt.plot(rs,m_choices)

plt.plot(rs,m_fail)

當r較大時,很容易在後續數字中找不到更大的,從而獲得較差的最終選擇。

n=10,觀察r的變化對結果的影響,對r從0.1到0.9取9個值,每個值模擬10000次。

plt.plot(rs,m_choices)

plt.plot(rs,m_fail)

當n較小時,雖然隨着r的增大,在後續數字中找不到更大的數字的概率也是近乎線性增大,但是如果a太小則選不到較大的閾值,因此r在0.1到0.9之間存在最優解。

這啓示我們,當基數n較大時,r的取值可適當減小,以便獲得更優的結果。

4.進一步討論

可以看到,對於該方法,當在後續數字中找不到更大的數字時,只能被迫選擇最後一個數字,導致結果較差。一個後續改進的思路是,當在一段時間內(第a個數字後的一些數字中)未發現更好的時,應適當降低要求。

對於不同的n,存在不同r的最優取值,n越大,r的最優取值越小。

如果原數據服從其他分佈規律,如卡方分佈,F分佈等,則結果可能有不同的表現,可能需要根據不同的分佈採取不同的策略。

實際上,迴歸相親問題,現實情況遠比該數學問題複雜的多,首先每個人有自己的特點,不能被很好地量化打分,即使打分也是各方面表現有不同的分數,其次,n是不可控的,且人的思維都是不斷髮展變化的,挑選者不可能一成不變地遵循一個死板的策略,被挑選者也不一定在被挑選後即接受。最後,且行且珍惜。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章