Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convenient way to reindex one level of a multiindex

Tags:

python

pandas

consider the pd.Series s and pd.MultiIndex idx

idx = pd.MultiIndex.from_product([list('AB'), [1, 3], list('XY')],
                                 names=['one', 'two', 'three'])
s = pd.Series(np.arange(8), idx)
s

one  two  three
A    1    X        0
          Y        1
     3    X        2
          Y        3
B    1    X        4
          Y        5
     3    X        6
          Y        7
dtype: int32

I want to reindex on level='two' with np.arange(4)
I can do it with:

s.unstack([0, 2]).reindex(np.arange(4), fill_value=0).stack().unstack([0, 1])

one  two  three
A    0    X        0
          Y        0
     1    X        0
          Y        1
     2    X        0
          Y        0
     3    X        2
          Y        3
B    0    X        0
          Y        0
     1    X        4
          Y        5
     2    X        0
          Y        0
     3    X        6
          Y        7
dtype: int32

But I'm looking for something more direct if it exists. Any ideas?

like image 637
piRSquared Avatar asked Sep 28 '16 16:09

piRSquared


People also ask

How do I convert MultiIndex to single index in pandas?

To revert the index of the dataframe from multi-index to a single index using the Pandas inbuilt function reset_index(). Returns: (Data Frame or None) DataFrame with the new index or None if inplace=True.

How do you reindex a data frame?

Reindexing the columns using axis keyword One can reindex a single column or multiple columns by using reindex() method and by specifying the axis we want to reindex. Default values in the new index that are not present in the dataframe are assigned NaN.

How do you use reindex function?

The reindex() function is used to conform DataFrame to new index with optional filling logic, placing NA/NaN in locations having no value in the previous index. Conform DataFrame to new index with optional filling logic, placing NA/NaN in locations having no value in the previous index.


1 Answers

Unfortunately if need reindex with MultiIndex, need all levels:

mux = pd.MultiIndex.from_product([list('AB'), np.arange(4), list('XY')],
                                 names=['one', 'two', 'three'])

print (s.reindex(mux, fill_value=0))
one  two  three
A    0    X        0
          Y        0
     1    X        0
          Y        1
     2    X        0
          Y        0
     3    X        2
          Y        3
B    0    X        0
          Y        0
     1    X        4
          Y        5
     2    X        0
          Y        0
     3    X        6
          Y        7
dtype: int32

EDIT by comment:

idx = pd.MultiIndex.from_tuples([('A', 1, 'X'), ('B', 3, 'Y')],
                                 names=['one', 'two', 'three'])
s = pd.Series([5,6], idx)
print (s)
one  two  three
A    1    X        5
B    3    Y        6
dtype: int64

mux = pd.MultiIndex.from_tuples([('A', 0, 'X'), ('A', 1, 'X'), 
                                 ('A', 2, 'X'), ('A', 3, 'X'), 
                                 ('B', 0, 'Y'), ('B', 1, 'Y'), 
                                 ('B', 2, 'Y'), ('B', 3, 'Y')],
                                 names=['one', 'two', 'three'])

print (s.reindex(mux, fill_value=0))
one  two  three
A    0    X        0
     1    X        5
     2    X        0
     3    X        0
B    0    Y        0
     1    Y        0
     2    Y        0
     3    Y        6
dtype: int64

Direct Solution

new_lvl = np.arange(4)
mux = [(a, b, c) for b in new_lvl for a, c in s.reset_index('two').index.unique()]
s.reindex(mux, fill_value=0).sort_index()

one  two  three
A    0    X        0
          Y        0
     1    X        0
          Y        1
     2    X        0
          Y        0
     3    X        2
          Y        3
B    0    X        0
          Y        0
     1    X        4
          Y        5
     2    X        0
          Y        0
     3    X        6
          Y        7
dtype: int64
like image 94
jezrael Avatar answered Oct 12 '22 17:10

jezrael