1
$\begingroup$

I am trying to sort elements in multiple lists into buckets with weighted data. I can do the single-list case based on a previous question. Specifically, the code under Update in the first answer.

data = {1, 2, 3, 4, 5, 6, 7, 10};
bins = {0, 2, 4, 6, 8, 10};
weights = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.0};

With[{ranges = Partition[bins, 2, 1]}, 
 Total@Pick[weights, 
     BitXor[UnitStep[Subtract[data, #1]], 
      UnitStep[Subtract[data, #2]]], 1] & @@@ ranges]

which gives the following output: {0.1, 0.5, 0.9, 1.3, 0}

Now, I'm trying to generalise to the following input:

data = {{1, 2, 3, 4, 5, 6, 7, 10}, {3, 5, 6}};
bins = {0, 2, 4, 6, 8, 10};
weights = {{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.0}, {0.4, 0.6, 0.5}};

I can't use the same code, because Pick does not treat each list sequentially. However, I can get the desired result using this code (where I make it take the first and second list separately:

With[{ranges = Partition[bins, 2, 1]}, 
 Total@Pick[weights[[1]], 
     BitXor[UnitStep[Subtract[data, #1]], 
       UnitStep[Subtract[data, #2]]][[1]], 1] & @@@ ranges]

With[{ranges = Partition[bins, 2, 1]}, 
 Total@Pick[weights[[2]], 
     BitXor[UnitStep[Subtract[data, #1]], 
       UnitStep[Subtract[data, #2]]][[2]], 1] & @@@ ranges]

{0.1, 0.5, 0.9, 1.3, 0} {0, 0.4, 0.6, 0.5, 0}

But I want to generalise to a large number of lists now. I tried a loop but when i generalise to a loop it does not work:

For[i = 1, 2, i++,
 With[{ranges = Partition[bins, 2, 1]}, 
  Total@Pick[weights[[i]], 
      BitXor[UnitStep[Subtract[data, #1]], 
        UnitStep[Subtract[data, #2]]][[i]], 1] & @@@ ranges]
 ]

How can I generalise it cleanly?

$\endgroup$
  • 1
    $\begingroup$ Don't use For. The output of For is Null, so you can only generate output with side effects (e.g. Print, or assigning output to a variable). $\endgroup$ – Carl Woll Jun 12 at 3:29
1
$\begingroup$

Given wBinCountsLeft from the linked answer, repeated below:

wBinCountsLeft[data_, weights_, bins_] := With[{ranges=Partition[bins,2,1]},
    Total @ Pick[
        weights,
        BitXor[UnitStep[Subtract[data, #1]], UnitStep[Subtract[data, #2]]],
        1
    ]& @@@ ranges
]

you can just use MapThread:

MapThread[
    wBinCountsLeft[##, bins]&,
    {data, weights}
]

{{0.1, 0.5, 0.9, 1.3, 0}, {0, 0.4, 0.6, 0.5, 0}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.