【发布时间】:2020-09-20 04:09:51
【问题描述】:
我们有 N 个用户,平均为 P。每个用户的点数,其中每个点是 0 到 1 之间的单个值。我们需要使用已知密度为 0.05 的正态分布来分配每个点的质量,因为这些点具有一些不确定性。此外,我们需要将质量包裹在 0 和 1 周围,例如0.95 处的点也将分配 0 左右的质量。我在下面提供了一个工作示例,它将正态分布分箱到 D=50 箱中。该示例使用 Python 类型模块,但如果您愿意,可以忽略它。
from typing import List, Any
import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
D = 50
BINS: List[float] = np.linspace(0, 1, D + 1).tolist()
def probability_mass(distribution: Any, x0: float, x1: float) -> float:
"""
Computes the area under the distribution, wrapping at 1.
The wrapping is done by adding the PDF at +- 1.
"""
assert x1 > x0
return (
(distribution.cdf(x1) - distribution.cdf(x0))
+ (distribution.cdf(x1 + 1) - distribution.cdf(x0 + 1))
+ (distribution.cdf(x1 - 1) - distribution.cdf(x0 - 1))
)
def point_density(x: float) -> List[float]:
distribution: Any = scipy.stats.norm(loc=x, scale=0.05)
density: List[float] = []
for i in range(D):
density.append(probability_mass(distribution, BINS[i], BINS[i + 1]))
return density
def user_density(points: List[float]) -> Any:
# Find the density of each point
density: Any = np.array([point_density(p) for p in points])
# Combine points and normalize
combined = density.sum(axis=0)
return combined / combined.sum()
if __name__ == "__main__":
# Example for one user
data: List[float] = [.05, .3, .5, .5]
density = user_density(data)
# Example for multiple users (N = 2)
print([user_density(x) for x in [[.3, .5], [.7, .7, .7, .9]]])
### NB: THE REMAINING CODE IS FOR ILLUSTRATION ONLY!
### NB: THE IMPORTANT THING IS TO COMPUTE THE DENSITY FAST!
middle: List[float] = []
for i in range(D):
middle.append((BINS[i] + BINS[i + 1]) / 2)
plt.bar(x=middle, height=density, width=1.0 / D + 0.001)
plt.xlim(0, 1)
plt.xlabel("x")
plt.ylabel("Density")
plt.show()
在此示例中为 N=1、D=50、P=4。但是,我们希望将这种方法扩展到 N=10000 和 P=100,同时尽可能快。我不清楚我们如何向量化这种方法。我们如何才能最好地加快速度?
编辑
更快的解决方案可能会产生略微不同的结果。例如,它可以近似正态分布,而不是使用精确的正态分布。
EDIT2
我们只关心使用user_density() 函数计算density。该情节仅用于帮助解释该方法。我们不关心情节本身:)
EDIT3
请注意,P 是平均值。每个用户的积分。一些用户可能拥有更多,而一些用户可能拥有更少。如果有帮助,您可以假设我们可以扔掉积分,这样所有用户的最大积分为 2 * P。只要解决方案可以为每个用户处理灵活的点数,就可以在进行基准测试时忽略这部分。
【问题讨论】:
-
为什么您的分布在
1附近有一个峰值?由于0.5有两个点,直方图不应该在0.5加倍吗? -
什么意思?直方图是
0.5的两倍 - 它是0.08,而其他的在0.04附近。 -
1的质量是故意的。请参阅我的问题中的“我们需要将质量包裹在 0 和 1 周围,例如 0.95 处的点也将在 0 附近分配质量”:) -
我知道我们需要将质量包裹在 0 和 1 之间。但这并不能真正解释为什么您会在
1看到一个峰值。您的数据根本不集中在 1 左右。 -
其中一个数据点位于
0.05,这会在0和1周围创建密度。1处的密度等于0.1处的密度。
标签: python performance numpy scipy probability