convert series index (matching on a pattern) to dataframe columns

Viewed 201

I have a series (with index as shown) appearing as

E1         543
Units1_E   100
E2         553
Units2_E   420
E3         513
Units3_E   110
F1         243
Units1_F   500
F2         450
Units2_F   300
F3         400
Units3_F   200

I am looking to convert it into dataframe such that the output comes as

 E_F     Units
 543     100
 553     420
 513     110
 243     500
 450     300
 400     200

So the output desired is more like a pair value column.. Am not sure how this could be done efficiently, am thinking of regex to filter the series index ?

3 Answers

If is necessary match pair and unpair values in Series is possible create MultiIndex by integer division and modulo by array with length of Series and reshape by Series.unstack:

arr = np.arange(len(s))
s.index = [arr// 2, arr % 2]
df = s.unstack()
df.columns = ['E_F','Units']
print (df)
   E_F  Units
0  543    100
1  553    420
2  513    110
3  243    500
4  450    300
5  400    200

Or create new DataFrame by indexing - pair and unpair values:

#pandas 0.24+
a = s.to_numpy()
#pandas below
#a = s.values
df = pd.DataFrame({'E_F':a[::2], 'Units':a[1::2]})
print (df)
   E_F  Units
0  543    100
1  553    420
2  513    110
3  243    500
4  450    300
5  400    200

Another idea (slowier like first 2) is test if first values of index are E or F, create Series and MultiIndex by GroupBy.cumcount:

idx = pd.Series(np.where(s.index.str[0].isin(['E','F']), 'E_F','Units'))
s.index = [idx.groupby(idx).cumcount(), idx]
df = s.unstack()
print (df)
   E_F  Units
0  543    100
1  553    420
2  513    110
3  243    500
4  450    300
5  400    200

Use this code:

>>> df = pd.DataFrame({i: pd.Series(x.values.ravel()) 
                      for i, x in pd.DataFrame(s).T.groupby(lambda x: x[0] in ['E', 'F'], axis=1)})
>>> df.columns = ['E_F', 'Units']
>>> df
   E_F  Units
0  100    543
1  420    553
2  110    513
3  500    243
4  300    450
5  200    400
>>> 

I use zip on s and s.shift to build the dataframe and reindex to pick only odd rows:

pd.DataFrame(list(zip(s.shift(), s)), columns=['E_F', 'Units']).reindex(index=range(1,s.size,2))

Out[225]:
      E_F  Units
1   543.0    100
3   553.0    420
5   513.0    110
7   243.0    500
9   450.0    300
11  400.0    200
Related