Reverse values in pd.Series by their value type

Question:

I have this pd.Series:

s = pd.Series([1, 'a', 1.4, 'b', 4, 98, 6.7, 'hello', 98.9])

My goal is to switch the values by each value type in reverse order.

My desired output is:

>>> s = pd.Series([98, 'hello', 98.9, 'b', 4, 1, 6.7, 'a', 1.4])
>>> s
0       98
1    hello
2     98.9
3        b
4        4
5        1
6      6.7
7        a
8      1.4
dtype: object
>>> 

As you can see, the different value types are still in mixed order, but they are reversed by the other same type values.

  • The integer order was 1, 4, 98 and it’s now 98, 4, 1.

  • The float order was 1.4, 6.7, 98.9 and it’s now 98.9, 6.7, 1.4.

  • The string order was 'a', 'b', 'hello' and it’s now 'hello', 'b', 'a'

What I have tried so far is:

>>> s.to_frame().groupby([[*map(type, s)]], sort=False).apply(lambda x: x.iloc[::-1]).reset_index(drop=True)
       0
0     98
1      4
2      1
3  hello
4      b
5      a
6   98.9
7    6.7
8    1.4
>>> 

And yes, they do get reversed in order. But, since I’m using groupby, the values are grouped together into separated groups, they’re not mixed together.

How would I fix this?

Asked By: U12-Forward

||

Answers:

I just figured out a solution myself, it’s a bit long an inefficient. I would still prefer better solutions though.

This is how I did it:

print(
     s.to_frame().groupby([[*map(type, s)]], sort=False)
     .apply(lambda x: x.reindex(x.index[::-1])
     .rename(index=dict(zip(x.index[::-1], x.index))))
     .reset_index(level=0, drop=True)
     .sort_index().squeeze().rename(index=None)
)

Output:

0       98
1    hello
2     98.9
3        b
4        4
5        1
6      6.7
7        a
8      1.4
dtype: object

I use to_frame to convert this Series into a DataFrame, and I use map to give me the types of all the values. After that, I use groupby to group them and apply and rename to reverse the order/index of them. The next step is to use reset_index to reset the index and sort the values by the index using sort_index. Then, I just use squeeze to convert this DataFrame to a Series again, and rename to remove the index name.

Answered By: U12-Forward
out = (s.groupby(s.map(type), sort=False)
       .apply(lambda x: pd.Series(x.sort_values(ascending=False).tolist(), index=x.index)))

out

0       98
1    hello
2     98.9
3        b
4        4
5        1
6      6.7
7        a
8      1.4
dtype: object
Answered By: Panda Kim
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.