Home > OS >  Pandas create a multi-indexed DataFrame with random values
Pandas create a multi-indexed DataFrame with random values

Time:11-22

I have the following multi-indexed DataFrame.

import pandas as pd
import numpy as np

# Create df ---
names = ['add', 'sub', 'mul', 'divi'] # List of the names of our maths functions
size = 4

tups = [('scalars', 'add', 'sc0'), ('scalars', 'add', 'sc1'), ('scalars', 'add', 'sc2'), ('scalars', 'sub', 'sc0'), ('scalars', 'sub', 'sc1'), ('scalars', 'mul', 'sc0'), ('scalars', 'mul', 'sc1'), ('scalars', 'mul', 'sc2'), ('scalars', 'divi', 'sc0'), ('scalars', 'divi', 'sc1'), ('operator', '', '')]
df = pd.DataFrame(columns=pd.MultiIndex.from_tuples(tups))

df['operatorIndex'] = np.random.randint(0, len(names), size)
df['operator'] = df['operatorIndex'].apply(lambda x: str(names[x]))

groupSize = 2
df['ID']=np.divmod(np.arange(len(df)),groupSize)[0] 1
df.set_index('ID', inplace=True)
df.sort_index(inplace=True)
> df

    scalars                                   operator  operatorIndex
    add         sub     mul         divi        
    sc0 sc1 sc2 sc0 sc1 sc0 sc1 sc2 sc0 sc1     
ID                                              
1   NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   mul       2
1   NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   add       0
2   NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   sub       1
2   NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   mul       2

How could I assign random integers (between 0 and 100) only to sc columns that correlate to the value in each row's operator column? Preferably, this would be done without any loops.

An example could look like

> df

    scalars                                   operator  operatorIndex
    add         sub     mul         divi        
    sc0 sc1 sc2 sc0 sc1 sc0 sc1 sc2 sc0 sc1     
ID                                              
1   NaN NaN NaN NaN NaN 7   3   9   NaN NaN   mul       2
1   29  12  11  NaN NaN NaN NaN NaN NaN NaN   add       0
2   NaN NaN NaN 6   36  NaN NaN NaN NaN NaN   sub       1
2   NaN NaN NaN NaN NaN 16  2   29  NaN NaN   mul       2

CodePudding user response:

First, mask the values where the 2nd column level (df.columns.get_level_values(level=1)) coincides with the operator column value (df['operator']). This can be done by converting both to numpy arrays (using the to_numpy method) and taking advantage of numpy broadcasting.

mask = df.columns.get_level_values(level=1).to_numpy() == df['operator'].to_numpy()[:, None]

Then pass this mask to DataFrame.mask, and update the locations of True values with random integers between 0 and 100.

res = df.mask(mask, np.random.randint(0, 101, size=df.shape))

Output

# Given the input df
>>> df 

   scalars                                              operator operatorIndex
       add            sub       mul           divi                            
       sc0  sc1  sc2  sc0  sc1  sc0  sc1  sc2  sc0  sc1                       
ID                                                                            
1      NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN      mul             2
1      NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN      add             0
2      NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN      sub             1
2      NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN      mul             2

>>> mask 

[[False False False False False  True  True  True False False False False]
 [ True  True  True False False False False False False False False False]
 [False False False  True  True False False False False False False False]
 [False False False False False  True  True  True False False False False]]

>>> res

       add            sub       mul           divi                            
       sc0  sc1  sc2  sc0  sc1  sc0  sc1  sc2  sc0  sc1                       
ID                                                                            
1      NaN  NaN  NaN  NaN  NaN    2   79   17  NaN  NaN      mul             2
1       15   16   30  NaN  NaN  NaN  NaN  NaN  NaN  NaN      add             0
2      NaN  NaN  NaN   35   94  NaN  NaN  NaN  NaN  NaN      sub             1
2      NaN  NaN  NaN  NaN  NaN   11   95   48  NaN  NaN      mul             2
  • Related