Problem/Task: create a function that inputs a pandas data frame represented by the markdown in Fig 1 and converts/outputs it to a list with the structure represented in Fig 2.
I look forward to any feedback/support anyone might have!
| resources | ('Widget A (idx = 0)', 't1') | ('Widget A (idx = 0)', 't2') | ('Widget A (idx = 0)', 't3') | ('Widget A (idx = 0)', 't4') | ('Widget A (idx = 0)', 't5') | ('Widget A (idx = 0)', 't6') | ('Widget A (idx = 0)', 't7') | ('Widget A (idx = 0)', 't8') | ('Widget A (idx = 0)', 't9') | ('Widget A (idx = 0)', 't10') | ('Widget A (idx = 0)', 't11') | ('Widget A (idx = 0)', 't12') | ('Widget A (idx = 0)', 't13') | ('Widget A (idx = 0)', 't14') | ('Widget A (idx = 0)', 't15') | ('Widget B (idx = 1)', 't1') | ('Widget B (idx = 1)', 't2') | ('Widget B (idx = 1)', 't3') | ('Widget B (idx = 1)', 't4') | ('Widget B (idx = 1)', 't5') | ('Widget B (idx = 1)', 't6') | ('Widget B (idx = 1)', 't7') | ('Widget B (idx = 1)', 't8') | ('Widget B (idx = 1)', 't9') | ('Widget B (idx = 1)', 't10') | ('Widget B (idx = 1)', 't11') | ('Widget B (idx = 1)', 't12') | ('Widget B (idx = 1)', 't13') | ('Widget B (idx = 1)', 't14') | ('Widget B (idx = 1)', 't15') | ('Widget C (idx =2)', 't1') | ('Widget C (idx =2)', 't2') | ('Widget C (idx =2)', 't3') | ('Widget C (idx =2)', 't4') | ('Widget C (idx =2)', 't5') | ('Widget C (idx =2)', 't6') | ('Widget C (idx =2)', 't7') | ('Widget C (idx =2)', 't8') | ('Widget C (idx =2)', 't9') | ('Widget C (idx =2)', 't10') | ('Widget C (idx =2)', 't11') | 
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| m_1 | 10 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 17 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_2 | nan | nan | 15 | nan | nan | nan | 17 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 30 | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 24 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_3 | nan | nan | 23 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 26 | nan | nan | nan | 21 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 22 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_4 | nan | nan | 27 | nan | nan | nan | 19 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 22 | nan | nan | nan | 18 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 29 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_5 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 21 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | 
| m_6 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 16 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 16 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 25 | nan | nan | nan | nan | 
| m_7 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 14 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 30 | nan | nan | nan | nan | 
| m_8 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_9 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_10 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_11 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 14 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 12 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 10 | 
| m_12 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 
Problem/Task: create a function that inputs a pandas data frame represented by the markdown in Fig 1 and converts/outputs it to a list with the structure represented in Fig 2.
I look forward to any feedback/support anyone might have!
| resources | ('Widget A (idx = 0)', 't1') | ('Widget A (idx = 0)', 't2') | ('Widget A (idx = 0)', 't3') | ('Widget A (idx = 0)', 't4') | ('Widget A (idx = 0)', 't5') | ('Widget A (idx = 0)', 't6') | ('Widget A (idx = 0)', 't7') | ('Widget A (idx = 0)', 't8') | ('Widget A (idx = 0)', 't9') | ('Widget A (idx = 0)', 't10') | ('Widget A (idx = 0)', 't11') | ('Widget A (idx = 0)', 't12') | ('Widget A (idx = 0)', 't13') | ('Widget A (idx = 0)', 't14') | ('Widget A (idx = 0)', 't15') | ('Widget B (idx = 1)', 't1') | ('Widget B (idx = 1)', 't2') | ('Widget B (idx = 1)', 't3') | ('Widget B (idx = 1)', 't4') | ('Widget B (idx = 1)', 't5') | ('Widget B (idx = 1)', 't6') | ('Widget B (idx = 1)', 't7') | ('Widget B (idx = 1)', 't8') | ('Widget B (idx = 1)', 't9') | ('Widget B (idx = 1)', 't10') | ('Widget B (idx = 1)', 't11') | ('Widget B (idx = 1)', 't12') | ('Widget B (idx = 1)', 't13') | ('Widget B (idx = 1)', 't14') | ('Widget B (idx = 1)', 't15') | ('Widget C (idx =2)', 't1') | ('Widget C (idx =2)', 't2') | ('Widget C (idx =2)', 't3') | ('Widget C (idx =2)', 't4') | ('Widget C (idx =2)', 't5') | ('Widget C (idx =2)', 't6') | ('Widget C (idx =2)', 't7') | ('Widget C (idx =2)', 't8') | ('Widget C (idx =2)', 't9') | ('Widget C (idx =2)', 't10') | ('Widget C (idx =2)', 't11') | 
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| m_1 | 10 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 17 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_2 | nan | nan | 15 | nan | nan | nan | 17 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 30 | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 24 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_3 | nan | nan | 23 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 26 | nan | nan | nan | 21 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 22 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_4 | nan | nan | 27 | nan | nan | nan | 19 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 22 | nan | nan | nan | 18 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 29 | nan | nan | nan | nan | nan | nan | nan | nan | 
| m_5 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 21 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | 
| m_6 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 16 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 16 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 25 | nan | nan | nan | nan | 
| m_7 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 23 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 14 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 30 | nan | nan | nan | nan | 
| m_8 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_9 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_10 | nan | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | 10 | nan | nan | nan | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | 15 | nan | nan | nan | nan | nan | nan | 13 | nan | nan | nan | 13 | nan | nan | 
| m_11 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 14 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 12 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan | 10 | 
| m_12 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 1 | nan | 
`
components = [ 
# widget A -> [task_0...task_i] -> [(machine_id_0, dur_0)...machine_id_i, dur_i]
[   
    [(1, 10)], #t1
    [(12, 1)], #t2
    [(2, 15), (3, 23), (4,27)], #t3
    [(12, 1)], #t4
    [(8,10), (9,10), (10,10)], #t5
    [(12, 1)], #t6
    [(2, 17), (3, 15), (4,19)], #t7
    [(12, 1)], #t8
    [(8,10), (9,10), (10,10)], #t9
    [(12, 1)], #t10
    [(5, 15), (6, 16), (7,23)], #t11
    [(12, 1)], #t12
    [(8,10), (9,10), (10,10)], #t13
    [(12, 1)], #t14
    [(11,14)], #t15
],
# widget B -> [task_0...task_i] -> [(machine_id_0, dur_0)...machine_id_i, dur_i]
[   
    [(1, 23)], #t1
    [(12, 1)], #t2
    [(2, 30), (3, 26), (4,22)], #t2
    [(12, 1)], #t2
    [(8,15), (9,15), (10,15)], #t3
    [(12, 1)], #t2
    [(2, 23), (3, 21), (4,18)], #t4
    [(12, 1)], #t2
    [(8,15), (9,15), (10,15)], #t5
    [(12, 1)], #t2
    [(5, 21), (6, 16), (7,14)], #t6
    [(12, 1)], #t2
    [(8,15), (9,15), (10,15)], #t7
    [(12, 1)], #t2
    [(11,12)], #t8
],
# widget C -> [task_0...task_i] -> [(machine_id_0, dur_0)...machine_id_i, dur_i]
[   
    [(1, 17)], #t1
    [(12, 1)], #t2
    [(2, 24), (3, 22), (4,29)], #t3
    [(12, 1)], #t4
    [(8,13), (9,13), (10,13)], #t5
    [(12, 1)], #t6
    [(2, 23), (3, 25), (4,30)], #t7
    [(12, 1)], #t8
    [(8,13), (9,13), (10,13)], #t9
    [(12, 1)], #t10
    [(11,10)], #t11
],] 
`
Here's one approach:
Minimal Reproducible Example
import pandas as pd
import numpy as np
data = [[1, np.nan, np.nan],
        [np.nan, 2, 2],
        [np.nan, 3, np.nan]]
        
