Другое решение с быстрым тестом:
pd.DataFrame(sorted(df.values.tolist(), key=lambda k: (k[0]%2==0, k[1])), columns=['a', 'b'])
Распечатки:
a b
0 1 0
1 3 1
2 5 2
3 7 3
4 2 0
5 4 1
6 6 2
7 8 3
Бенчмарк:
df = pd.DataFrame({'a': [1,2,3,4,5,6,7,8],
'b': [0,0,1,1,2,2,3,3]})
from timeit import timeit
def f1():
return pd.DataFrame(sorted(df.values.tolist(), key=lambda k: (k[0]%2==0, k[1])), columns=['a', 'b'])
def f2():
s = df.groupby('b').cumcount().sort_values(kind='mergesort')
return df.loc[s.index]
def f3():
return df.iloc[np.lexsort([df['b'], df.groupby('b').cumcount()])]
t1 = timeit(lambda: f1(), number=1_000)
t2 = timeit(lambda: f2(), number=1_000)
t3 = timeit(lambda: f3(), number=1_000)
print(t1)
print(t2)
print(t3)
Отпечатки (AMD 2400G / Ubuntu 18.04, Python 3.8.3, Pandas 1.0.3):
0.45131446300365496
2.2533202580088982
1.6977271080104401
Таким образом, решение с sorted()
кажется самым быстрым.
РЕДАКТИРОВАТЬ: примерно после ~ 3000 элементов решение с np.lexsort
начинает побеждать.