2
$\begingroup$

Say one has a list of pairs

list = {{0,1},{1,2},{1,4},{5,6},{3,2},{3,5},{0,9}}

and one wants to sum the second element of the pairs for which the first element is equal, i.e, obtain:

{{0,10},{1,6},{3,7},{5,6}}

Then, there are many posts that provide wonderful answers, such as:

-https://mathematica.stackexchange.com/questions/4332/combining-values-in-one-column-or-part-when-values-in-another-column-or-part

-https://mathematica.stackexchange.com/questions/146882/list-of-tuples-group-by-first-element-of-tuple-sum-up-the-second-element-per-g

My question differs only slightly, namely, I have a list of pairs, ordered by first element

list = {{0.2,1},{0.2,9},{1.1,2},{1.2,4},{3.2,2},{3.5,5},{5.6,6}}

and I want to create n bins based on the first element, the value of a bin being the total mass (second elements) of the items in the bin. For example, if I would want to create n = 2 bins in the interval [0, 6), I would get bins with ranges [0, 3) and [3, 6), and their total masses are, respectively, 16 and 13. Identifying a bin with its left limit, the desired output would thus be

{{0,16},{3,13}}

Based on the code of the first described problem, I wrote the following procedure (which for now uses the range as given in the code, but should work with any range whose right limit is strictly larger than the biggest first element of the list):

tempList = Transpose@list;
range = {Min[tempList] - 1, Max[tempList] + 1};
rounding = (tempList[[1]][[-1]] - tempList[[1]][[1]])/n; 
convolution[[1]] = 
  tempList[[1]][[1]] + (Round[#, rounding] & /@ (tempList[[1]] - 
       tempList[[1]][[1]]));
output = 
  Transpose[
   Map[{#[[1, 1]], Total[#[[;; , 2]]]} &, 
    GatherBy[Transpose[tempList], First[#] &]]];

Note: The last line stems from the links above.

However, I was wondering if more efficient methods are possible, that (perhaps) explicitely use the different nature of our program by, e.g., some splitting procedures. The lists I work with are typically around size 100 000, and n would have size 10 000.

$\endgroup$

1 Answer 1

4
$\begingroup$

Maybe use WeightedData and Histogram?

list = {{0.2, 1}, {0.2, 9}, {1.1, 2}, {1.2, 4}, {3.2, 2}, {3.5, 5}, {5.6, 6}};
weightedList = WeightedData @@ Transpose[list];

Histogram[weightedList, {{0, 3, 6}}]
(* graphical display of histogram *)

HistogramList[weightedList, {{0, 3, 6}}]
(* {{0, 3, 6}, {16., 13.}} *)

That last one can be massaged to what you want:

Most[Flatten[HistogramList[weightedList, {{0, 3, 6}}], {2}]]
(* {{0, 16.}, {3, 13.}} *)
$\endgroup$
1
  • $\begingroup$ Thank you for contributing! I was unaware of the existence of the function HistogramList, which is very nice. Unfortunately, combining WeightedData and HistogramList does not seem to speed up the list manipulation. $\endgroup$ Commented Dec 22, 2023 at 10:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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