Weighted averaging a list

Each Answer to this Q is separated by one/two green lines.

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.

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

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

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.

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)

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


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .