Сортировать pandas фрейм данных по столбцу в другом фрейме данных - pandas - PullRequest
1 голос
/ 27 января 2020

Допустим, у меня есть Pandas DataFrame с двумя столбцами, например:

df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [100, 200, 300, 400]})
print(df)

   a    b
0  1  100
1  2  200
2  3  300
3  4  400

И, скажем, у меня также есть серия Pandas, например:

s = pd.Series([1, 3, 2, 4])
print(s)

0    1
1    3
2    2
3    4
dtype: int64

Как можно отсортировать столбец a, чтобы он стал таким же, как ряд s, с соответствующими значениями строк, отсортированными вместе?

Мой желаемый вывод будет:

   a    b
0  1  100
1  3  300
2  2  200
3  4  400

Есть ли способ достичь этого?

Пожалуйста, проверьте ответ на свой вопрос ниже.

Ответы [ 2 ]

3 голосов
/ 27 января 2020

А как же:

(
    df.assign(s=s)
    .sort_values(by='s')
    .drop('s', axis=1)
)
2 голосов
/ 27 января 2020

Я сталкивался с этими проблемами довольно часто, поэтому я просто подумал поделиться своими решениями в Pandas.

Решения:

Решение 1:

Использование set_index для преобразования столбца a в индекс, затем использование reindex для изменения порядка, затем использование rename_axis для изменения имени индекса обратно на a, затем использование reset_index преобразовать столбец a из индекса обратно в столбец:

print(df.set_index('a').reindex(s).rename_axis('a').reset_index('a'))

Решение 2:

Использование set_index для преобразования столбца a в индекс, затем используйте loc для изменения порядка, затем используйте reset_index для преобразования столбца a из индекса обратно в столбец:

print(df.set_index('a').loc[s].reset_index())

Решение 3:

Используя iloc для индексации строк в другом порядке, затем используйте map, чтобы получить тот порядок, который соответствует df, чтобы отсортировать его по серии s:

print(df.iloc[list(map(df['a'].tolist().index, s))])

Решение 4:

Использование pd.DataFrame для создания нового объекта DataFrame, затем использование sorted с аргументом key для сортировки DataFrame b y серия s:

print(pd.DataFrame(sorted(df.values.tolist(), key=lambda x: s.tolist().index(x[0])), columns=df.columns))

Время:

Время с кодом ниже:

import pandas as pd
from timeit import timeit
df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [100, 200, 300, 400]})
s = pd.Series([1, 3, 2, 4])
def u10_1():
    return df.set_index('a').reindex(s).rename_axis('a').reset_index('a')
def u10_2():
    return df.set_index('a').loc[s].reset_index()
def u10_3():
    return df.iloc[list(map(df['a'].tolist().index, s))]
def u10_4():
    return pd.DataFrame(sorted(df.values.tolist(), key=lambda x: s.tolist().index(x[0])), columns=df.columns)
print('u10_1:', timeit(u10_1, number=1000))
print('u10_2:', timeit(u10_2, number=1000))
print('u10_3:', timeit(u10_3, number=1000))
print('u10_4:', timeit(u10_4, number=1000))

Выход:

u10_1: 3.012849470495621
u10_2: 3.072132612502147
u10_3: 0.7498072134665241
u10_4: 0.8109911930595484

У @ Аллен тоже довольно хороший ответ.

...