Search code examples
pythonlistaverage

average of "row"and "column" in list


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


Solution

  • (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]]