Weighted averaging a list

Question:

Thanks for your responses. Yes, I was looking for the weighted average.

rate = [14.424, 14.421, 14.417, 14.413, 14.41]

amount = [3058.0, 8826.0, 56705.0, 30657.0, 12984.0]

I want the weighted average of the top list based on each item of the bottom list.

So, if the first bottom-list item is small (such as 3,058 compared to the total 112,230), then the first top-list item should have less of an effect on the top-list average.

Here is some of what I have tried. It gives me an answer that looks right, but I am not sure if it follows what I am looking for.

for g in range(len(rate)):
    rate[g] = rate[g] * (amount[g] / sum(amount))
rate = sum(rate)

EDIT:
After comparing other responses with my code, I decided to use the zip code to keep it as short as possible.

Asked By: GShocked

||

Answers:

This looks like a weighted average.

values = [1, 2, 3, 4, 5]
weights = [2, 8, 50, 30, 10]

s = 0
for x, y in zip(values, weights):
    s += x * y

average = s / sum(weights)
print(average) # 3.38

This outputs 3.38, which indeed tends more toward the values with the highest weights.

Answered By: maahl
for g in range(len(rate)):
   rate[g] = rate[g] * amount[g] / sum(amount)
rate = sum(rate)

is the same as:

sum(rate[g] * amount[g] / sum(amount) for g in range(len(rate)))

which is the same as:

sum(rate[g] * amount[g] for g in range(len(rate))) / sum(amount)

which is the same as:

sum(x * y for x, y in zip(rate, amount)) / sum(amount)

Result:

14.415602815646439
Answered By: JuniorCompressor

Let’s use python zip function

zip([iterable, ...])

This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The returned list is truncated in length to the length of the shortest argument sequence. When there are multiple arguments which are all of the same length, zip() is similar to map() with an initial argument of None. With a single sequence argument, it returns a list of 1-tuples. With no arguments, it returns an empty list.

weights = [14.424, 14.421, 14.417, 14.413, 14.41]
values = [3058.0, 8826.0, 56705.0, 30657.0, 12984.0]
weighted_average = sum(weight * value for weight, value in zip(weights, values)) / sum(weights)
Answered By: Ɓukasz Rogalski

You could use numpy.average to calculate weighted average.

In [13]: import numpy as np

In [14]: rate = [14.424, 14.421, 14.417, 14.413, 14.41]

In [15]: amount = [3058.0, 8826.0, 56705.0, 30657.0, 12984.0]

In [17]: weighted_avg = np.average(rate, weights=amount)

In [19]: weighted_avg
Out[19]: 14.415602815646439
Answered By: Akavall

As a documented and tested function:

def weighted_average(values, weights=None):
    """
    Returns the weighted average of `values` with weights `weights`
    Returns the simple aritmhmetic average if `weights` is None.
    >>> weighted_average([3, 9], [1, 2])
    7.0
    >>> 7 == (3*1 + 9*2) / (1 + 2)
    True
    """
    if weights == None:
        weights = [1 for _ in range(len(values))]
    normalization = 0
    val = 0
    for value, weight in zip(values, weights):
        val += value * weight
        normalization += weight
    return val / normalization

For completeness another version where the values and weights are stored in tuples:

def weighted_average(values_and_weights):
    """
    The input is expected in the form:
        [(value_1, weight_1), (value_2, weight_2), ...(value_n, weight_n)]
    >>> weighted_average([(3,1), (9,2)])
    7.0
    >>> 7 == (3*1 + 9*2) / (1 + 2)
    True

    """
    normalization = 0
    val = 0
    for value, weight in values_and_weights:
        val += value * weight
        normalization += weight
    return val / normalization
Answered By: Caridorc
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.