Mathematica快速2D分级算法

Ben*_*mer 10 algorithm performance wolfram-mathematica bin binning

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

目前,我正在遍历表的每个元素,使用Select根据bin边界列表选择它应该位于哪个bin中,并将z值添加到占用该bin的值列表中.最后,我将Total映射到箱子列表,总结其内容(我这样做是因为我有时想做其他事情,比如最大化).

我已经尝试过使用Gather和其他类似的函数来做到这一点,但上面的方法速度非常快,不过可能我使用Gather很差.无论如何,通过我的方法进行排序还需要几分钟,我觉得Mathematica可以做得更好.有没有人有一个很好的高效算法方便吗?

小智 12

这是一个基于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
Run Code Online (Sandbox Code Playgroud)

给出{2.012217,Null}

AbsoluteTiming[
 System`SetSystemOptions[ 
  "SparseArrayOptions" -> {"TreatRepeatedEntries" -> 1}];
 res3 = SparseArray[indexes -> zvalues];
 System`SetSystemOptions[ 
  "SparseArrayOptions" -> {"TreatRepeatedEntries" -> 0}];
 ]
Run Code Online (Sandbox Code Playgroud)

给出{0.195228,Null}

res3 == res2
True
Run Code Online (Sandbox Code Playgroud)

"TreatRepeatedEntries" - > 1添加重复的位置.

  • 我现在才注意到这个回复.我希望这是SparseArray的一个选项而不是系统选项. (4认同)
  • 我确实曾多次在MathGroup上展示过这一点:http://forums.wolfram.com/mathgroup/archive/2010/Dec/msg00335.html. (3认同)
  • 你可以扩大一点"添加重复的位置"吗?我无法理解它的作用. (2认同)
  • 如果你有规则{2,3} - > 1,{2,3} - > 10,比方说,{2,3} - > 2,mat [[2,3]]的值将是1 + 10 + 2; "TreatRepeatedEntries"表示如果重复位置条目,则将值相加.SparseArray的默认行为是不这样做.TreatRepeatedEntries" - > 1激活该功能 - 使用此功能可以编写非常高效的代码. (2认同)

Mr.*_*ard 5

由于Szabolcs的可读性问题,我打算重写下面的代码.在此之前,要知道如果您的垃圾箱是常规的,并且您可以使用Round,FloorCeiling(使用第二个参数)代替Nearest,下面的代码将会更快.在我的系统上,它的测试速度比GatherBy发布的解决方案更快.


假设我理解你的要求,我建议:

data = RandomReal[100, {75, 3}];

bins = {0, 20, 40, 60, 80, 100};

Reap[
  Sow[{#3, #2}, bins ~Nearest~ #] & @@@ data,
  bins,
  Reap[Sow[#, bins ~Nearest~ #2] & @@@ #2, bins, Tr@#2 &][[2]] &
][[2]] ~Flatten~ 1 ~Total~ {3} // MatrixForm
Run Code Online (Sandbox Code Playgroud)

重构:

f[bins_] := Reap[Sow[{##2}, bins ~Nearest~ #]& @@@ #, bins, #2][[2]] &

bin2D[data_, X_, Y_] := f[X][data, f[Y][#2, #2~Total~2 &] &] ~Flatten~ 1 ~Total~ {3}
Run Code Online (Sandbox Code Playgroud)

使用:

bin2D[data, xbins, ybins]
Run Code Online (Sandbox Code Playgroud)

  • 我的第一个评论只是一个沮丧的哭泣,而不是直接针对你:-)但严重的是,我认为这是客观上难以阅读(尽管"易读"是一个主观和文化的东西,取决于我们使用的是什么至).例如,行"Reap [Sow [#1,bins~Near~~#2]&@@@#2,bins,Tr @#2&]`.有三次出现`#2`,每个都是不同函数的参数.使用"Tr"作为"Total"的简写是误导性的.非正统使用内联表示法. (2认同)
  • 我想建议一个改变.使用`Nearest`很好,但每次使用它都必须进行大量的预处理.我建议用`With [{nn = Nearest [bins]},...]`包装`f`中的所有内容,并使用`nn [#]`而不是`bins~Nearest~#`.这需要一次所需的所有预处理,并且在我的机器上超过10 ^ 6点,它将削减近7秒. (2认同)