In my previous article where I found the average of a list in Python without using imports, in this article I want to expand how you could apply the same concept, but to two-dimensional lists. Thankfully, if you know how to find the average of a one dimensional list in Python, you can simply expand this knowledge to finding the average of a two-dimensional list.
The big question to ask, when finding the average of a two-dimensional list, is seeking what is it that you want to average: is the whole list, or just an average of each row, or is it an average of each list?
Here’s a simple 2-dimensional list showing some results according to what type of average is sought:
[[1, 2, 3],
[3, 4, 5],
[5, 6, 13]]
# average of each cell = 36 / 9 = 4.6667
# average of each row = (6 + 12 + 18) / 3 = 14
# average of each column = (9 + 12 + 21) / 3 = 14
# average of each row as list = [2, 4, 8]
# average of each column as list = [3, 4, 7]
# average of the rows = (2 + 4 + 8) / 3 = 4.6667
# average of the columns = (3 + 4 + 7) = 4.6667
To calculate the average of each cell, all that is needed is to obtain the values of all numeric cells within the 2D list, and then to sum the contents of those numeric values and divide by the quantity of numeric values.
We can easily achieve this feat by capturing all values into a list, and then apply what we’ve already learned previously by averaging a list in Python without using any libraries .
But how would we go about calculating the average of each row, or column within a 2D list in Python?
Could the same concept be applied to calculating the average of these elements within a 2D list?
Yes, they can!
Calculate Average Each Row & Column
To calculate the average of each row or column in a 2D list we need to store the contents of numeric values in each row and column.
The best way to store these values is by using a
dict
to operate as the row or column identifier and to then append all numeric values into that
dict
.
Once we have a list of numbers we can then simply apply what we already know on how to obtain an average of a list.
Let’s create a function that can create all of these averages, we’ll use a function to help coordinate the calculation.
def calculate_averages(list_2d):
cell_total = list()
row_totals = dict()
column_totals = dict()
for row_idx, row in enumerate(list_2d):
for cell_idx, cell in enumerate(row):
# is cell a number?
if type(cell) in [int, float, complex]:
cell_total.append(cell)
if row_idx in row_totals:
row_totals[row_idx].append(cell)
else:
row_totals[row_idx] = [cell]
if cell_idx in column_totals:
column_totals[cell_idx].append(cell)
else:
column_totals[cell_idx] = [cell]
per_row_avg = [sum(row_totals[row_idx]) / len(row_totals[row_idx]) for row_idx in row_totals]
per_col_avg = [sum(column_totals[col_idx]) / len(column_totals[col_idx]) for col_idx in column_totals]
row_avg = sum(per_row_avg) / len(per_row_avg)
col_avg = sum(per_col_avg) / len(per_col_avg)
return {'cell_average': sum(cell_total) / len(cell_total),
'per_row_average': per_row_avg,
'per_column_average': per_col_avg,
'row_average': row_avg,
'column_average': col_avg}
data = [['this', 'is a', 'header row'], [1, 2, 3], [3, 4, 5], [5, 6, 13]]
result = calculate_averages(data)
print(result)
# {'cell_average': 4.666666666666667, 'per_row_average': [2.0, 4.0, 8.0], 'per_column_average': [3.0, 4.0, 7.0], 'row_average': 4.666666666666667, 'column_average': 4.666666666666667}
This function performs a loop through each row, and then through each cell in the row. Hence, why we have two for-loops to match the dimensions of the two-dimensional list.
All operations are performed on the cell level where we first check the value of the cell is numeric. As you can see with the
data
variable I have added a header row to the 2D list, as these are
not numeric
these items need to be filtered out from the average calculations.
Once we’ve filtered the numeric values, we then append this to our
cell_total
list – this is the list that will provide the simple average
of all numeric values
in the list.
Then we move to the row and column section, as shown below:
if row_idx in row_totals:
row_totals[row_idx].append(cell)
else:
row_totals[row_idx] = [cell]
if cell_idx in column_totals:
column_totals[cell_idx].append(cell)
else:
column_totals[cell_idx] = [cell]
In this section we check if an identifer representing the row or the column exists on the dictionary for each subsequent
row_totals
and
column_totals
. The identifier in this case is the
row_idx
or the
cell_idx
respectively.
If these properties already exist on the dictionary, then we append another element to the existing list, if not we then create a list with the first
cell
value.
The final section of our function before outputting the result, is this:
per_row_avg = [sum(row_totals[row_idx]) / len(row_totals[row_idx]) for row_idx in row_totals]
per_col_avg = [sum(column_totals[col_idx]) / len(column_totals[col_idx]) for col_idx in column_totals]
row_avg = sum(per_row_avg) / len(per_row_avg)
col_avg = sum(per_col_avg) / len(per_col_avg)
Here we have a one-liner for-loop that takes the results of each list in our compiled
row_totals
and
column_totals
dictionaries and performs the simple average needed: total the values inside the list and then divide by the quantity of items in the list.
The
per_row_avg
variable produces a list representing the average of each row. The only issue here being, that it does not display a
None
value for any non-numeric rows. The same applies to the
per_col_avg
variable too.
Finally, to obtain an average of a row we obtain the lists of
per_row_avg
and
per_col_avg
and then, once again, apply the simple average calculation of summing the contents of the list and dividing by the quantity of values in that list. Now we have an average per row, and an average per column.
Summary
The trick to help manage the calculation of a two-dimensional list, where it’s uncertain if the list contains proper values to calculate an average, is to store each of the rows and columns in a dict during the operation, and then to store numeric values into a list.
In this article we’ve also shown how you can calculate the total average of all numeric values within a 2D list using Python’s functions (no imports needed), and how to apply the same logic to calculate the averages of rows and columns for your 2D list.
Here is just the function which you would call
calculate_averages(your_2d_list)
and insert your 2D list in the parameters:
def calculate_averages(list_2d):
cell_total = list()
row_totals = dict()
column_totals = dict()
for row_idx, row in enumerate(list_2d):
for cell_idx, cell in enumerate(row):
# is cell a number?
if type(cell) in [int, float, complex]:
cell_total.append(cell)
if row_idx in row_totals:
row_totals[row_idx].append(cell)
else:
row_totals[row_idx] = [cell]
if cell_idx in column_totals:
column_totals[cell_idx].append(cell)
else:
column_totals[cell_idx] = [cell]
per_row_avg = [sum(row_totals[row_idx]) / len(row_totals[row_idx]) for row_idx in row_totals]
per_col_avg = [sum(column_totals[col_idx]) / len(column_totals[col_idx]) for col_idx in column_totals]
row_avg = sum(per_row_avg) / len(per_row_avg)
col_avg = sum(per_col_avg) / len(per_col_avg)
return {'cell_average': sum(cell_total) / len(cell_total),
'per_row_average': per_row_avg,
'per_column_average': per_col_avg,
'row_average': row_avg,
'column_average': col_avg}