Mathematica快速2D分箱算法


问题内容

在Mathematica中开发适当的快速装箱算法时遇到了一些麻烦。我有一个大的(〜100k个元素)数据集,形式为T =
{{x1,y1,z1},{x2,y2,z2},....},我想将其分类为2D数组100x100个bin,bin值由落入每个bin的Z值之和得出。

目前,我正在遍历表中的每个元素,使用“选择”基于bin边界列表挑选出它应该在哪个bin中,然后将z值添加到占用该bin的值列表中。最后,我将Total映射到垃圾箱列表,对垃圾箱的内容求和(之所以这样做,是因为有时我想做其他事情,例如最大化)。

我曾尝试使用Gather和其他此类函数来执行此操作,但是上述方法可笑得更快,尽管也许我使用Gather的效率很差。无论如何,按照我的方法进行排序仍然需要几分钟,我觉得Mathematica可以做得更好。有没有人有一个很好的高效算法方便吗?


问题答案:

这是一种基于Szabolcs帖子的方法,速度大约快一个数量级。

data = RandomReal[5, {500000, 3}];
(*500k values*)
zvalues = data[[All, 3]];

epsilon = 1*^-10;(*prevent 101 index*)
(*rescale and round (x,y) coordinates to index pairs in the 1..100 range*)
indexes = 1 + Floor[(1 - epsilon) 100 Rescale[data[[All, {1, 2}]]]];

res2 = Module[{gb = GatherBy[Transpose[{indexes, zvalues}], First]}, 
    SparseArray[
     gb[[All, 1, 1]] -> 
      Total[gb[[All, All, 2]], {2}]]]; // AbsoluteTiming

给出{2.012217,Null}

AbsoluteTiming[
 System`SetSystemOptions[ 
  "SparseArrayOptions" -> {"TreatRepeatedEntries" -> 1}];
 res3 = SparseArray[indexes -> zvalues];
 System`SetSystemOptions[ 
  "SparseArrayOptions" -> {"TreatRepeatedEntries" -> 0}];
 ]

给出{0.195228,空}

res3 == res2
True

“ TreatRepeatedEntries”-> 1将重复的位置加起来。