Question: 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! Fig 1: Pandas Data Frame (Function Input) as Markdown    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    Fig 2: Example of Target Data Structure (Function Output) for List ` 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 ],]  `

Answer: 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  Use 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   Use 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)   Now, use 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   Chain another 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   Finally, chain Series.to_list.