[原神科普] 一篇关于《原神》抽卡概率/期望计算的正经介绍(上)
Imagine076
编辑于 2026年04月02日 17:02
收录于文集
共2篇

注:本文的正确性建立在目前广为流传的一份角色池与武器池单抽出货概率数据之上,详见文章 2.1 与 2.3 部分。

0  省流版

角色池:

  • 从零开始抽出一个五星角色期望抽数:62.3,中位抽数:75,最大概率抽数:77

  • 从零开始抽出一个目标 UP 五星角色期望抽数:93.4,中位抽数:80,最大概率抽数:77

  • 从零开始抽出满命目标 UP 五星角色期望抽数:654.1,中位抽数:653,最大概率抽数:644

武器池:

  • 从零开始抽出一个五星武器期望抽数:53.3,中位抽数:64,最大概率抽数:66

  • 从零开始抽出一个目标 UP 五星武器期望抽数:86.5,中位抽数:78,最大概率抽数:66

  • 从零开始抽出满精目标 UP 五星武器期望抽数:432.7,中位抽数:433,最大概率抽数:464

能衡量“欧非”程度的最直接指标是在前多少抽内出货的累计概率。上述六种情况的累积概率图象见文章 2.2 与 2.3 对应部分。

1  文章介绍

每一位热衷于或受苦于在《原神》中抽卡的玩家都希望有一个直观的指标来帮助自己判断自己的“欧非”程度。此时,出货关于抽数的概率分布以及出货的期望次数成为了玩家们想要获取到的信息。然而,大部分对概率与期望计算方法较为陌生的玩家面对游戏抽卡说明中的一堆数据表现得茫然。打开一些相关视频的评论区,你甚至能找到“抽卡保底数是 90,所以期望出货次数就是 90”这样的评论。

本文的目的便是教会你正确计算出“省流版”部分中给出的所有数据,并对《原神》抽卡模型的设计进行一定的分析。

2  主要流程

2.1  基础数据获取

我们首先以角色 UP 池为例。

要想进行具体的计算,我们首先需要获取到单抽得到五星角色(即“出货”)的概率。你可能会认为,在祈愿说明中给出的“5 星角色祈愿的基础概率为 0.600%5C%25”正是我们所需要的数据,实则不然。否则,如果每抽出货的概率恒定,不会产生 90 抽保底的机制。

我们从一些地方可以获取到这样一个函数:在累计 i-1 次抽卡后,第 i 次出货的概率 p(i) 满足

p(i)%20%3D%20%5Cbegin%7Bcases%7D0.006%2C%20%26i%20%3C%2074%2C%5C%5C%20%5Cmin%5C%7B1%2C%20p(i%20-%201)%20%2B%200.06%5C%7D%2C%20%26i%20%5Cgeq%2074.%5Cend%7Bcases%7D

也即,前 73 次抽卡出货的概率均为 0.6%5C%25,从第 74 抽开始,概率每抽增长 6%5C%25,直到 100%5C%25

这是目前网络上流传最广泛的单抽概率数据。这一函数的深层来源我们不得而知,但它的确满足这样一些基本条件:以 0.6%5C%25 作为基础概率;保底为 90 抽;主观上满足抽卡的实际情形;表示形式较为简单(这样的概率的设计可能需要经过较多推敲,但最终形式往往不会复杂)。我们姑且信之,并将其用于接下来的具体计算。

2.2  具体计算

2.2.1  抽五星(忽略 UP 与否)角色

我们首先计算从零开始抽卡出货(仅考虑五星,忽略 UP 与否)关于抽数的概率分布。

P(i) 表示从零开始恰好在第 i 抽出货的概率。也许你可以轻易地写出 P(i)%20%3D%20p(i)%20%5Ccdot%20%5Cprod_%7Bj%20%3D%201%7D%5E%7Bi%20-%201%7D(1%20-%20p(j)),但在这里,我们用一个略显复杂的方式表示它:再设 f(i) 表示前 i均没有出货的概率,从而列出方程组:

