0

I am trying to make an new list with the averages from every n row and column. my original list looks like this:

\list =
\[\[1,1,1,2,2,2,3,3,3\],
\[4,4,4,5,5,5,6,6,6\],
\[7,7,7,8,8,8,9,9,9\],
\[0,0,0,1,1,1,2,2,2\],
\[3,3,3,4,4,4,5,5,5\],
\[6,6,6,7,7,7,8,8,8\]\]

n = 3\

my new list should look like this: list = [[4,5,6],[3,4,5]]

i tried it in al lot of ways but i get lost along the way

Bart008
  • 3
  • 1
  • 3
    Can you please share with us what you have tried and the problem? – Daniel Hao Mar 05 '23 at 17:04
  • it's in python. i tried to make a total and than divide it by n**2; but i don't know how to make it go through the whole list so i can make the new list – Bart008 Mar 06 '23 at 17:50
  • i used for and while loops to make the total (for a in list and while b < n) – Bart008 Mar 06 '23 at 17:55
  • 1
    Can you explain to us how do you get the expected results? Just one example to make the logic clear. It's a 6x9 matrix.. – Daniel Hao Mar 06 '23 at 18:09
  • From what I understand, your list represents a 2D array, which you want to partition into sub-arrays each of size `n * n`, calculating the average of each. Is this correct? – user21283023 Mar 06 '23 at 18:30
  • 1
    @user21283023; that's correct. and avery row should be a sub-list – Bart008 Mar 06 '23 at 18:48

1 Answers1

2

(Note that this solution relies on the numpy package, and assumes that your list is represented as a 2D NumPy array.)


Input Data

import numpy as np

lst = [[1,1,1,2,2,2,3,3,3],
       [4,4,4,5,5,5,6,6,6],
       [7,7,7,8,8,8,9,9,9],
       [0,0,0,1,1,1,2,2,2],
       [3,3,3,4,4,4,5,5,5],
       [6,6,6,7,7,7,8,8,8]
      ]

n = 3

# Convert the list of lists to a 2D array.
arr_2d = np.array(lst)

print(arr_2d)

Solution

Partitioning a 2D array

There appears to be no simple method to partition a 2D array into 2D sub-arrays in Python. But this answer provides a function that can accomplish this:

def blockshaped(arr, nrows, ncols):
    """
    Return an array of shape (n, nrows, ncols) where
    n * nrows * ncols = arr.size

    If arr is a 2D array, the returned array should look like n sub-blocks with
    each sub-blocks preserving the "physical" layout of arr.
    """
    h, w = arr.shape
    assert h % nrows == 0, f"{h} rows is not evenly divisible by {nrows}"
    assert w % ncols == 0, f"{w} cols is not evenly divisible by {ncols}"
    return (arr.reshape(h//nrows, nrows, -1, ncols)
               .swapaxes(1,2)
               .reshape(-1, nrows, ncols))

Output of blockshaped(arr_2d, n, n) (will be represented as a 3D array):

[[[1 1 1]
  [4 4 4]
  [7 7 7]]

 [[2 2 2]
  [5 5 5]
  [8 8 8]]

 [[3 3 3]
  [6 6 6]
  [9 9 9]]

 [[0 0 0]
  [3 3 3]
  [6 6 6]]

 [[1 1 1]
  [4 4 4]
  [7 7 7]]

 [[2 2 2]
  [5 5 5]
  [8 8 8]]]

Calculating average of partitions

After applying the blockshaped() function, you can use np.mean() to calculate the averages of each sub-array, and then np.array_split() to then group them as sub-lists according to the rows of the original array.

I've created a function to accomplish all of this:

def avg_partitions(arr, n):
    """
    Partitions a a 2D array into n x n sub-arrays and outputs 
    as a list of lists each of their average values grouped row-wise.
    """

    # Partition into 2D sub arrays each of size n x n
    sub_arrs = blockshaped(arr, n, n)

    # Create a list made up of the mean of each of these sub-arrays
    avg_values = [np.mean(a) for a in sub_arrs]

    # Work out how many sublists to split the resulting chucks into (Number of Rows / n)
    n_lists = arr.shape[0] // n

    # Split the average into sub-lists (made of arrays)
    avg_sublists = np.array_split(avg_values, n_lists)

    # Convert the arrays to lists
    avg_sublists = [a.tolist() for a in avg_sublists]

    return avg_sublists

Output of avg_partitions(arr_2d, n):

[[4.0, 5.0, 6.0], [3.0, 4.0, 5.0]]
user21283023
  • 936
  • 8