I have a function that is supposed to do the following: take in a list of lists, and a list of numerical weights. Then, take the weighted average of every bottom-level item in the list of lists, with the first item in the list of weights being used to weight the first list of things, the second item in the list of weights being used to weight the second list, etc. It’s like a function that simply takes the weighted average of items in a list, but the items are grouped so that a particular weight gets applied to each group. This is useful if a lot of things have the same weight. Here is the code:
def getAverage(x,wts=[0.1,0.3,0.6]):
"""Get weighted average of partitioned list."""
xsum = 0
i = 0
for item in x:
xsum += reduce(lambda x,y:x+y,item)*wts[i]
i += 1
return xsum/reduce(lambda x,y:x+y,wts)
However, when I try to compile, I get the following error for that line:
TypeError: unsupported operand type(s) for +=: 'int' and 'list'
What? Why? Why does that multiplication return a list? That makes no sense. reduce() returns a number (integer to be precise), and the elements of wts are floats. How is it not allowed to be added to xsum? Did I misuse lambda or something?
Your function is mainly sound (although I presume it’s either named wrong or you want to divide by the number of items at the end too – otherwise it’s not an average), so you must be passing in incorrect arguments. The most likely is that your second argument is in fact a list of lists, not a list of integers.
This said, we can improve on the function. There are a few issues here. Firstly, you are using
reduce()to sum items, when thesum()built-in can do this job more effectively.Next, the loop counts using
i– this is a bad practice, instead, we should use theenumerate()built-in. However, here we are using it to loop over two lists at the same time, and in Python, that is best done using thezipbuilt-in.As the result is being accumulated, we can turn the whole thing into a generator expression and sum that too. This means we can end up with a simple way of doing this:
I also left out the default value for weights – unless the default is domain-specific, I would suggest there is no good default here, as it depends on the length of
items. The only potential for a good default might be to presume equal weighting. E.g: