简体   繁体   中英

Averaging results from a list of lists where every nth list is a reptition

So I wrote a model that computes results over various parameters via a nested loop. Each computation returns a list of len(columns) = 10 elements, which is added to a list of lists ( res ).

Say I compute my results for some parameters len(alpha) = 2 , len(gamma) = 2 , rep = 3 , where rep is the number of repetitions that I run. This yields results in the form of a list of lists like this:

res = [ [elem_1, ..., elem_10], ..., [elem_1, ..., elem_10] ]

I know that len(res) = len(alpha) * len(gamma) * repetitions = 12 and that each inner list has len(columns) = 10 elements. I also know that every 3rd list in res is going to be a repetition (which I know from the way I set up my nested loops to iterate over all parameter combinations, in fact I am using itertools).

I now want to average the result list of lists. What I need to do is to take every (len(res) // repetitions) = 4 th list, add them together element-wise, and divide by the number of repetitions (3). Sounded easier than done, for me.

Here is my ugly attempt to do so:

# create a list of lists of lists, where the inner list of lists are lists of the runs with the identical parameters alpha and gamma
res = [res[i::(len(res)//rep)] for i in range(len(res)//rep)]

avg_res = []
for i in res:
    result = []
    for j in (zip(*i)):
        result.append(sum(j))
    avg_res.append([i/repetitions for i in result])

print(len(result_list), avg_res)

This actually yields, what I want, but it surely is not the pythonic way to do it. Ugly as hell and 5 minutes later I can hardly make sense of my own code...

What would be the most pythonic way to do it? Thanks in advance!

In some cases a pythonic code is a matter of style, one of its idioms is using list comprehension instead of loop so writing result = [sum(j) for j in (zip(*i))] is simpler than iterating over zip(*i) .

On the other hand nested list comprehension looks more complex so don't do

avg_res = [[i/repetitions for i in [sum(j) for j in (zip(*j))]] for j in res]

You can write:

res = [res[i::(len(res)//rep)] for i in range(len(res)//rep)]

avg_res = []
for i in res:
    result = [sum(j) for j in (zip(*i))]
    avg_res.append([i/repetitions for i in result])

print(len(result_list), avg_res)

Another idiom in Programming in general (and in python in particular) is naming operations with functions, and variable names, to make the code more readable :

def sum_columns(list_of_rows):
  return [sum(col) for col in (zip(*list_of_rows))]
def align_alpha_and_gamma(res):
  return [res[i::(len(res)//rep)] for i in range(len(res)//rep)]

aligned_lists = align_alpha_and_gamma(res)

avg_res = []
for aligned_list in aligned_lists:
    sums_of_column= sum_columns(aligned_list)
    avg_res.append([sum_of_column/repetitions for sum_of_column in sums_of_column])

print(len(result_list), avg_res)

Off course you can choose better names according to what you want to do in the code.

It was a bit hard to follow your instructions, but as I caught, you attempt to try sum over all element in N'th list and divide it by repetitions.

res = [list(range(i,i+10)) for i in range(10)]
N = 4
repetitions = 3
average_of_Nth_lists = sum([num for iter,item in enumerate(res) for num in item if iter%N==0])/repetitions
print(average_of_Nth_lists)

output:

85.0

explanation for the result: equals to sum(0-9)+sum(4-13)+sum(8-17) = 255 --> 255/3=85.0

created res as a list of lists, iterate over N'th list (in my case, 1,5,9 you can transform it to 4,8 etc if that what you are wish, find out where in the code or ask for help if you don't get it), sum them up and divide by repetitions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM