Data set with many variables in Python, many indented dictionaries? I am working with a data set that has many variables. Currently I am storing the data in many indented dictionaries in the following way:
import numpy as np

X_POSITIONS = [0,1.5,1]
Y_POSITIONS = [0,1,2]
CHANNELS = ['left pad', 'right pad', 'top pad', 'bottom pad']

data = {}
for x in X_POSITIONS:
    data[x] = {}
    for y in Y_POSITIONS:
        data[x][y] = {}
        for ch in CHANNELS:
            data[x][y][ch] = np.random.rand() # Here I would place my data.

This works fine, but it is cumbersome if by some reason I need to change the order of the keys. Consider the following function:
def do_something_with_single_channel(data_from_one_channel):
    for x in data_from_one_channel:
        for y in data_from_one_channel[x]:
            print(f'x = {x}, y = {y}, data[x][y] = {data_from_one_channel[x][y]}')

Before calling this function the whole data object has to be rearranged:
new_data = {}
for ch in CHANNELS:
    new_data[ch] = {}
    for x in X_POSITIONS:
        new_data[ch][x] = {}
        for y in Y_POSITIONS:
            new_data[ch][x][y] = data[x][y][ch]

do_something_with_single_channel(new_data['left pad'])

Since this seems to be a very common thing to do, I am sure that there must already exist something better than dictionaries for this purpose. Ideally I imagine something that can be accessed in the same way as the arguments of a function by giving names to the variables and forgetting about the order, for example something of the form
do_something_with_single_channel(data[channel='left pad'])

Does something like this exists? What's the name?
Consider a nested dictionary comprehension:
data = {x:{y:{ch: np.random.rand()
          for ch in CHANNELS}
          for y in Y_POSITIONS}
          for x in X_POSITIONS}

pprint.pprint(data)

{0: {0: {'bottom pad': 0.4563182938806024,
         'left pad': 0.7109389987303294,
         'right pad': 0.04972926343584316,
         'top pad': 0.49018200203439044},
     1: {'bottom pad': 0.9197368747212471,
         'left pad': 0.49675239597387033,
         'right pad': 0.8846734838851381,
         'top pad': 0.2536908682927299},
     2: {'bottom pad': 0.19202917332705682,
         'left pad': 0.4680743827356374,
         'right pad': 0.9824888617543756,
         'top pad': 0.7871922090543111}},
 1: {0: {'bottom pad': 0.532524614137474,
         'left pad': 0.5500941768186839,
         'right pad': 0.046363378683273115,
         'top pad': 0.507924966038481},
     1: {'bottom pad': 0.18606527132423667,
         'left pad': 0.2926470569818338,
         'right pad': 0.4542221348696881,
         'top pad': 0.07304292627461106},
     2: {'bottom pad': 0.255962925458759,
         'left pad': 0.8206558157675303,
         'right pad': 0.028156806394849743,
         'top pad': 0.4617476628686388}},
 1.5: {0: {'bottom pad': 0.5537703566924752,
           'left pad': 0.14192043274483335,
           'right pad': 0.04030969407542717,
           'top pad': 0.4145838174513119},
       1: {'bottom pad': 0.10519991606894175,
           'left pad': 0.33471726599841756,
           'right pad': 0.10389744180143101,
           'top pad': 0.3927574328293768},
       2: {'bottom pad': 0.2950323578101469,
           'left pad': 0.9335998766267041,
           'right pad': 0.9337763647877098,
           'top pad': 0.6591832120994695}}}


However, to retain data of disparate types for later analyses, use pandas Data Frames which are essentially equal length Pandas Series (or 1-D Numpy arrays). And using itertools.product, you can return all possible combinations from multiple iterables:
from itertools import product 

import numpy as np
import pandas as pd

data = list(product(X_POSITIONS, Y_POSITIONS, CHANNELS))

# CAST LIST OF VALUES INTO DATA FRAME AND ASSIGN COLUMN OF RANDOM NUMs
df = (pd.DataFrame(data, columns=['X_POSITIONS', 'Y_POSITIONS', 'CHANNELS'])
        .assign(value = np.random.rand(len(data), 1)))

Output (N=36 for 3 * 3 * 4 product)
print(df)

#     X_POSITIONS  Y_POSITIONS    CHANNELS     value
# 0           0.0            0    left pad  0.761372
# 1           0.0            0   right pad  0.440973
# 2           0.0            0     top pad  0.182679
# 3           0.0            0  bottom pad  0.564203
# 4           0.0            1    left pad  0.954728
# 5           0.0            1   right pad  0.539686
# 6           0.0            1     top pad  0.957724
# 7           0.0            1  bottom pad  0.232217
# 8           0.0            2    left pad  0.488761
# 9           0.0            2   right pad  0.883579
# 10          0.0            2     top pad  0.010666
# 11          0.0            2  bottom pad  0.022114
# 12          1.5            0    left pad  0.129402
# 13          1.5            0   right pad  0.763472
# 14          1.5            0     top pad  0.475217
# 15          1.5            0  bottom pad  0.160637
# 16          1.5            1    left pad  0.521797
# 17          1.5            1   right pad  0.865391
# 18          1.5            1     top pad  0.263130
# 19          1.5            1  bottom pad  0.576295
# 20          1.5            2    left pad  0.004636
# 21          1.5            2   right pad  0.137856
# 22          1.5            2     top pad  0.156635
# 23          1.5            2  bottom pad  0.198684
# 24          1.0            0    left pad  0.143598
# 25          1.0            0   right pad  0.660144
# 26          1.0            0     top pad  0.588416
# 27          1.0            0  bottom pad  0.294899
# 28          1.0            1    left pad  0.915973
# 29          1.0            1   right pad  0.348533
# 30          1.0            1     top pad  0.391135
# 31          1.0            1  bottom pad  0.951016
# 32          1.0            2    left pad  0.015479
# 33          1.0            2   right pad  0.719314
# 34          1.0            2     top pad  0.976324
# 35          1.0            2  bottom pad  0.191481

To subset data frame by your indicator values:
print(df[df['CHANNELS'] == 'right pad'])

#     X_POSITIONS  Y_POSITIONS   CHANNELS     value
# 1           0.0            0  right pad  0.988888
# 5           0.0            1  right pad  0.091176
# 9           0.0            2  right pad  0.334674
# 13          1.5            0  right pad  0.706215
# 17          1.5            1  right pad  0.032422
# 21          1.5            2  right pad  0.024871
# 25          1.0            0  right pad  0.554525
# 29          1.0            1  right pad  0.790112
# 33          1.0            2  right pad  0.650198