【问题标题】:Conditional Averaging of a vector based on similarities in another vector c++基于另一个向量c ++中的相似性的向量的条件平均
【发布时间】:2014-08-16 15:39:17
【问题描述】:

最好举个例子。

假设向量 A 包含:

A = {3  ,2 ,1 ,4  ,6 ,3 ,8 ,4}

向量 B 包括:

B = {1.5,2 ,2 ,1.5,3 ,3 ,3 ,2}

向量B中的唯一值是{1.5, 2, 3}

我希望得到的向量 RESULT 是:

RESULT[0] = Average(A given B=1.5) = Average(3,4)

RESULT[1] = Average(A given B=2 )  = Average(2,1,4)

RESULT[2] = Average(A given B=3 )  = Average(6,3,8)

计算这个最有效的方法是什么。我自己的方法是遍历 B 的唯一元素,并且对于它们中的每一个,遍历每个 B 值以尝试匹配该唯一数字,并在每次匹配中不断总结向量 A 的相应元素,同时计算匹配的数量,所以我可以找到平均值。

这太慢了。因为我的向量 A 是 8M 个元素,而向量 B 由 0.5M 个唯一值组成。

任何帮助将不胜感激。

【问题讨论】:

  • 同步对两个向量进行排序,然后迭代B的相等范围?
  • 这看起来很有希望,我现在试试看能提高多少速度。
  • 不过,依赖浮点值的精确相等是一种味道。
  • 具有浮点数的唯一值听起来很奇怪。请注意,例如.1+.2!=.3doubles。

标签: c++ vector conditional average


【解决方案1】:

您可以使用(哈希)表进行循环:查看 Live On Coliru

int main()
{
    vector<int>    A = {3  ,2 ,1 ,4  ,6 ,3 ,8 ,4};
    vector<double> B = {1.5,2 ,2 ,1.5,3 ,3 ,3 ,2};

    assert(A.size() == B.size());

    struct accum { 
        uintmax_t sum = 0; 
        size_t number_of_samples = 0; 
        void sample(int val) { sum += val; ++number_of_samples; }
    };
    map<double, accum> average_state;

    for(size_t i = 0; i<B.size(); ++i)
        average_state[B[i]].sample(A[i]);

    for(auto& entry : average_state)
    {
        accum& state = entry.second;
        double average = static_cast<double>(state.sum) / state.number_of_samples;
        std::cout << "Bucket " << entry.first << "\taverage of " << state.number_of_samples << " samples:\t" << average << "\n";
    }
}

打印

Bucket 1.5  average of 2 samples:   3.5
Bucket 2    average of 3 samples:   2.33333
Bucket 3    average of 3 samples:   5.66667

【讨论】:

  • 为什么平均称为有效?
  • 因为它是经过计算的。当然,您可以将其命名为“平均”。我对问题域一无所知,所以我编造了一些东西。 更新
【解决方案2】:

这是一个懒惰的想法:同步遍历两个向量并将结果聚合到一个单独的容器中。例如:

#include <cassert>
#include <cmath>
#include <iostream>
#include <map>
#include <utility>

std::map<double, std::pair<int, std::size_t>> m;

assert(A.size() == B.size());

for (std::size_t i = 0; i != A.size(); ++i)
{
    assert(!std::isnan(B[i]));

    auto & p = m[B[i]];
    p.first += A[i];
    p.second += 1;
}

最后你只报告结果:

for (const auto & p : m)
    std::cout << "Average for bin " << p.first << " is "
              << static_cast<double>(p.second.first) / p.second.second
              << "\n";

(请注意,您的键值不能是 NaN:在有序映射中,NaN 不是严格排序的一部分;在无序映射中,它不与自身比较。)

【讨论】:

  • 为什么使用map 而不是unordered_map
  • @DDrmmr:报告的有序遍历?
  • 很高兴断言!isnan :) 我记得 SO 问题 (+1)
  • 谢谢,这个方法看起来不错。我也会试试这个。我不知道“auto & p = m[B[i]];”会自动处理地图。好的!不,我的数据没有任何 NaN。
  • @sehe:我很惊讶你能在没有提及 Boost Phoenix、Qi、Karma 或 MPL 序列的情况下回答这个问题。甚至没有任何融合......
猜你喜欢
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 2016-09-19
  • 2018-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多