python - Parsing Multi-Index Pandas Data Frame for Tuple List Appendage - Stack Overflow

admin2025-05-01  0

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

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

],] 

`

Share Improve this question asked Jan 2 at 20:07 BP130BP130 675 bronze badges 1
  • Can you give your input dataframe as code? You dataframe headers are really tuples? – Scott Boston Commented Jan 3 at 13:52
Add a comment  | 

2 Answers 2

Reset to default 1

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.

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)]
]

]
转载请注明原文地址:http://anycun.com/QandA/1746098694a91648.html