我已经完成了距离的计算并存储在推力矢量中,例如,我有2个质心和5个数据点,并且计算距离的方式是,对于每个质心,我首先使用5个数据点计算了距离并存储在数组中,之后,另一个质心在1d数组中的距离,如下所示:

for (int i = 0; i < centroids.size(); ++i)
{
    computeDistance(Data, distances, centroids[i], nDataPoints, nDimensions);
}


产生向量1d,例如:

DistancesValues = {10, 15, 20, 12, 10, 5, 17, 22, 8, 7}

DatapointsIndex = {1, 2,  3,   4,  5,  1,  2,  3, 4, 5}


其中前5个值代表质心1,其他5个值代表质心2。

我想知道是否存在推力函数,可以在其中将计数存储在每个质心的最小值的另一个数组中?

比较每个索引的值,结果应为:

Counts = {2, 3}


哪里:

CountOfCentroid 1 = 2
CountOfCentroid 2 = 3

最佳答案

这是一种可能的方法:


创建一个附加的质心索引向量:

DistancesValues = {10, 15, 20, 12, 10, 5, 17, 22,  8, 7}
DatapointsIndex = {1,   2,  3,  4,  5, 1,  2,  3,  4, 5}
CentroidIndex   = {1,   1,  1,  1,  1, 2,  2,  2,  2, 2}

现在使用DatapointsIndex作为键进行sort_by_key,并将其他两个向量压缩为值。这具有重新排列所有3个向量的效果,以使DatapointsIndex具有类似的索引分组在一起:

DatapointsIndex = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5}


(另外2个向量会相应地重新排列)。
现在执行reduce_by_key。如果选择thrust::minimum运算符,则得到的归约结果将有效地选择组中的最小值(而不是对组中的值求和)。 reduce_by_key表示在每个连续的相似键组上进行这种类型的缩减。因此,我们将再次使用DatapointsIndex作为我们的关键向量,并将其他两个向量压缩在一起作为我们的值向量。我们不需要关心的大多数reduce_by_key输出,除了从CentroidIndex向量发出的结果向量。通过计算此结果向量中的质心索引,我们可以获得所需的输出。


这是一个完整的示例:

$ cat t428.cu
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>
#include <thrust/copy.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <stdio.h>
#define NUM_POINTS 5
#define NUM_CENTROID 2
#define DSIZE (NUM_POINTS*NUM_CENTROID)

int main(){

  int DistancesValues[DSIZE] = {10, 15, 20, 12, 10, 5, 17, 22, 8, 7};
  int DatapointsIndex[DSIZE] = {1, 2,  3,   4,  5,  1,  2,  3, 4, 5};
  int CentroidIndex[DSIZE]   = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2};

  thrust::device_vector<int> DV(DistancesValues, DistancesValues + DSIZE);
  thrust::device_vector<int> DI(DatapointsIndex, DatapointsIndex + DSIZE);
  thrust::device_vector<int> CI(CentroidIndex, CentroidIndex + DSIZE);
  thrust::device_vector<int> Ra(NUM_POINTS);
  thrust::device_vector<int> Rb(NUM_POINTS);

  thrust::sort_by_key(DI.begin(), DI.end(), thrust::make_zip_iterator(thrust::make_tuple(DV.begin(), CI.begin())));
  thrust::reduce_by_key(DI.begin(), DI.end(), thrust::make_zip_iterator(thrust::make_tuple(DV.begin(), CI.begin())), thrust::make_discard_iterator(), thrust::make_zip_iterator(thrust::make_tuple(Ra.begin(), Rb.begin())), thrust::equal_to<int>(), thrust::minimum<thrust::tuple<int, int> >());
  printf("CountOfCentroid 1 = %d\n", thrust::count(Rb.begin(), Rb.end(), 1));
  printf("CountOfCentroid 2 = %d\n", thrust::count(Rb.begin(), Rb.end(), 2));

  return 0;
}

$ nvcc -arch=sm_20 -o t428 t428.cu
$ ./t428
CountOfCentroid 1 = 2
CountOfCentroid 2 = 3
$


正如Eric在他的答案here中指出的(您的问题几乎是那个问题的重复),sort_by_key可能是不必要的。数据的重新排序遵循常规模式,因​​此我们无需利用排序的复杂性,因此可以通过巧妙地使用迭代器来对数据进行重新排序。在这种情况下,可能只需一次调用reduce_by_key即可执行整个操作(大约)。

关于c++ - 使用Thrust库获取最近的质心? (K-均值),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23970593/

10-12 20:48