Как нарезать мультииндексный фрейм данных со списком меток на одном уровне - PullRequest
0 голосов
/ 04 марта 2020

Модули данных MultiIndex очень мощные, но лично я думаю, что на них недостаточно (четких) документов, особенно для различного типа нарезки ... Вот мой вопрос:

Как нарезать многоиндексированные данные только на одном уровне со списком меток? Пожалуйста, помогите мне, если у вас есть решение ( без сброса индексов и преобразования данных в одноуровневый индекс! Что очевидно и не эффективно )

Например, у нас есть следующий фрейм данных:

import pandas as pd
import numpy as np

df = pd.DataFrame(index=range(10))
df['id'] = pd.Series(range(10,20))
df['name'] = [f'name_{id}' for id in range(10,20)]
df['price'] = np.random.rand(df.index.size)
df['date'] = pd.date_range('20200310', '20200319')
df = df.set_index(['id', 'date'])
df

enter image description here

Нарезка на одну метку работает очень хорошо:

df.xs('2020-03-10', level='date', drop_level=False)

enter image description here

Но как мы можем нарезать список меток на этом уровне?

df.xs(('2020-03-10', '2020-03-11', '2020-03-12'), level='date', drop_level=False)

Это приводит к исключению :

enter image description here

Однако Python do c говорит, что параметр "key" также может быть кортежем:

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.xs.html

enter image description here

Ответы [ 2 ]

3 голосов
/ 04 марта 2020

Для фильтрации по нескольким значениям используйте Index.get_level_values с Index.isin и boolean indexing:

a = df[df.index.get_level_values('date').isin(('2020-03-10', '2020-03-11', '2020-03-12'))]
print (a)
                  name     price
id date                         
10 2020-03-10  name_10  0.557772
11 2020-03-11  name_11  0.122315
12 2020-03-12  name_12  0.775976

Однако Python do c говорит, что параметр "key" также может быть кортежем:

Кортеж можно использовать, но работать по-разному - вы можете выбрать обе метки, например:

b = df.xs((10, '2020-03-10'), drop_level=False)
print (b)
name      name_10
price    0.348808
Name: (10, 2020-03-10 00:00:00), dtype: object

c = df.xs((10, '2020-03-10'), level=('id','date'), drop_level=False)
print (c)
                  name     price
id date                         
10 2020-03-10  name_10  0.239876

Как упомянуто @yatu, другое решение с IndexSlice - с : для всех первых уровней и последним : для всех столбцов:

df = df.loc[pd.IndexSlice[:, ['2020-03-10', '2020-03-11', '2020-03-12']], :]
print (df)
                  name     price
id date                         
10 2020-03-10  name_10  0.557488
11 2020-03-11  name_11  0.592082
12 2020-03-12  name_12  0.547747
2 голосов
/ 04 марта 2020

Использование кортежей при доступе к мультииндексам предназначено для обращения к различным уровням / иерархии. Кортежи предназначены для этого использования, а не для передачи нескольких элементов в рамках одной иерархии / уровня. Для множественного выбора на одном и том же уровне вам нужно использовать некоторые другие функции, такие как Jezrael .

dates = ['2020-03-10', '2020-03-11', '2020-03-12']
filtered_df = df[df.index.get_level_values('date').isin(dates)]
...