Ahmad
Ahmad

Reputation: 413

How to aggregate the elements in a nested list

I have a list of lists as follows:

original_list = [['B_S', 'O', 'O', 'O'],
                 ['B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'B_S', 'O'],

                 ['O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O'],

                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]

I want to aggregate each three list to be one list based on the majority of elements. That is, if two positions have the same element, the new list will take the same element in the same position. The desired output should be like:

desired_output = [['B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]

I have tried with this complex function:

def collect_labels(lab_user):

  def aggregate_labels(a,b,c):
     aggregated_list = []
     # iterate over 3 lists
     for x,y,z in zip(a, b, c):
        if x != 'O':
          aggregated_list.append(x)
        elif y != 'O':
          aggregated_list.append(y)
        #elif z != 'O':
          #aggregated_list.append(z)  # you can improve the code
        else:
          aggregated_list.append(z)
     return aggregated_list

  result = [aggregate_labels(lab_user[i], lab_user[i+1], lab_user[i+2]) for i in range(0,len(lab_user)-2, 3)] 
  return result

But it return the wrong result:

wrong_result= [['B_S', 'O', 'O', 'O'],
               ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O'],
               ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O']]

I will be very grateful if you could help me to correct my code!

Upvotes: 1

Views: 209

Answers (2)

Samwise
Samwise

Reputation: 71464

The hardest part of the problem is just grouping your lists into the three chunks:

>>> [original_list[i*3:i*3+3] for i in range(len(original_list)//3)]
[[['B_S', 'O', 'O', 'O'], ['B_S', 'O', 'O', 'O'], ['O', 'O', 'B_S', 'O']], 
[['O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O']], 
[['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]]

Once you have that, though, you can use zip to group the items you want to compare:

>>> chunks = [original_list[i*3:i*3+3] for i in range(len(original_list)//3)]
>>> [list(zip(*j)) for j in chunks]
[[('B_S', 'B_S', 'O'), ('O', 'O', 'O'), ('O', 'O', 'B_S'), ('O', 'O', 'O')],
[('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('B_S', 'O', 'O'), ('O', 'B_S', 'O'), ('O', 'O', 'B_S'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O')], 
[('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('B_S', 'B_S', 'B_S'), ('O', 'O', 'O'), ('O', 'O', 'O'), ('B_S', 'B_S', 'B_S'), ('B_S', 'O', 'O'), ('O', 'O', 'O'), ('O', 'O', 'O')]]

And then you just want to pick the item in each of those zipped tuples that appears the most frequently -- aka statistics.mode:

>>> import statistics
>>> [[statistics.mode(i) for i in zip(*j)] for j in chunks]
[['B_S', 'O', 'O', 'O'], 
['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'], 
['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]

or all together:

from statistics import mode

original_list = [['B_S', 'O', 'O', 'O'],
                 ['B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'B_S', 'O'],

                 ['O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O'],

                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]
CHUNK_LEN = 3

desired_output = [
    [mode(i) for i in zip(*j)] 
    for j in (
        original_list[i*CHUNK_LEN:(i+1)*CHUNK_LEN] 
        for i in range(len(original_list)//CHUNK_LEN)
    )
]

Obviously if you can make original_list just be correctly grouped up front it's a lot easier:

from statistics import mode

original_list = [[['B_S', 'O', 'O', 'O'],
                 ['B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'B_S', 'O']],

                 [['O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O']],

                 [['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]]

desired_output = [
    [mode(i) for i in zip(*j)] 
    for j in original_list
]

Upvotes: 3

arshovon
arshovon

Reputation: 13651

A broader solution using loop:

def merge_result(data):
    ar = []
    for i in range(0, len(data)-2, 3):
        temp = []        
        for j in range(len(data[i])):
            if data[i][j] == data[i+1][j]:
                temp.append(data[i][j])
            elif data[i+2][j] == data[i+1][j]:
                temp.append(data[i+1][j])
            elif data[i][j] == data[i+2][j]:
                temp.append(data[i][j])
            else:
                temp.append('O')
        ar.append(temp)
    return ar

if __name__ == "__main__":
    original_list = [['B_S', 'O', 'O', 'O'],
                 ['B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'B_S', 'O'],

                 ['O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'O'],

                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'B_S', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O'],
                 ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]
    print(merge_result(original_list))

Output:

[['B_S', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', 'B_S', 'O', 'O', 'B_S', 'O', 'O', 'O']]

Upvotes: 2

Related Questions