Re: Efficient function to accumulate a list of
- To: mathgroup at smc.vnet.net
 - Subject: [mg132514] Re: Efficient function to accumulate a list of
 - From: Bob Hanlon <hanlonr357 at gmail.com>
 - Date: Fri, 4 Apr 2014 03:57:58 -0400 (EDT)
 - Delivered-to: l-mathgroup@mail-archive0.wolfram.com
 - Delivered-to: l-mathgroup@wolfram.com
 - Delivered-to: mathgroup-outx@smc.vnet.net
 - Delivered-to: mathgroup-newsendx@smc.vnet.net
 - References: <20140403061721.737146A1A@smc.vnet.net>
 
Your function does not work as described. For comparison with other
approaches, I have simplified it and modified it to do what you described.
Clear[particleToDensity, particleToDensity2, particleToDensity3]
Use Module to localize the transient variable names, delete the unnecessary
Round and If, and use lower case letter to start a user-defined function
(avoid potential future name conflict with built-in functions):
particleToDensity[particles_,
  arrayDimensions_: {144, 300}] :=
 Module[{arr, l, tp},
  arr = ConstantArray[0, arrayDimensions];
  For[l = 1, l <= Length[particles], l++,
   tp = particles[[l]];
   arr[[tp[[2]], tp[[3]]]] += tp[[1]]];
  arr]
Use Map rather than For loop:
particleToDensity2[particles_,
  arrayDimensions_: {144, 300}] :=
 Module[{arr},
  arr = ConstantArray[0, arrayDimensions];
  (arr[[#[[2]], #[[3]]]] += #[[1]]) & /@
   particles;
  arr]
Use SparseArray
particleToDensity3[particles_,
  arrayDimensions_: {144, 300}] :=
 SparseArray[{#[[1, 2]], #[[1, 3]]} -> Total[#[[All, 1]]] & /@
   GatherBy[particles, #[[{2, 3}]] &], arrayDimensions]
data = {{3.6, 7, 4}, {3.4, 8, 6}, {2.1, 7, 4}};
t1 = Timing[arr1 = particleToDensity[data];];
t2 = Timing[arr2 = particleToDensity2[data];];
t3 = Timing[arr3 = particleToDensity3[data];];
Verifying that the arrays are equivalent
arr1 == arr2 == arr3
True
Map is marginally quicker and the sparse array approach is much quicker
{t1[[1]]/t2[[1]], t1[[1]]/t3[[1]]}
{1.03, 2.7}
However, if the array is relatively dense
data = Table[{
    RandomReal[{0, 5}],
    RandomInteger[{1, 144}],
    RandomInteger[{1, 300}]},
   {10000}];
t1 = Timing[arr1 = particleToDensity[data];];
t2 = Timing[arr2 = particleToDensity2[data];];
t3 = Timing[arr3 = particleToDensity3[data];];
Verifying that the arrays are equivalent
arr1 == arr2 == arr3
True
Map is now noticeably quicker but the SparseArray became noticeably slower
than your approach.
{t1[[1]]/t2[[1]], t1[[1]]/t3[[1]]}
{1.3822, 0.7310}
Bob Hanlon
On Thu, Apr 3, 2014 at 2:17 AM, <julian.w.francis at gmail.com> wrote:
> Dear all,
>
> I am struggling with how to convert a list of (value, coords) tuples into
> an array such that the an element in the array should represent the sum of
> all value elements in that list with matching coords, and zero if no
> matches, e.g.
>
> { {3.6, 7,4}, {3,4, 8,6}, {2.1, 7,4} }
>
> if it were a 10X10 element array would become all zero's, except element
> (7,4)->(3.6+2.1) and (8,6)->3.4
>
> I've got some code which does what I want:
>
> ParticleToDensity[particles_] := (
>   arr = ConstantArray[0, {144, 300}];
>   For[l = 1, l < NoParticles, l++,
>    (tp = particles[[l]];
>     If[tp[[2]] != 0,
>      arr[[Round[tp[[3]]], Round[tp[[2]]]]] += tp[[1]]]
>     )];
>   arr)
>
> So, the argument to the function is a list of "particles", and the first
> element of this particle is the value in the array I'd like to accumulate,
> and the next two elements in that particle say where in the array they
> should be accumulated.
>
> It seems to work, but it is slow. I can see that this isn't really the
> Mathematica way of doing things, but I'm struggling to think of a better
> way.
>
> For reference, NoParticles is typically set to something like 10,000, and
> it takes about 0.1 secs to process on my machine. However this needs to be
> done frequently, hence I am hoping for a better way.
>
>
>
> Any help greatly appreciated.
>
> Thanks,
> Julian.
>
>
- References:
- Efficient function to accumulate a list of {value,coord} into array
- From: julian.w.francis@gmail.com
 
 
 - Efficient function to accumulate a list of {value,coord} into array