有趣的问题。这里有一个建议,根据您在数学方面的倾向程度,可能很难实现。
请注意,我为了速度而交换了空间,因为我建议的东西很可能在计算上非常繁重(但需要根据实际数据进行测试)。
首先,使用一种功能方法。概率分布是一个概率测度:
struct Distribution
{
virtual ~Distribution() {};
virtual double integrate(std::function<double(double)>) = 0;
};
这样,你可以抽象出你生成的样本,因为你不想储存它们。相信自己可以用“整合”方法做任何事情。
当然,对于明确的样本,你可以做如下操作:
struct SampledDistribution
{
double integrate(std::function<double(double)> f)
{
double acc = 0;
for (double x: samples) acc += f(samples);
return acc / samples.size();
}
std::deque<double> samples;
};
现在,存储部分:
传统的表示方法——直方图数组——不太理想,主要是因为量化/分辨率和空间之间的权衡。我想必定有一种表示方法,可以根据本地“复杂性”自适应地改变箱子大小。
传统的方法是
小波。您可以通过调用
integrate
来生成系数,并将其序列化。如果积分估计器产生的方差很高,则可以丢弃系数。
然后,要进行反序列化,您需要生成一个
Distribution
对象,其
integrate
方法针对小波执行积分。可以使用您喜欢的数值积分方法进行积分。我在这里故意保持模糊,因为实际实现取决于您选择的小波族(平滑、紧支撑、正交或非正交等)。无论如何,您都需要深入研究文献以获取详细信息。
这里的重点是,通常只需要很少的小波来表示具有少量特征(比如几个峰值和其他规则形状)的平滑函数,不像更“常规”的有限元素(直方图是一种有限元素表示)。小波表示自适应于变换对象的特征,无论它们的位置或大小如何。此外,您可以决定保留多少系数,从而控制压缩比率。
另外,0.001的数字相当高:我怀疑您只需要少量系数。
权衡在于使用哪种小波类别:非常平滑的分布可能会用平滑小波很好地表示,但紧支持小波可能更容易集成等。实验。注意,您不需要“小波变换”包:只需要小波函数的显式表示和积分程序(尝试Gauss-XXX过程进行重建,或者使用某些高阶方法)。
我倾向于使用在傅里叶域中定义的小波(例如Lemarie小波),因为它们在傅里叶空间中的值和导数为零是已知的,这使您可以强制执行对分布的约束:概率测度必须集成为1,并且您可能事先知道期望值或方差。
此外,您可能希望将变量更改为仅处理函数,例如在[0,1]上。有大量关于区间小波的文献。