Я хочу выбрать строки в определенном порядке, указанном в списке. Например
Этот фрейм данных
a=[['car',1],['bike',3],['jewel',2],['tv',5],['phone',6]]
df=pd.DataFrame(a,columns=['items','quantity'])
>>> df
items quantity
0 car 1
1 bike 3
2 jewel 2
3 tv 5
4 phone 6
Я хочу получить строки с таким порядком ['tv','car','phone'], то есть сначала тв, потом машина, а потом телефон. Я пробовал этот метод, но он не поддерживает порядок
arr=['tv','car','phone']
df.loc[df['items'].isin(arr)]
items quantity
0 car 1
3 tv 5
4 phone 6






IIUC Categorical
df=df.loc[df['items'].isin(arr)]
df.iloc[pd.Categorical(df['items'],categories=arr,ordered=True).argsort()]
Out[157]:
items quantity
3 tv 5
0 car 1
4 phone 6
Или reindex: обратите внимание, что это не сохранит предыдущий индекс, и если исходный индекс имеет значение, вы должны использовать Categorical (упоминается Энди Л., если у вас есть дубликаты в элементах, reindex будет не удалось)
df.set_index('items').reindex(arr).reset_index()
Out[160]:
items quantity
0 tv 5
1 car 1
2 phone 6
Или цикл через arr
pd.concat([df[df['items']==x] for x in arr])
Out[171]:
items quantity
3 tv 5
0 car 1
4 phone 6
@ЭндиЛ. yelp это будет, Однако он может проверить другие методы, которые я предоставил :-)
прохладно! просто прошу убедиться, что я не ошибаюсь reindex :)
Вот ненавязчивое решение с использованием Index.get_indexer, которое не требует установки индекса:
df.iloc[pd.Index(df['items']).get_indexer(['tv','car','phone'])]
items quantity
3 tv 5
0 car 1
4 phone 6
Обратите внимание: если это станет частым явлением (я имею в виду «индексацию» со списком в столбце), вам лучше превратить этот столбец в индекс. Бонусные баллы, если вы сортируете его.
df2 = df.set_index('items')
df2.loc[['tv','car','phone']]
quantity
items
tv 5
car 1
phone 6
Вот еще один сорт, в котором используется .loc.
# Move items to the index, select, then reset.
df.set_index("items").loc[arr].reset_index()
Или другой, который не меняет индекс.
df.loc[df.reset_index().set_index("items").loc[arr]["index"]]
Почему бы нет:
>>> df.iloc[df.loc[df['items'].isin(arr), 'items'].apply(arr.index).sort_values().index]
items quantity
3 tv 5
0 car 1
4 phone 6
>>>
Я бы создал словарь от arr и map до items и dropna, sort_values
d = dict(zip(arr, range(len(arr))))
Out[684]: {'car': 1, 'phone': 2, 'tv': 0}
df.loc[df['items'].map(d).dropna().sort_values().index]
Out[693]:
items quantity
3 tv 5
0 car 1
4 phone 6
merge на помощь:
(pd.DataFrame({'items':['tv','car','phone']})
.merge(df, on='items')
)
Выход:
items quantity
0 tv 5
1 car 1
2 phone 6
df не в порядке массива.
@YaakovBressler Да, и об этом позаботится слияние с фреймом данных, созданным из массива.
Я не предполагаю, что порядок массива будет важен, но что, если бы это было так? Будет ли способ сохранить это в слиянии?
Я не понимаю. Это цель использования слияния здесь. То есть merge сохранить порядок ДАННОГО массива.
Порядок массива (не то, что у df)
Да, ПОРЯДОК МАССИВА поддерживается merge. Вы хоть пробовали?
Понимаю. Моя ошибка, извините. Однако исходный индекс был утерян.
Для выбора всех элементов, существующих на входе df, вот один с searchsorted и должен быть хорошим по производительности -
In [43]: sidx = df['items'].argsort()
In [44]: df.iloc[sidx[df['items'].searchsorted(['tv','car','phone'],sorter=sidx)]]
Out[44]:
items quantity
3 tv 5
0 car 1
4 phone 6
Почему бы не искать индекс, фильтровать и изменять порядок:
df['new_order'] = df['items'].apply(lambda x: arr.index(x) if x in arr else -1)
df_new = df[df['new_order']>=0].sort_values('new_order')
items quantity new_order
3 tv 5 0
0 car 1 1
4 phone 6 2
reindexпотерпит неудачу, если его реальные данные будут дублироватьсяitems?