I have 2 list of lists as follows:
A = [[],[],[],[500,540],[510,560,550],[460,510,600,450]]
B = [[],[],[],[4000,2500],[3500,3600,3000],[3000,2900,3300,3500]]
I would like to calculate the weighted average of values in every list of A using lists of B as corresponding weights. My output C should like like:
C = [[],[],[],[515],[540],[505]]
What I tried so far is using
C = []
for i in range(len(A)):
avg = np.average(A[i], weights=B[i])
C.append(avg)
Many thanks for your help.
CodePudding user response:
The code you have done works so far, except that it does not work for lists in A that have 0 len. So you can account for it through the following modification:
import numpy as np
A = [[],[],[],[500,540],[510,560,550],[460,510,600,450]]
B = [[],[],[],[4000,2500],[3500,3600,3000],[3000,2900,3300,3500]]
C = []
for i in range(len(A)):
if len(A[i]) > 0:
avg = np.average(A[i], weights=B[i])
C.append(avg)
else:
C.append([])
Output:
C
Out[10]: [[], [], [], 515.3846153846154, 539.7029702970297, 505.03937007874015]
CodePudding user response:
The only issue is that weights
can't be the empty list:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<__array_function__ internals>", line 180, in average
File "site-packages/numpy/lib/function_base.py", line 524, in average
raise ZeroDivisionError(
ZeroDivisionError: Weights sum to zero, can't be normalized
However, B[:3] == [[], [], []]
, so you have three empty weights.
You can handle these empty lists accordingly:
C = []
for i in range(len(A)):
avg = np.average(A[i], weights=B[i]) if B[i] else 0
C.append(avg)
Output:
C == [0, 0, 0, 515.3846153846154, 539.7029702970297, 505.03937007874015]
CodePudding user response:
This is my best solution:
import numpy as np
A = [[], [], [], [500, 540], [510, 560, 550], [460, 510, 600, 450]]
B = [[], [], [], [4000, 2500], [3500, 3600, 3000], [3000, 2900, 3300, 3500]]
C = list()
for list_values, list_weights in zip(A, B):
if len(list_values) == 0 or len(list_weights) == 0:
C.append([])
else:
weighted_average = np.average(list_values, weights=list_weights)
C.append(weighted_average)
CodePudding user response:
As others have pointed out, you need to deal with the empty lists. But no-one has given you the output you asked for. The other solutions also use counters (probably to mirror your own code), but this is not usually considered idiomatic Python.
I would probably do this in a list comprehension, and instead of indexing into both lists I'd take advantage of zip()
.
You said you wanted rounded integers in in 1-item lists, like:
C = [[int(np.round(np.average(a, weights=b), 0))] if a else [] for a, b in zip(A, B)]
This returns what you specified in your question:
[[], [], [], [515], [540], [505]]
But if it was me, I think I'd want the results as floats like:
C = [np.average(a, weights=b) if a else np.nan for a, b in zip(A, B)]
This results in:
[nan, nan, nan, 515.3846153846154, 539.7029702970297, 505.03937007874015]
which personally I would prefer.