该工具能否计算“投入k抽,能抽到道具个数的分布”
作者您好,我在文档里发现了这样一个问题“投入k抽,能抽到道具个数的分布”,并粗略阅读了一下教程和源码,并未发现能解决上述问题的简便方法。想问一下是否是我遗漏了哪些实现。
该问题可以有效帮助那些抽卡资源已知的玩家评估中奖概率。
这个问题我目前没有计算复杂度较低的方法,只能为每个单独的情况编写动态规划算法进行计算,复杂度为 $O(k^2)$。以前的老代码里有对应的实现,见这份代码里的 luck_evaluate 函数,大概是先算恰好在第 1-k 抽抽到 0-k 个道具的分布,再计算恰好第 k 抽时得到道具的分布。这样的算法是精确的,但是其编写实在是不够灵活,只能解决少部分问题,因此新的工具包中没有再采取这样的实现了。
如果使用新的工具包,我目前推荐采用曲折一点点的方法:先得到获取 0-k 个道具的抽数分布,以此得到 k 抽时获取大于等于 n 个道具的概率,然后再差分得到恰好获取 0-k 个道具的概率。
以原神为例,如果抽k抽,最多可以抽到k个道具可以调用 GI.up_5star_character(item_num=k, multi_dist=True) 返回获取 1-k 个道具所需的抽数分布,然后获得列表中每个情况分布的 cdf,然后提取第 k 抽的数值,最后做差分得到投入 k 抽能得到道具个数的分布。
这样的方法可以对所有情况的问题都适用,不过这样的复杂度有点高,使用也不尽然方便,考虑之后研究一下怎么方便的处理这个问题,或许会写个新的函数。
我刚刚想到一个方法,在中奖率普遍较低的情况下可以忽略长尾,用较小的计算量获得主体分布情况。 假设我们想知道砸200抽抽出0~7个奖品的概率分布(出8个概率极低,后续概率忽略不计),可以分别计算抽出i个奖品的抽数分布,再将前200抽出货的概率求和,即可得到200抽抽出i个奖品的(精确?)概率
是的,完全可以忽略概率太低的长尾部分,刚刚去写代码去了,你可以参考以下实现:
import GGanalysis.games.genshin_impact as GI
import numpy as np
from GGanalysis import *
k = 360
# 计算获得 0-k 个道具所需抽数分布并以列表形式返回,因为原神 360 抽几乎不能抽超过10个UP五星,因此设置为10以减小计算量
distributions = GI.up_5star_character(10, multi_dist=True)
def calc_item_num_dist(dist_list: list[FiniteDist], pull):
'''根据输入获得 0-k 个道具所需抽数分布列表计算pull抽时获得道具数量分布'''
item_num = len(dist_list) - 1
ans = np.zeros(item_num+1)
for i in range(0, item_num+1):
if len(dist_list[i]) <= pull+1:
ans[i] = 1
else:
ans[i] = dist_list[i].cdf[pull]
ans[0:-1] -= ans[1:].copy()
return FiniteDist(ans)
# 获得能得到道具数量的分布,其中最末尾分布表示大于等于这个数量道具数的和
item_num_dist = calc_item_num_dist(distributions, k)
# 画图
from matplotlib import pyplot as plt
plt.fill_between(range(len(item_num_dist)), 0, item_num_dist[:], alpha=0.5, step='mid', edgecolor='none')
plt.step(range(len(item_num_dist)), item_num_dist[:], where='mid')
plt.show()
不过怎么自动估计长尾部分我没有做,最后还需要对画出来的图判断一下是不是想要的部分。
这玩意工作正常的话我就找地方塞到主分支里,看看还有啥可以优化的空间没?比如接口定义啥的,然后找机会写到文档里
测试了一下,(1999的常驻池)跟我算出来的结果一样,也跟暴力模拟的结果接近
长尾判断可以是累积概率超过99.99%就break
接口什么的我没意见
那我想想以怎样的形式加入工具包可以兼顾计算速度和使用方便,这条issue就先挂在这里。 话说1999好像最近加了新卡池啊?啥情况的卡池啊?
一个带200井+大小保底机制的池
打扰一下,请问是否能实现同时计算多个卡池的情况呢;比如以星铁举例:我目前有k抽,打算要先抽出n个up光锥,把剩下的全都投入up角色池中,输出此时能够得到up角色的分布这样?可能表述不严谨十分抱歉:D
这种问题我没想到办法简单计算,所以不打算合并到工具包里。具体计算你可以参考以下思路: 计算抽出n个up光锥所需抽数分布(这个工具包里有了),然后枚举需要k抽,对于每种情况计算能抽多少个up角色(就是这个issue上面的实现)。最后把所有情况的分布加到一起就行,这个实现不复杂,就是把现有功能组合一下就行,但是效率不高,你可以试试自己实现一下。