%5Cbegin%7Bcases%7Df(0)%20%3D%201%2C%20%5C%5C%20f(i)%20%3D%20f(i%20-%201)%20%5Ccdot%20(1%20-%20p(i))%2C%20%26i%20%3D%201%2C%202%2C%20%5Ccdots%2C%2090.%5Cend%7Bcases%7D

并且有

P(i)%20%3D%20f(i%20-%201)%20%5Ccdot%20p(i)%2C~~~%20i%20%3D%201%2C%202%2C%20%5Ccdots%2C%2090.

这样表示的好处我们很快就会看到。依据该方程组的形式,我们可以迭代地从 f(0) 开始依次计算 f(1)%2C%20P(1)%2C%20%5Ccdots%2C%20f(90)%2C%20P(90)。出货的期望抽数 E%20%3D%20%5Csum_%7Bi%20%3D%201%7D%5E%7B90%7Di%20%5Ccdot%20P(i)

我们简单地写一份 Python 代码完成这一计算并输出结果:

代码块
Python
自动换行
复制代码
import matplotlib.pyplot as plt
import numpy as np

PITY = 90

f = np.zeros(PITY)
result = np.zeros(PITY + 1)
single_rate = [0.006] * (PITY + 1)
for i in range(74, 91):
  single_rate[i] = min((1.0, single_rate[i - 1] + 0.06))

### Calculate
f[0] = 1
for i in range(0, PITY):
  if i + 1 < PITY:
    f[i + 1] = f[i] * (1 - single_rate[i + 1])
  result[i + 1] += f[i] * single_rate[i + 1]

presum = np.zeros(PITY + 1)
expect = 0
for i in range(1, PITY + 1):
  presum[i] = presum[i - 1] + result[i]
  expect += result[i] * i
  print("%i: %.10lf %.10lf" % (i, result[i], presum[i]))
print("Expect: %.6lf" % (expect))
print("Debug: %.10lf" % (presum[PITY]))

### Draw function image
fig, ax = plt.subplots(2, 1)
ax[0].plot(np.arange(0, PITY + 1), result * 100)
ax[1].plot(np.arange(0, PITY + 1), presum * 100)
for i in range(0, 2):
  ax[i].grid(True)
  ax[i].set_ylabel('(%)')
  ax[i].set_xlim([0, PITY])
ax[0].set_ylim([0, 11])
ax[1].set_ylim([0, 102])
ax[1].set_xlabel('Pulls')
plt.savefig('result')
plt.show()
复制成功

输出的期望抽数 E_1%20%3D%2062.297332P(i) 本身及其前缀和关于抽数的图象如下(前缀和则表示在前 i 抽内出货的概率,这便是衡量“欧非”程度的最直接指标):

P(i) 图象的峰值位于点 (77%2C%200.105) 处,这表明从零开始抽卡,最有可能在第 77 抽时出货,概率约为 10.5%5C%25。前缀和图象的 50%5C%25 对应的抽数在 7576 之间,距 75 更近,这表明中位抽数约为 75。至此,我们得到了“省流版”中的第一行数据。

2.2.2  抽五星 UP 角色

当我们的目标仅落在 UP 角色上时,一些潜在的变量被引入了进来:是否是大保底,以及若是大保底,又已经累计了多少抽。在 2.2.1 部分中仅用一个变量 i 控制函数 f 便不再可取。

仍设 P(i) 表示从零开始恰好在第 i 抽出货的概率。设 f(i%2C%20j%2C%20x)(x%20%5Cin%20%5C%7B0%2C%201%5C%7D) 表示在前 i 抽没有抽到目标 UP 角色,且保底情况为 x0 为小保底,1 为大保底),保底累计抽数为 j 的概率。注意到当处于小保底时,有 0.5 的概率获取到想要的 UP 角色,还有 0.5 的概率“歪”,因此可以列出方程组:

%5Cbegin%7Bcases%7D%0Af(0%2C%200%2C%200)%20%3D%201%2C%20%5C%5C%0Af(i%2C%20j%2C%20x)%20%3D%20f(i%20-%201%2C%20j%20-%201%2C%20x)%20%5Ccdot%20(1%20-%20p(j))%2C%20%26i%20%3D%201%2C%20%5Ccdots%2C%20180%2C%20~%20j%20%3D%201%2C%20%5Ccdots%2C%20%5Cmin%5C%7Bi%2C%2090%5C%7D%2C%20~%20x%20%3D%200%2C%201%2C%20%5C%5C%0Af(i%2C%200%2C%201)%20%3D%20f(i%20-%201%2C%20i%20-%201%2C%200)%20%5Ccdot%20p(i)%20%5Ccdot%200.5%2C%20%26i%20%3D%201%2C%20%5Ccdots%2C%2090.%20%26%20%26%0A%5Cend%7Bcases%7D

并且有

P(i)%20%3D%0A%5Cbegin%7Bcases%7D%0Af(i%20-%201%2C%20i%20-%201%2C%200)%20%5Ccdot%20p(i)%20%5Ccdot%200.5%20%2B%20%5Csum_%7Bj%20%3D%201%7D%5E%7Bi%7Df(i%20-%201%2C%20j%20-%201%2C%201)%20%5Ccdot%20p(i)%2C%20%26%20i%20%5Cleq%2090%2C%20%5C%5C%0A%5Csum_%7Bj%20%3D%201%7D%5E%7B90%7Df(i%20-%201%2C%20j%20-%201%2C%201)%20%5Ccdot%20p(i)%2C%20%26%20i%20%3E%2090.%0A%5Cend%7Bcases%7D

关于 f 的方程组中的第三个方程的含义为:如果在小保底阶段抽中了五星角色,且为非 UP(概率为 0.5),则清空保底的累计抽数,进入大保底阶段。

利用含参量 f 来计算 P 的好处此时便得以体现——当需要考虑的情况变得复杂时,我们可以通过增加参数变量来沿用之前的计算方法。f 仍然可以迭代计算,只需要分别从小到大枚举 i%2C%20j

沿用上面部分的代码,做一些基础修改后,核心计算部分如下:

代码块
Python
自动换行
复制代码
MAX_PULLS = 180
PITY = 90

f = np.zeros((MAX_PULLS, PITY, 2))
result = np.zeros(MAX_PULLS + 1)

### Calculate
f[0][0][0] = 1
for i in range(0, MAX_PULLS):
  for j in range(0, min((i + 1, PITY))):
    if i + 1 < MAX_PULLS and j + 1 < PITY:
      for x in range(0, 2):
        f[i + 1][j + 1][x] += f[i][j][x] * (1 - single_rate[j + 1])
    if i + 1 < MAX_PULLS:
      f[i + 1][0][1] += f[i][j][0] * single_rate[j + 1] * 0.5
    result[i + 1] += f[i][j][0] * single_rate[j + 1] * 0.5
    result[i + 1] += f[i][j][1] * single_rate[j + 1]
复制成功

输出的期望抽数 E_2%20%3D%2093.445998。事实上,它恰好为 E_1%20%3D%2062.2973321.5 倍,这是因为若在小保底阶段就出 UP 角色,则期望抽数为 E_1,而若在大保底阶段才出 UP 角色,则期望抽数为 2E_1,因此 E_2%20%3D%200.5%20%5Ccdot%20E_1%20%2B%200.5%20%5Ccdot%202E_1%20%3D%201.5E_1P(i) 本身及其前缀和关于抽数的图象如下:

P(i) 图象的峰值位于点 (77%2C%200.0548) 处,这表明从零开始抽卡,最有可能在第 77 抽时出目标 UP 角色,概率约为 5.48%5C%25。前缀和图象的 50%5C%25 对应的抽数在 7980 之间,距 80 更近,这表明中位抽数约为 80