m_idx = pd.MultiIndex.from_tuples(
    [('A', 't1'),
     ('A', 't2'),
     ('B', 't1')]
    )
idx = pd.Index([f'm_{i}' for i in range(1, 4)], name='resources')
df = pd.DataFrame(data, columns=m_idx, index=idx)
             A         B
            t1   t2   t1
resources               
m_1        1.0  NaN  NaN
m_2        NaN  2.0  2.0
m_3        NaN  3.0  NaN
Desired output
components = [
    [ # A
        [(1, 1)], # t1
        [(2, 2), (3, 3)] # t2
    ],
    [ # B
        [(2, 2)] # t1
    ]
]
Code
components = (
    df.reset_index()
    .melt([('resources','')])
    .dropna(subset='value')
    .assign(
        tmp=lambda x: 
            list(
                zip(
                    x[('resources','')].str.split('_').str[1].astype(int), 
                    x['value'].astype(int))
                )
            )
    .groupby(['variable_0', 'variable_1'], sort=False)['tmp']
    .apply(list)
    .groupby('variable_0', sort=False)
    .apply(list)
    .to_list()
    )
Output:
components
[[[(1, 1)], [(2, 2), (3, 3)]], [[(2, 2)]]]
Explanation / Intermediates
df.reset_index to apply df.melt on the previous index (now: ('resources', '')) + df.dropna on 'value' column.df.reset_index().melt([('resources','')]).dropna(subset='value')
  (resources, ) variable_0 variable_1  value
