将平面列表加权为正态分布
weighting a flat list to the normal distribution
我有任意长度的字符串项目列表,我需要 "normalize" 这个列表,以便每个项目都是正态分布的一部分,将权重附加到字符串。
除了我下面提供的方法之外,还有什么更有效的 mathematical/statistical 方法可以解决这个问题?
func normalizeAppend(in []string, shuffle bool) []string {
var ret []string
if shuffle {
shuffleStrings(in)
}
l := len(in)
switch {
case remain(l, 3) == 0:
l3 := (l / 3)
var low, mid, high []string
for i, v := range in {
o := i + 1
switch {
case o <= l3:
low = append(low, v)
case o > l3 && o <= l3*2:
mid = append(mid, v)
case o >= l3*2:
high = append(high, v)
}
}
q1 := 1600 / len(low)
q2 := 6800 / len(mid)
q3 := 1600 / len(high)
for _, v := range low {
ret = append(ret, fmt.Sprintf("%s_%d", v, q1))
}
for _, v := range mid {
ret = append(ret, fmt.Sprintf("%s_%d", v, q2))
}
for _, v := range high {
ret = append(ret, fmt.Sprintf("%s_%d", v, q3))
}
case remain(l, 2) == 0 && l >= 4:
l4 := (l / 4)
var first, second, third, fourth []string
for i, v := range in {
o := i + 1
switch {
case o <= l4:
first = append(first, v)
case o > l4 && o <= l4*2:
second = append(second, v)
case o > l4*2 && o <= l4*3:
third = append(third, v)
case o > l4*3:
fourth = append(fourth, v)
}
}
q1 := 1600 / len(first)
q2 := 3400 / len(second)
q3 := 3400 / len(third)
q4 := 1600 / len(fourth)
for _, v := range first {
ret = append(ret, fmt.Sprintf("%s_%d", v, q1))
}
for _, v := range second {
ret = append(ret, fmt.Sprintf("%s_%d", v, q2))
}
for _, v := range third {
ret = append(ret, fmt.Sprintf("%s_%d", v, q3))
}
for _, v := range fourth {
ret = append(ret, fmt.Sprintf("%s_%d", v, q4))
}
default:
var first, second, third []string
q1 := (1 + math.Floor(float64(l)*.16))
q3 := (float64(l) - math.Floor(float64(l)*.16))
var o float64
for i, v := range in {
o = float64(i + 1)
switch {
case o <= q1:
first = append(first, v)
case o > q1 && o < q3:
second = append(second, v)
case o >= q3:
third = append(third, v)
}
}
lq1 := 1600 / len(first)
lq2 := 3400 / len(second)
lq3 := 1600 / len(third)
for _, v := range first {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq1))
}
for _, v := range second {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq2))
}
for _, v := range third {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq3))
}
}
return ret
}
有人要求澄清:
我有一个项目列表,将通过加权选择一次从列表中多次选择一个项目,首先我有一个(隐含)权重为 1 的列表:
[a_1, b_1, c_1, d_1, e_1, f_1, g_1, h_1、i_1、j_1、k_1]
我正在寻找一种更好的方法来使该列表成为产生更多 'normal' 选择权重分布的东西:
[a_1, b_2, c_3, d_5, e_14, f_30, g_14, h_5、i_3、j_2、k_1]
或者我可能需要将我的方法更改为更基于统计的方法。底线是我想以多种方式控制从项目列表中进行选择,其中之一是确保项目以近似正态曲线的方式返回。
如果你只想计算给定列表的权重,那么你需要做以下事情:
- 正态分布的均值
- 正态分布的方差
- 值的离散化器
第一个很简单。您希望平均值位于列表的中心。因此(假设从零开始的索引):
mean = (list.size - 1) / 2
第二个有点随意,取决于你希望你的重量下降多陡。在距 mean
3 * standard_deviation
的距离之外,正态分布的权重实际上为零。因此,在大多数情况下,良好的标准偏差可能介于第四和第六列表长度之间:
standard_deviation = (1/4 .. 1/6) * list.size
variance = standard_deviation^2
假设你想要整数权重,你需要从正态分布中离散化权重。最简单的方法是指定最大权重(位于平均位置的元素)。
就是这样。位置 i
处元素的权重为:
weight[i] = round(max_weight * exp(-(i - mean)^2 / (2 * variance)))
我有任意长度的字符串项目列表,我需要 "normalize" 这个列表,以便每个项目都是正态分布的一部分,将权重附加到字符串。
除了我下面提供的方法之外,还有什么更有效的 mathematical/statistical 方法可以解决这个问题?
func normalizeAppend(in []string, shuffle bool) []string {
var ret []string
if shuffle {
shuffleStrings(in)
}
l := len(in)
switch {
case remain(l, 3) == 0:
l3 := (l / 3)
var low, mid, high []string
for i, v := range in {
o := i + 1
switch {
case o <= l3:
low = append(low, v)
case o > l3 && o <= l3*2:
mid = append(mid, v)
case o >= l3*2:
high = append(high, v)
}
}
q1 := 1600 / len(low)
q2 := 6800 / len(mid)
q3 := 1600 / len(high)
for _, v := range low {
ret = append(ret, fmt.Sprintf("%s_%d", v, q1))
}
for _, v := range mid {
ret = append(ret, fmt.Sprintf("%s_%d", v, q2))
}
for _, v := range high {
ret = append(ret, fmt.Sprintf("%s_%d", v, q3))
}
case remain(l, 2) == 0 && l >= 4:
l4 := (l / 4)
var first, second, third, fourth []string
for i, v := range in {
o := i + 1
switch {
case o <= l4:
first = append(first, v)
case o > l4 && o <= l4*2:
second = append(second, v)
case o > l4*2 && o <= l4*3:
third = append(third, v)
case o > l4*3:
fourth = append(fourth, v)
}
}
q1 := 1600 / len(first)
q2 := 3400 / len(second)
q3 := 3400 / len(third)
q4 := 1600 / len(fourth)
for _, v := range first {
ret = append(ret, fmt.Sprintf("%s_%d", v, q1))
}
for _, v := range second {
ret = append(ret, fmt.Sprintf("%s_%d", v, q2))
}
for _, v := range third {
ret = append(ret, fmt.Sprintf("%s_%d", v, q3))
}
for _, v := range fourth {
ret = append(ret, fmt.Sprintf("%s_%d", v, q4))
}
default:
var first, second, third []string
q1 := (1 + math.Floor(float64(l)*.16))
q3 := (float64(l) - math.Floor(float64(l)*.16))
var o float64
for i, v := range in {
o = float64(i + 1)
switch {
case o <= q1:
first = append(first, v)
case o > q1 && o < q3:
second = append(second, v)
case o >= q3:
third = append(third, v)
}
}
lq1 := 1600 / len(first)
lq2 := 3400 / len(second)
lq3 := 1600 / len(third)
for _, v := range first {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq1))
}
for _, v := range second {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq2))
}
for _, v := range third {
ret = append(ret, fmt.Sprintf("%s_%d", v, lq3))
}
}
return ret
}
有人要求澄清:
我有一个项目列表,将通过加权选择一次从列表中多次选择一个项目,首先我有一个(隐含)权重为 1 的列表:
[a_1, b_1, c_1, d_1, e_1, f_1, g_1, h_1、i_1、j_1、k_1]
我正在寻找一种更好的方法来使该列表成为产生更多 'normal' 选择权重分布的东西:
[a_1, b_2, c_3, d_5, e_14, f_30, g_14, h_5、i_3、j_2、k_1]
或者我可能需要将我的方法更改为更基于统计的方法。底线是我想以多种方式控制从项目列表中进行选择,其中之一是确保项目以近似正态曲线的方式返回。
如果你只想计算给定列表的权重,那么你需要做以下事情:
- 正态分布的均值
- 正态分布的方差
- 值的离散化器
第一个很简单。您希望平均值位于列表的中心。因此(假设从零开始的索引):
mean = (list.size - 1) / 2
第二个有点随意,取决于你希望你的重量下降多陡。在距 mean
3 * standard_deviation
的距离之外,正态分布的权重实际上为零。因此,在大多数情况下,良好的标准偏差可能介于第四和第六列表长度之间:
standard_deviation = (1/4 .. 1/6) * list.size
variance = standard_deviation^2
假设你想要整数权重,你需要从正态分布中离散化权重。最简单的方法是指定最大权重(位于平均位置的元素)。
就是这样。位置 i
处元素的权重为:
weight[i] = round(max_weight * exp(-(i - mean)^2 / (2 * variance)))