zoukankan      html  css  js  c++  java
  • 过程选择模型

    前段时间看到赵玉平老师讲的关于相亲选择的问题,感觉比较有趣,希望通过概率模拟验证一下该方法的有效性。

    原链接如下,感兴趣可先了解原讲解:管理学博士是怎么硬核相亲的,过程太真实了,最后居然选到这么好的“对象”!强烈建议大家学学…… %相亲    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是不可控的,且人的思维都是不断发展变化的,挑选者不可能一成不变地遵循一个死板的策略,被挑选者也不一定在被挑选后即接受。最后,且行且珍惜。

  • 相关阅读:
    python-多任务-进程
    注解_Annotation
    ZIP压缩输入/输出流
    什么是API,这篇文章让你豁然开朗
    异常处理(在控制台输入数据)
    控件监听与面板监听
    多态与继承
    Java——socketser与cli
    20170307
    20180305
  • 原文地址:https://www.cnblogs.com/dingdangsunny/p/15664646.html
Copyright © 2011-2022 走看看