Multiindex from array in Pandas with non unique data
pandas, python
Solution
I have an open issue to work on problems like these:
https://github.com/pydata/pandas/issues/388
Here is a solution. First a simple (and not very efficient) function to get the group ordinal number:
def group_position(*args):
"""
Get group position
"""
from collections import defaultdict
table = defaultdict(int)
result = []
for tup in zip(*args):
result.append(table[tup])
table[tup] += 1
return np.array(result)
i.e.
In [49]: group_position(df['Z'], df['A'])
Out[49]: array([0, 1, 2, 0, 1, 0, 1, 2, 0, 0])
Now use this as an auxiliary index variable and unstack:
In [52]: df
Out[52]:
Z A beta2 M shell
0 100 200 0.31120 197.2 -4.213
1 100 200 -0.41970 202.0 -1.143
2 100 200 0.03205 203.0 0.000
3 100 201 0.29670 191.0 -4.434
4 100 201 -0.48930 196.1 -4.691
5 100 202 0.30840 183.4 -4.134
6 100 202 -0.48730 188.2 -4.750
7 100 202 -0.24830 188.4 -1.106
8 100 203 0.30690 177.1 -4.355
9 101 203 -0.49560 182.5 -5.217
In [53]: df['pos'] = group_position(df['Z'], df['A'])
In [54]: df.set_index(['Z', 'A', 'pos']).unstack('pos')
Out[54]:
beta2 M shell
pos 0 1 2 0 1 2 0 1 2
Z A
100 200 0.3112 -0.4197 0.03205 197.2 202.0 203.0 -4.213 -1.143 0.000
201 0.2967 -0.4893 NaN 191.0 196.1 NaN -4.434 -4.691 NaN
202 0.3084 -0.4873 -0.24830 183.4 188.2 188.4 -4.134 -4.750 -1.106
203 0.3069 NaN NaN 177.1 NaN NaN -4.355 NaN NaN
101 203 -0.4956 NaN NaN 182.5 NaN NaN -5.217 NaN NaN
Final munging to get it exactly like you showed:
In [61]: result = df.set_index(['Z', 'A', 'pos']).unstack('pos')
In [62]: result.rename(columns=lambda x: '%s[%d]' % (x[0], x[1]+1)).reset_index()
Out[62]:
Z A beta2[1] beta2[2] beta2[3] M[1] M[2] M[3] shell[1] shell[2] shell[3]
0 100 200 0.3112 -0.4197 0.03205 197.2 202.0 203.0 -4.213 -1.143 0.000
1 100 201 0.2967 -0.4893 NaN 191.0 196.1 NaN -4.434 -4.691 NaN
2 100 202 0.3084 -0.4873 -0.24830 183.4 188.2 188.4 -4.134 -4.750 -1.106
3 100 203 0.3069 NaN NaN 177.1 NaN NaN -4.355 NaN NaN
4 101 203 -0.4956 NaN NaN 182.5 NaN NaN -5.217 NaN NaN
Problem
I have the following data frame ``` In[45]: data[:10] Out[45]: Z A beta2 M shell 0 100 200 0.3112 197.2 -4.213 1 100 200 -0.4197 202 -1.143 2 100 200 0.03205 203 0 3 100 201 0.2967 191 -4.434 4 100 201 -0.4893 196.1 -4.691 5 100 202 0.3084 183.4 -4.134 6 100 202 -0.4873 188.2 -4.75 7 100 202 -0.2483 188.4 -1.106 8 100 203 0.3069 177.1 -4.355 9 101 203 -0.4956 182.5 -5.217 ``` My question is, how can I group/transform the data in such a way that I have a MultiIndex with (Z,A) as indexes(or MultiIndexes) having into account that the data is not unique? To clear my goal this is what I expect to achieve: ``` beta2[1] beta2[2] beta2[3] M[1] M[2] M[3] shell[1] shell[2] shell[3] Z A 0 100 200 0.3112 -0.4197 0.03205 197.2 202 203 -4.213 -1.143 0 1 100 201 0.2967 0.4893 NaN 191 196.1 NaN -4.434 -4.691 NaN 2 100 202 0.3084 -0.4873 NaN 183.4 188.2 NaN -4.134 -4.75 NaN 3 100 203 0.3069 NaN NaN 177.1 NaN NaN -4.355 NaN NaN 4 101 203 -0.4956 NaN NaN 182.5 NaN NaN -5.217 NaN NaN ``` I understand that this involves at least two steps, one for the uniqueness and one for the indexing in Z,A so any help in one of those steps is appreciated, also, is there some data structure which is maybe more appropiate for this problem? Edit: I have found that the line: data=data.set_index(('Z','A')) solves the the problem of the indexing in Z,A. Unfortunately this only works if (Z,A) pairs are unique.