0           m_1          A         t1    1.0
4           m_2          A         t2    2.0
5           m_3          A         t2    3.0
7           m_2          B         t1    2.0
df.assign to add a column ('tmp') as a tuple (list + zip) containing the digits from 'resources' (via Series.str.split + Series.astype) and values from 'value'..assign(...)
  (resources, ) variable_0 variable_1  value     tmp
0           m_1          A         t1    1.0  (1, 1)
4           m_2          A         t2    2.0  (2, 2)
5           m_3          A         t2    3.0  (3, 3)
7           m_2          B         t1    2.0  (2, 2)
df.groupby with the variable columns (original pd.MultiIndex) with sort=False to preserve order, and get 'tmp' as list (groupby.apply)..groupby(['variable_0', 'variable_1'])['tmp'].apply(list)
variable_0  variable_1
A           t1                    [(1, 1)]
            t2            [(2, 2), (3, 3)]
B           t1                    [(2, 2)]
Name: tmp, dtype: object
df.groupby, now solely with 'variable_0' (level 0 from original pd.MultIndex) and get list again..groupby('variable_0').apply(list)
variable_0
A    [[(1, 1)], [(2, 2), (3, 3)]]
B                      [[(2, 2)]]
Name: tmp, dtype: object
Series.to_list.If df is your multi-index dataframe, you could get the wanted components list by looping over your 3 blocks of widgets and using list comprehension with np.where which gives the rows and columns index where the values are not NaN:
widget = {}
components = []
widgets_col = sorted(list(set(df.columns.get_level_values(0))))  # ['Widget A (idx = 0)', 'Widget B (idx = 1)', 'Widget C (idx =2)']
for col in widgets_col:
    mask = df.loc[:, (col,)].notna().T
    components.append([[(j+1, df.loc["m_"+str(j+1), (col, "t"+str(i+1))])] 
                       for (i, j) in zip(*np.where(mask))])
print(components)
[
[
[(1, 10.0)], [(12, 1.0)], [(2, 15.0)], [(3, 23.0)], [(4, 27.0)], [(12, 1.0)], [(8, 10.0)], [(9, 10.0)], [(10, 10.0)], [(12, 1.0)], [(2, 17.0)], [(3, 15.0)], [(4, 19.0)], [(12, 1.0)], [(8, 10.0)], [(9, 10.0)], [(10, 10.0)], [(12, 1.0)], [(5, 15.0)], [(6, 16.0)], [(7, 23.0)], [(12, 1.0)], [(8, 10.0)], [(9, 10.0)], [(10, 10.0)], [(12, 1.0)], [(11, 14.0)]
], 
[
[(1, 23.0)], [(12, 1.0)], [(2, 30.0)], [(3, 26.0)], [(4, 22.0)], [(12, 1.0)], [(8, 15.0)], [(9, 15.0)], [(10, 15.0)], [(12, 1.0)], [(2, 23.0)], [(3, 21.0)], [(4, 18.0)], [(12, 1.0)], [(8, 15.0)], [(9, 15.0)], [(10, 15.0)], [(12, 1.0)], [(5, 21.0)], [(6, 16.0)], [(7, 14.0)], [(12, 1.0)], [(8, 15.0)], [(9, 15.0)], [(10, 15.0)], [(12, 1.0)], [(11, 12.0)]
], 
[
[(1, 17.0)], [(12, 1.0)], [(2, 24.0)], [(3, 22.0)], [(4, 29.0)], [(12, 1.0)], [(8, 13.0)], [(9, 13.0)], [(10, 13.0)], [(12, 1.0)], [(5, 23.0)], [(6, 25.0)], [(7, 30.0)], [(12, 1.0)], [(8, 13.0)], [(9, 13.0)], [(10, 13.0)], [(12, 1.0)], [(11, 10.0)]
]
]
