C++ 寻求概率分布数据表示的建议

C++ 寻求概率分布数据表示的建议,c++,data-structures,probability,C++,Data Structures,Probability,我正在寻找一种优雅而有效的方法来表示和存储由显式采样构造的任意概率分布 分发版应具有以下属性: 样本是浮点值,但原则上可以认为分辨率低至.001 从间隔[-4000;4000] 但是,对于任何两个样本a,b,|a-b |

我正在寻找一种优雅而有效的方法来表示和存储由显式采样构造的任意概率分布

分发版应具有以下属性:

  • 样本是浮点值,但原则上可以认为分辨率低至.001
  • 从间隔
    [-4000;4000]
  • 但是,对于任何两个样本
    a
    b
    |a-b |<40
  • 90%的时候,它会有一个尖峰或几个尖峰彼此靠近
  • 在10%的时间内,它将有一个宽度为0.5到5的不均匀平台的峰值
通常的表示法——直方图数组——是不可取的,主要是因为量化/分辨率和空间之间的权衡。我想一定有一种表示方法,根据局部“复杂性”自适应地改变箱子大小

空间令人担忧,因为更高级别的网格状数据结构将包含数千个单元,每个单元至少包含一个这样的概率表示。方便的磁盘或网络传输序列化是可取的,但效率不是优先考虑的

任何帮助都将不胜感激。

这个怎么样:

我假设我们从相当于直方图的数据开始,即一个区间列表,其中包含与之相关的样本数

现在,让我们从一个包含所有样本的小直方图开始,构建一个近似值

对于近似中的所有桶,考虑将它在中间分割为两个桶,但实际上只拆分桶将获得近似的最佳改进。

重复此操作,直到达到所需的近似值或获得可接受的最大桶数

因此,您需要的是一种确定最佳分割桶的方法。我想说,与原来的一半相比,新桶的最大偏差可能是可行的

你还需要一些标准来确定何时停止

我认为这实际上非常类似于一维八叉树。您可以在那里寻找高效的实现


为了实际存储近似值,只需存储一个包含桶边界的数组,另一个包含每个桶的内容。或者一个大小为两倍的数组,具有交替的bucketboundary和content value。

我强烈建议查看。他们在这个问题上做得最多,而我提出的任何试图解决分辨率粒度问题的spec算法都至少是他们切身考虑过的

不过,正如前面提到的,用于乘法解析数据的八叉树似乎是您所希望的数据结构的正确表示形式。与包含死记硬背的数据的扁平柱状图不同,您的目标是以固定粒度的不同级别在数据集中存储扰动。这与用于的算法最为相似,另外还需要从分布中以某种粒度和复杂度提取样本

为了创建分类算法或二分法来填充数据结构,我强烈建议查看分解算法,如用于确定数据中扰动的形状和复杂性。其他方法(例如,和)也可能是合适的,但我觉得简单的矢量化分解可能适合您的目的


而且,不管它值多少钱,如果你在空间中找到一个更适用的算法,我会非常感兴趣。我直接与对数据中的多尺度关系感兴趣的研究人员合作,因此如果您偶然发现了更有效的方法,请告诉我们

有趣的问题。这里有一个建议,根据你在数学上的倾向程度,它可能很难实现

请注意,我以空间换取速度,因为我的建议在计算上可能相当繁重(但这需要根据实际数据进行测试)

首先,使用功能性方法。概率分布是一种概率度量:

struct Distribution
{
    virtual ~Distribution() {};
    virtual double integrate(std::function<double(double)>) = 0;
};
struct分布
{
虚拟~Distribution(){};
虚拟双积分(std::function)=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;
};
struct SampledDistribution
{
双积分(标准::函数f)
{
双acc=0;
对于(双x:样本)acc+=f(样本);
返回acc/samples.size();
}
std::deque样品;
};
现在,存储部分:

通常的表示法——直方图数组——主要是不可取的 由于量化/分辨率和空间之间的权衡。我 想象一下,一定有一种自适应的表示方法 根据本地“复杂度”改变箱子大小

传统的方法是。您可以通过调用
integrate
来生成系数,您可以序列化这些系数。如果系数产生的积分估计量的方差很高,则将系数丢弃

然后,为了反序列化,您生成一个
分布
对象,该对象的
集成
方法对小波执行集成。积分可以用你最喜欢的求积法进行。我在这里故意含糊其辞,因为实际实现取决于您选择的小波族(平滑、紧支撑、正交与否,等等)。无论如何,你都需要深入了解细节

这里的要点是,你通常只需要很少的小波来表示一个光滑的函数,它具有很少的特征(比如说一些峰值,或者有规律的形状),这与更“规则”的有限元不同