根据一些外部值生成分布
Generate a distribution based on some external value
假设我有四种货币,我想随机选择一种:
Bronze, Silver, Gold, Platinum
基于一些 "rating" 值,我想为每种货币分配一个概率以使其有机会被选中。假设这个评级值是从 0.0 - 5.0
现在,如果我的评级较高,我想将分布加权到白金一侧,如果我的评级较低,则将其加权到青铜一侧。
所以 5.0 的评分可能如下所示:
Bronze: 0.0, Silver: 0.10, Gold: 0.30, Platinum: 0.60
同样,评分 0.0 可能如下所示:
Bronze: 0.60, Silver: 0.30, Gold: 0.10, Platinum: 0.0
2.5 的评级在中间货币之间的分布可能看起来更均匀。
我真的想不出一种算法来处理这个问题。如何根据控制分布的某个值生成 100% 的分布?有谁知道我可以从哪里开始?
一个简单的答案是用 4 条直线拟合您拥有的数据,然后收工。
一个更灵活的方法是以你喜欢的任何方式定义4个非负的相对权重函数,比如bronze(r)
、silver(r)
、gold(r)
、platinum(r)
.然后你定义 total(r) = bronze(r) + silver(r) + gold(r)+ platinum(r)
。而现在青铜的概率是bronze(r)/total(r)
.
这种方法的优点是您可以像这样使用函数:bronze(r) = 4 * 0.3^r
、silver(r) = 2 * 0.7^r
、gold(r) = 1
、platinum(r) = 0.1 * 1.8^r
。现在最有可能是 r=0
青铜。在 r=1
银最有可能。在 r=2
黄金是最有可能的。在 r=5
铂金是最有可能的。
您应该尝试各种功能,并确定您的游戏最耐玩的结果。
这是一些想法/草图,为此我可能应该受到统计学家的惩罚(至少在执行方面)。我假设这不是一个大规模的拟合问题,可能需要其他方法。
大体思路是:使用一个dirichlet-distribution来生成最终的分布。狄利克雷分布本身也有参数(参见 wiki),由于对称性,我们在这里使用正态分布,并且只需要 2 个参数(我们可以固定方差,这样我们只需要任务中定义的一个变量;方差仍然是一个设计参数来控制这个标量 -> dist 函数的映射;实际上这也可以在一些一维优化问题中用作优化变量,这不是微不足道的,因为可能是非凸的,我们得到了非快速-评估函数)作为定义狄利克雷分布的内部分布。
这是一些示例代码 (python),这可能是理论上的噩梦,而且就 numpy/scipy-usage 而言也不是那么好,但是嘿,这只是一个示例:
import numpy as np
from scipy.stats import norm
def get_sample(param):
# location = mean shifted because of the task (symmetry not at zero!)
outer_normal = np.array([norm.pdf(x, scale=1, loc=param-2.5) for x in np.linspace(-1, 1, 4)])
# shifting (we need positive reals as dirichlet-input) maybe critical in terms of theory
shifted_outer_normal = outer_normal + np.amin(outer_normal)
return np.random.dirichlet(shifted_outer_normal)
# Try 3 values (borders + mean) and sample 1000 times each; calculate means
print(np.mean([get_sample(0) for i in range(1000)], axis=0)) # input: 0
print(np.mean([get_sample(2.5) for i in range(1000)], axis=0)) # input: 2.5
print(np.mean([get_sample(5) for i in range(1000)], axis=0)) # input: 5
输出:
[ 0.73142688 0.21514722 0.04402889 0.00939702] # remark: only approximating sum=1 as independent means
[ 0.21711426 0.27841426 0.28205054 0.22242094]
[ 0.00943747 0.04039373 0.22860444 0.72156436]
如果 {Bronze, Silver, Gold, Platinum} 设置在 x 轴位置 {0, 1, 2, 3]} 上,我们可以想象权重呈三角形,可以在 0 和 3 之间移动速率从 0 变为 5 时的光标。
三角形由 3 个点定义:左、中(峰)、右
center = rate * 3 / 5
这样做,当速率= 0时中心= 0,当速率= 5时中心= 3
left = center - 2.5
和
right = center + 2.5
这样的分布可以在OpenTURNS中定义,只需写
dist = ot.Triangular(left, center, right)
然后,必须对其进行转换以满足您的需求。事实上,由于结果必须是 {0, 1, 2, 3} 之间的整数值,我们必须在 -0.5 左侧和 3.5 右侧截断此分布,然后将其四舍五入为最接近的整数,例如 [-0.5, 0.5[ => 0, [0.5, 1.5[=> 1, [1.5, 2.5[ => 2, [2.5, 3.5]=> 3
这是构建参数分布的代码:
import openturns as ot
def distribution (r):
# Define ot.Triangular()
center = r * 3 / 5
left = center - 3
right = center + 3
dist = ot.Triangular(left, center, right)
# Truncate ot.Triangular()
trunc = ot.TruncatedDistribution(dist, -0.5, 3.5)
# Transforme the distribution to round its realizations
f = ot.PythonFunction(1, 1, lambda x: [round(x[0])])
round_distribution = ot.CompositeDistribution(f, trunc)
return round_distribution
尝试一下:
# draw a sample of size 5 when rate = 0
rate = 0
print(distribution (rate).getSample(5)
>>> [ X0 ]
0 : [ 1 ]
1 : [ 0 ]
2 : [ 1 ]
3 : [ 0 ]
4 : [ 0 ]
青铜 (0) 和银 (1) 更有可能被抽到。
当 rate = 5 时,相同的操作将给出:
[ X0 ]
0 : [ 3 ]
1 : [ 2 ]
2 : [ 3 ]
3 : [ 3 ]
4 : [ 1 ]
在这种情况下 'Bronze' 的概率为 0。
假设我有四种货币,我想随机选择一种:
Bronze, Silver, Gold, Platinum
基于一些 "rating" 值,我想为每种货币分配一个概率以使其有机会被选中。假设这个评级值是从 0.0 - 5.0
现在,如果我的评级较高,我想将分布加权到白金一侧,如果我的评级较低,则将其加权到青铜一侧。
所以 5.0 的评分可能如下所示:
Bronze: 0.0, Silver: 0.10, Gold: 0.30, Platinum: 0.60
同样,评分 0.0 可能如下所示:
Bronze: 0.60, Silver: 0.30, Gold: 0.10, Platinum: 0.0
2.5 的评级在中间货币之间的分布可能看起来更均匀。
我真的想不出一种算法来处理这个问题。如何根据控制分布的某个值生成 100% 的分布?有谁知道我可以从哪里开始?
一个简单的答案是用 4 条直线拟合您拥有的数据,然后收工。
一个更灵活的方法是以你喜欢的任何方式定义4个非负的相对权重函数,比如bronze(r)
、silver(r)
、gold(r)
、platinum(r)
.然后你定义 total(r) = bronze(r) + silver(r) + gold(r)+ platinum(r)
。而现在青铜的概率是bronze(r)/total(r)
.
这种方法的优点是您可以像这样使用函数:bronze(r) = 4 * 0.3^r
、silver(r) = 2 * 0.7^r
、gold(r) = 1
、platinum(r) = 0.1 * 1.8^r
。现在最有可能是 r=0
青铜。在 r=1
银最有可能。在 r=2
黄金是最有可能的。在 r=5
铂金是最有可能的。
您应该尝试各种功能,并确定您的游戏最耐玩的结果。
这是一些想法/草图,为此我可能应该受到统计学家的惩罚(至少在执行方面)。我假设这不是一个大规模的拟合问题,可能需要其他方法。
大体思路是:使用一个dirichlet-distribution来生成最终的分布。狄利克雷分布本身也有参数(参见 wiki),由于对称性,我们在这里使用正态分布,并且只需要 2 个参数(我们可以固定方差,这样我们只需要任务中定义的一个变量;方差仍然是一个设计参数来控制这个标量 -> dist 函数的映射;实际上这也可以在一些一维优化问题中用作优化变量,这不是微不足道的,因为可能是非凸的,我们得到了非快速-评估函数)作为定义狄利克雷分布的内部分布。
这是一些示例代码 (python),这可能是理论上的噩梦,而且就 numpy/scipy-usage 而言也不是那么好,但是嘿,这只是一个示例:
import numpy as np
from scipy.stats import norm
def get_sample(param):
# location = mean shifted because of the task (symmetry not at zero!)
outer_normal = np.array([norm.pdf(x, scale=1, loc=param-2.5) for x in np.linspace(-1, 1, 4)])
# shifting (we need positive reals as dirichlet-input) maybe critical in terms of theory
shifted_outer_normal = outer_normal + np.amin(outer_normal)
return np.random.dirichlet(shifted_outer_normal)
# Try 3 values (borders + mean) and sample 1000 times each; calculate means
print(np.mean([get_sample(0) for i in range(1000)], axis=0)) # input: 0
print(np.mean([get_sample(2.5) for i in range(1000)], axis=0)) # input: 2.5
print(np.mean([get_sample(5) for i in range(1000)], axis=0)) # input: 5
输出:
[ 0.73142688 0.21514722 0.04402889 0.00939702] # remark: only approximating sum=1 as independent means
[ 0.21711426 0.27841426 0.28205054 0.22242094]
[ 0.00943747 0.04039373 0.22860444 0.72156436]
如果 {Bronze, Silver, Gold, Platinum} 设置在 x 轴位置 {0, 1, 2, 3]} 上,我们可以想象权重呈三角形,可以在 0 和 3 之间移动速率从 0 变为 5 时的光标。
三角形由 3 个点定义:左、中(峰)、右
center = rate * 3 / 5
这样做,当速率= 0时中心= 0,当速率= 5时中心= 3
left = center - 2.5
和
right = center + 2.5
这样的分布可以在OpenTURNS中定义,只需写
dist = ot.Triangular(left, center, right)
然后,必须对其进行转换以满足您的需求。事实上,由于结果必须是 {0, 1, 2, 3} 之间的整数值,我们必须在 -0.5 左侧和 3.5 右侧截断此分布,然后将其四舍五入为最接近的整数,例如 [-0.5, 0.5[ => 0, [0.5, 1.5[=> 1, [1.5, 2.5[ => 2, [2.5, 3.5]=> 3
这是构建参数分布的代码:
import openturns as ot
def distribution (r):
# Define ot.Triangular()
center = r * 3 / 5
left = center - 3
right = center + 3
dist = ot.Triangular(left, center, right)
# Truncate ot.Triangular()
trunc = ot.TruncatedDistribution(dist, -0.5, 3.5)
# Transforme the distribution to round its realizations
f = ot.PythonFunction(1, 1, lambda x: [round(x[0])])
round_distribution = ot.CompositeDistribution(f, trunc)
return round_distribution
尝试一下:
# draw a sample of size 5 when rate = 0
rate = 0
print(distribution (rate).getSample(5)
>>> [ X0 ]
0 : [ 1 ]
1 : [ 0 ]
2 : [ 1 ]
3 : [ 0 ]
4 : [ 0 ]
青铜 (0) 和银 (1) 更有可能被抽到。
当 rate = 5 时,相同的操作将给出:
[ X0 ]
0 : [ 3 ]
1 : [ 2 ]
2 : [ 3 ]
3 : [ 3 ]
4 : [ 1 ]
在这种情况下 'Bronze' 的概率为 0。