努力和运气哪个更重要?
尽人事听天命的简单模型(python 实现)
最近看到科普视频: 成功是靠运气还是靠努力【官方双语】【Veritasium真理元素】_哔哩哔哩_bilibili
其中提到了这样一个现象:成功人士更倾向于(主观地)把自身的成功归因于自己比其他人更加努力和勤奋, 但 (客观的)统计实验发现,运气对成功的重要性可能比大部分人认为的更多。视频在第 3:43 分钟开始介绍了一个简化的数学模型,用于说明运气对于成功的重要性,而本文则对该模型进行一点儿拓展分析。
运气和努力的简化模型
视频中对该实验的背景描述是:
- 2017 年 NASA 宇航员招募,申请者超过 18300 名,只有 11 个人最终被选中
- 模型的简化在于,每个申请者的综合能力都由两部分组成:代表申请者努力程度的技能得分(记为 skill)和运气值(记为 luck)
- 两个分数都是 0 到 100 之间的随机值
- 综合得分中,运气值只占得分的 5%, 也就是
score = 0.95*skill+0.05*luck
那么生成单个申请者的各个得分的函数如下:
import random
uniform = lambda: random.uniform(0, 100)
def one_sample(luck_prop=0.05, randfunc=uniform):
"""
luck_prop: float, the proportion of luck in the score
"""
skill = randfunc()
luck = uniform()
score = (1 - luck_prop) * skill + luck_prop * luck
return score, skill, luck
one_sample 的参数 randfunc 用于切换技能得分的不同随机函数,默认是 0 到 100 之间的连续型均匀分布,对于运气值,始终使用 0 到 100 之间的连续均匀分布,即运气对每个人的都是“公平”的。
print(one_sample())
(52.85789719560306, 54.785661143387834, 16.230382187692417)
以下 sample 函数则调用 one_sample n 次,生成 n 个申请者得分,这里还记录了各个申请者的编号,后文会用上。
def sample(n, luck_prop=0.05, randfunc=uniform):
"""
n: int, the number of samples
luck_prop: float, the proportion of luck in the score
"""
cands = []
for i in range(n):
cands.append((*one_sample(luck_prop, randfunc), i))
return cands
生成 3 个申请者的测试:
from pprint import pprint
pprint(sample(3))
[(27.78752881204626, 27.9861453646286, 24.013814312981808, 0), (48.31691707868798, 48.392010640481864, 46.89013940460421, 1), (91.69099470649425, 92.32843025137734, 79.57971935371589, 2)]
接着从 n 个申请者中选择得分最高的前 k 个,根据视频内容,作者统计了两个指标:
- 综合得分最高的 k 个申请者的平均运气得分:目的是看一看被选中的 k 个人是否都是“幸运的”
- 综合得分最高的 k 个申请者中有多少是技能得分最高的:目的是想知道,仅凭借技能得分最高的申请者中有多少能被选中。 因此以下函数中还对技能得分进行排序,然后计算出两类排序的前 k 个申请者的重叠数量,用 top_skill 变量表示。 (个人额外添加了 reverse 参数,用于统计技能分排名大于 reverse 的人占成功者的比例,在之后的实验中会具体使用)
def select_top(cands, k=10, reverse=0):
"""
cands: list, the list of candidates
n: int, the number of top candidates
"""
cands.sort(reverse=True)
topk = cands[:k]
random.shuffle(cands)
cands.sort(key=lambda x: x[1], reverse=True)
if reverse == 0:
topk_by_skill = cands[:k]
else:
topk_by_skill = cands[reverse:]
# the number of top candidates with the highest skill
top_skill = len(set(topk) & set(topk_by_skill))
return topk, top_skill
pprint(select_top(sample(100), k=2))
([(95.56512295727296, 95.44577419575496, 97.83274942611516, 23), (94.4838240779109, 95.04167955593897, 83.88456999537755, 54)], 1)
最后是完整的模拟:
运行实验 m 次,每次生成 n 个申请者,取综合得分最高的前 k 个申请者,统计这 k 个“成功者”的平均得分,以及其中有多少人的 skill 得分也是前 k 的。
def simulate(m=1000, n=1000, k=10, rand_name="uniform", reverse=0):
lucks = []
skills = []
total_scores = []
top_skills = 0
randfunc = randfunc_map[rand_name]
for i in range(m):
cands = sample(n, randfunc=randfunc)
topk, top_skill = select_top(cands, k, reverse)
luck_ave = sum([c[2] for c in topk]) / k
skill_ave = sum([c[1] for c in topk]) / k
total_scores.append(sum([c[0] for c in topk]) / k)
lucks.append(luck_ave)
skills.append(skill_ave)
top_skills += top_skill
luck = sum(lucks) / m
skill = sum(skills) / m
score = sum(total_scores) / m
print(f"top {k} from {n} candidates with {rand_name} distribution")
print(
f"成功者平均运气值: {luck:.2f}, 成功者平均技能值: {skill:.2f}, 成功者平均得分: {score:.2f}"
)
if reverse == 0:
print(
f"总分最高的 {k} 人中平均有 {top_skills/m:.2f} 人的纯技能得分也在前 {k}"
)
else:
print(
f"总分最高的 {k} 人中平均有 {top_skills/m:.2f} 人的纯技能得分在 {reverse} 名之后"
)
randfunc_map = {
"uniform": uniform,
}
以上 randfunc_map 是给每个随机函数取一个名字,方便打印和探索不同随机函数的效果。
模拟 18300 个申请者中选 11 个的实验:
simulate(m=200, n=18300, k=11)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.69, 成功者平均技能值: 99.72, 成功者平均得分: 99.47 总分最高的 11 人中平均有 1.63 人的纯技能得分也在前 11
视频里说到,11 个被选中者的平均运气得分是 94.7 (以上结果是 94.69), 而平均只有 1.6 (以上是 1.63) 个申请者仅凭技能就能进入前 11 名。
这说明以上代码和视频中的模拟程序应该是一致的。
对结果的分析
极端的例子
以上结论表明,要能在 1 万 8 千多人中脱颖而出,运气绝不能差,另外,即便技能分已经排到了前 11 名,但能最终选上的概率仍然只有大概 1/10 。
初次在视频中看到这个结果时,我感到了困惑,觉得这似乎不太合理,可能是视频里只突出了成功者的运气值,给人一种运气才是成功的关键的错觉,但以上结果还显示,“成功者”的平均技能也达到了 99.72, 接近于满分。因此技能分和运气值都是成功的必要条件,而不是充分条件(即不是仅靠运气或者实力就能“成功”)。
以下用一些极端的例子来更清晰地说明为什么运气很重要,以及是努力出了什么问题,使得运气看上去如此重要:
如果所有申请者的成绩都是 100 分,那么它们的最终得分只能完全由那 5% 的运气值决定,先在随机函数集合中加入一个使得所有人得分都是 100 的函数, 然后再次模拟:
randfunc_map = {
"uniform": uniform,
"same100": lambda : 100
}
simulate(m=200, n=18300, k=11, rand_name="same100")
top 11 from 18300 candidates with same100 distribution 成功者平均运气值: 99.97, 成功者平均技能值: 100.00, 成功者平均得分: 100.00 总分最高的 11 人中平均有 0.00 人的纯技能得分也在前 11
由于基数很大,选中的人运气值几乎都要是满分。而由于每个人都是技能最高者(18300 人并列第一),那么每人只有 11/18300 的概率被选中。
如果申请者基数变小:
simulate(m=200, n=50, k=11, rand_name="same100")
top 11 from 50 candidates with same100 distribution 成功者平均运气值: 88.18, 成功者平均技能值: 100.00, 成功者平均得分: 99.41 总分最高的 11 人中平均有 2.42 人的纯技能得分也在前 11
自然的,成功者的运气值可以不用那么高。
这可以说明,如果某个行业过于内卷,大家都把分数刷到最高,那么决定成功的确实只能靠运气了,而运气如果真的完全均匀随机的话,这实际是一种最公平的分配机制了。
不过这里的“卷”不一定是朝着高分的方向,如果所有人都得 0 分,那么成功也都是靠运气。
randfunc_map = {
"uniform": uniform,
"same100": lambda : 100,
"same0": lambda : 0
}
simulate(m=200, n=18300, k=11, rand_name="same0")
top 11 from 18300 candidates with same0 distribution 成功者平均运气值: 99.97, 成功者平均技能值: 0.00, 成功者平均得分: 5.00 总分最高的 11 人中平均有 0.01 人的纯技能得分也在前 11
如果大家都躺平,但资源又是有限的,成功者被“随机地”选择出来也是最为公平的策略了。
但额外考虑到这份工作本身需要的技术门槛,如果所有人都是 0 分,也不太可能从这些人里选出 11 个宇航员。
从这个例子可以看到,模拟程序所体现的“运气很重要”的观点并没有那么反直觉,之所以运气变得重要,是因为有足够多的人的技能得分高到足够接近,无法拉开差距,而规则又必须选出特定数量的人,那么必然有些得分足够高的人被淘汰掉。
努力的差异度
以上程序中,运气值总分是 100 ,占总比分的 5%, 也就是说,运气可以左右的分数是 0 到 5 分。现在考虑这样一种针对技能值的分布,它是离散的,每个技能都是 6 的倍数,这意味着,如果 A 的技能得分是 60, B 的技能分是 66, 那么即便 A 的运气值是 100, 给总分贡献了 5 分,B 的运气值为 0, 那么 A 的总分(65)也不可能超过 B (66)
randfunc_map = {
"uniform": uniform,
"same100": lambda : 100,
"same0": lambda : 0,
"gap6": lambda: random.randint(0, 100) * 6
}
simulate(m=200, n=18300, k=11, rand_name="gap6")
top 11 from 18300 candidates with gap6 distribution 成功者平均运气值: 96.78, 成功者平均技能值: 600.00, 成功者平均得分: 574.84 总分最高的 11 人中平均有 0.61 人的纯技能得分也在前 11
这种情况下,成功者平均技能基本只能是满分,因为按照 101 个点( [0,100] 闭区间)的均匀的离散分布性质, 18300 个人之中,大致也会有 180 人得到 600 分满分,从中只挑选 11 人,因此又变成了以上描述的极端例子的场景。
该分布下意味着,运气在不同技能分之间的重要度为 0, 在相同技能分但不是满分的人之间也是 0, 在都是满分的人之间则是 100% 。运气的重要性是非常“局部”的,这似乎给了成功人士在实力相近或更高的人之间唯唯诺诺、 对实力更低的人重拳出击的理由(如果技高一筹就是正义的话,或者纯粹按实力地位出发与人交谈,或者纯优绩主义 )
不努力的后果
视频里只谈论了成功者的运气值,同时谈到了那些技能分前 11 名的申请者只有 1.61/11 的概率最终入选。 但如果我们去看那些技能分数不是很高的申请者,有多大机会被选上?
以下调用中设置 reverse=20 ,那么函数会统计如果按照纯技术分进行排序, 20 名以后的的申请者中有多少人能够进入综合得分前 11 名。 或者可以放在考研/考公或其他求职场景里,假设复试基本靠临场发挥的运气,那么初始排在 20 名之后的申请者 有多大机会进入综合前 11 名。
simulate(m=200, n=18300, k=11, rand_name="uniform", reverse=20)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.71, 成功者平均技能值: 99.72, 成功者平均得分: 99.47 总分最高的 11 人中平均有 8.26 人的纯技能得分在 20 名之后
可以看到,尽管技能得分不是前 20 名,但依靠更高的运气值,也有平均 8.26 人能够“逆袭”被最终选中。
继续查看初试排名更低的申请者:
simulate(m=200, n=18300, k=11, rand_name="uniform", reverse=50)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.79, 成功者平均技能值: 99.72, 成功者平均得分: 99.48 总分最高的 11 人中平均有 4.88 人的纯技能得分在 50 名之后
simulate(m=200, n=18300, k=11, rand_name="uniform", reverse=100)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.85, 成功者平均技能值: 99.73, 成功者平均得分: 99.49 总分最高的 11 人中平均有 1.17 人的纯技能得分在 100 名之后
simulate(m=200, n=18300, k=11, rand_name="uniform", reverse=150)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.75, 成功者平均技能值: 99.72, 成功者平均得分: 99.47 总分最高的 11 人中平均有 0.09 人的纯技能得分在 150 名之后
simulate(m=200, n=18300, k=11, rand_name="uniform", reverse=200)
top 11 from 18300 candidates with uniform distribution 成功者平均运气值: 94.82, 成功者平均技能值: 99.72, 成功者平均得分: 99.48 总分最高的 11 人中平均有 0.00 人的纯技能得分在 200 名之后
从以上结果可以看到,在 18300 申请者中,如果纯技能得分在 150 名之后,那基本不可能被选上了,而这只有 150/18300 (0.8%) 的比例,也就是技能低于 99.3 分基本就与“成功”无缘。
成功悖论
在视频的最后,作者说到:
我认为最好的关于成功的建议是悖论性质的:
- 首先,你必须相信你能完全掌控自己的命运,你的成功只取决于你自己的天赋和努力工作
- 但第二,你必须知道这对你和其他人都不是真的,所以你必须记住,当你取得成功时,运气扮演了一个重要的角色, 并带给你幸运,而你应该尽你所能来带给别人好运。
我理解作者的核心目的是:
- 提醒成功者中那些过于趾高气昂的人,不要忽视运气在成功中的比重,不要觉得成功的一切都归因于自己的能力, 因此不要狂妄自大或苛责于那些没有那么“成功”的人,而是多给其他人提供机会,增加其他人成功的运气。
- 鼓励那些还没有成功的人:不要相信运气,努力就会有回报。
对于第一条,我认为视频中展现的模拟实验结论确实有一定的说服力,因为 11 个成功者中,技能得分也是前 11 名的只有 1.6 个,这意味着,即便成功了,在那些“失败者”中也有很多实力在你之上的人。 但这种谦虚态度的辐射范围是局部的,对于技能得分低的大部分人,成功者又有趾高气昂的“正当理由”。
对于 “多给其他人提供机会,增加其他人成功的运气”这个建议,实际无法从该简化模型中延伸出来,在该简化模型下, 成功人数是固定的,即便给所有人增加运气,也可能只是把运气的均匀分布范围从 0 到 100 变成了 50 到 100 , 对于结果不会有实质影响;而给“其他人提供机会”更像是创造更多的职位和工作,提供多元化的选择,这可能更贴近现实中运气的实际体现,比如某人高考调剂到当时被认为是冷门的专业,但毕业时市场变化了,该专业毕业生变得供不应求,一般就会被认为是“运气好”。
视频作者可能预设了大多数人认为努力是非常重要的,因此只用模拟的例子作为凸显“运气”重要性的一个论据,从而刻意只展现了成功者的平均运气值,而隐藏了成功者的平均技能值,只展现了技能分最高的人被选中的“低概率”, 而没有展示技能分如果低于 99.3 基本就是“失败”的统计事实,这可以认为是一种统计上的解释技巧。
然而,实际上视频作者也可以把更完整的结论展示出来,类似本文所做的,以此说明努力的重要性,从而作为第二条的有力论据。 仅从这个简化模型来看, 要能够成功,你必须足够努力,如果努力达不到门槛,运气的作用是微乎其微的,当开始进入到“成功”的视野时(例子中技能得分前 150 名),运气对成功的重要性才开始显现。(这里的假设是,运气在任何阶段都是独立的,并且无法预测,如果你能提前知道自己的运气值,比如发现只有 80 多,那么或许不应该参与如此多竞争者的活动了)
因此这个简化模型实际很好地说明了中国的古话 – 尽人事,听天命。
它还额外表明,前后两句话并不是独立的,“尽人事”是”听天命“的必要条件,只有尽人事了才能够听天命,也就是能够看到失败和成功的不确定性,并坦然接受不确定导向的具体结果。
如果没有尽人事,听到的天命可能是单一的 – 不成功。
但不要忘了这只是一个极其简化的玩具模型,你随时可以跳出去,跳出单一评价标准的赛道,去到技能得分跨度更大,分布更加友好的领域或者参与者更少的蓝海,从而在某种元层面(比如“选择”,选择游戏本身,选择消解掉趾高气昂或郁郁寡欢的“正当性”)重新赋予 "尽人事,听天命" 的意义。