根据距离生成具有给定平均乘积的数字的算法

algorithm to generate numbers which have a given average product based on distance

提问人:woot 提问时间:10/14/2023 最后编辑:woot 更新时间:10/17/2023 访问量:65

问:

我正在尝试提出一种算法,该算法根据距离生成具有给定平均乘积的数字。例如,假设 x 轴上有 4 个点,x1、x2、x3 和 x4。每个点都有一个位置和一个值。x1 的位置是 x=1,x2 的位置是 x=2,依此类推。所以这意味着 x1 和 x2 之间的距离是 1,而 x2 和 x4 之间的距离是 2,依此类推。

我正在寻找一种方法来生成 x 值,以便它们的平均乘积等于给定的数字。因此,对于每个距离,我们将有一个方程式

d=3:(1/2) * (n1*n4 + n4*n1) = 平均值1

d=2:(1/4) * (n1*n3 + n2*n4 + n3*n1 + n4*n2) = 平均值2

d=1:(1/6) * (n1*n2 + n2*n3 + n3*n4 + n2*n1 + n3*n2 + n4*n3) = 平均值3

d=0:(1/4) * (n1^2 + n2^2 + n3^2 + n4^2) = 平均值4

我尝试将平均值设置为小整数,然后设置 n1=1 并从那里开始。由此产生的代数给我留下了一个没有解的系统。我一直在使用点之间的距离矩阵来帮助可视化正在发生的事情。我假设一个人可以自由地选择x1,就像种子一样,然后尝试根据它推导出其他点。

算法 统计 数学优化

评论

0赞 Pauly 10/14/2023
您好,我不确定您所说的“n1n4”是什么意思,如果您的意思是 x1 * x4,那么:您的输入将是 avg1、avg2、avg3 和 avg4。所以如果 avg4 = 0,所有点都必须在 0,x1 = x2 = x3 = x4 = 0 所以 avg1 = avg2 = avg3 = avg4 = 0 所以是的,有时不存在解决方案(例如输入:avg4 = 0,avg1 = 1 没有解决方案)我理解正确吗?
0赞 woot 10/14/2023
@Pauly我编辑了这篇文章以包含乘法符号,很抱歉不清楚。是的,给定平均值和点之间的距离,有没有办法生成点值,以便所有条件都成立。你能想出一个存在解决方案的例子吗?
0赞 Reinderien 10/17/2023
您能提供 avg1、2、3、4 的典型值吗?
0赞 Dave 10/17/2023
这有 n 个具有 n 个未知数的方程。
0赞 woot 10/18/2023
@Reinderien例如,avg4=10、avg3=6、avg2=2、avg1=1。

答:

2赞 Reinderien 10/17/2023 #1

此操作的内部是非线性的。它可能更好地表示为二次规划 (QP) 问题,但由于 scipy 不直接支持这些问题,我用泛型 .minimize

最好预先计算一个三维因子矩阵,其中包含距离、第一个 n 指数和第二个 n 指数的维度;然后在优化过程中使用一个来简化为均值向量。然后可以从目标均值中减去这些均值,并应用自点积来获得最小二乘成本。einsum

import numpy as np
from scipy.optimize import minimize

N = 4


def make_factors() -> np.ndarray:
    factors = np.empty((N, N, N))

    for d in range(N):
        if d == 0:
            num = 1
        else:
            num = 0.5
        diag = np.full(shape=N - d, fill_value=num/(N - d))
        addend = np.diag(v=diag, k=d)
        factors[d, ...] = addend
        if d != 0:
            factors[d, ...] += addend.T

    return factors


def actual_mean(params: np.ndarray, factors: np.ndarray) -> np.ndarray:
    # Equivalent to factors[i, ...] dot outer(params, params)
    return np.einsum('ijk,j,k->i', factors, params, params)


def cost(params: np.ndarray, factors: np.ndarray, target_means: np.ndarray) -> float:
    error = actual_mean(params, factors) - target_means
    return error.dot(error)


def solve(factors: np.ndarray, target_means: np.ndarray) -> np.ndarray:
    '''
    d=1: 1/2(N-1) * (2(N-1)n^2) = mean1
    n = sqrt(mean1) for x0
    '''
    x0 = np.full(shape=N, fill_value=np.sqrt(target_means[1]))

    result = minimize(
        fun=cost,
        x0=x0,
        args=(factors, target_means),
    )
    if not result.success:
        raise ValueError(result.message)
    return result.x


def main() -> None:
    factors = make_factors()
    target_means = np.array((3.4, 3.7, 3.3, 2.5))
    fit = solve(factors, target_means)
    print('n =', fit)
    print(target_means, '~', actual_mean(fit, factors))


if __name__ == '__main__':
    main()
n = [1.57903356 2.09332332 2.09332332 1.57903356]
[3.4 3.7 3.3 2.5] ~ [3.43767474 3.66428601 3.30542776 2.49334698]

评论

0赞 woot 10/18/2023
不错的解决方案!谢谢!