Как запросить значения столбцов индекса MultiIndex в pandas
пример кода:
In [171]: A = np.array([1.1, 1.1, 3.3, 3.3, 5.5, 6.6])
In [172]: B = np.array([111, 222, 222, 333, 333, 777])
In [173]: C = randint(10, 99, 6)
In [174]: df = pd.DataFrame(zip(A, B, C), columns=['A', 'B', 'C'])
In [175]: df.set_index(['A', 'B'], inplace=True)
In [176]: df
Out[176]:
C
A B
1.1 111 20
222 31
3.3 222 24
333 65
5.5 333 22
6.6 777 74
теперь я хочу получить значения:
1 квартале: в диапазоне [3.3, 6.6] - ожидаемое возвращаемое значение: [3.3, 5.5, 6.6] или [3.3, 3.3, 5.5, 6.6] в случае последнего включительно, и [3.3, 5.5] или [3.3, 3.3, 5.5] если нет.
Q2: в диапазоне [2.0, 4.0] - ожидаемое возвращаемое значение: [3.3] или [3.3, 3.3]
то же самое для любого другого MultiIndex измерение, например значения B:
Q3: в диапазоне [111, 500] с повторениями, как количество строк данных в диапазоне - ожидаемое возвращаемое значение: [111, 222, 222, 333, 333]
более формальной:
предположим, что T-таблица со столбцами A, B и C. таблица включает n строк. Ячейки таблицы-это числа, например двойные, B и C целые числа. Давайте создадим таблицы данных таблицы T, назовем ее DF. Зададим столбцы A и B индексов DF (без дублирования, т. е. без отдельных столбцов A и B как индексы, и отдельные данные), т. е. A и B в этом случае MultiIndex.
вопросы:
- Как написать запрос на индекс, например, для запроса индекса A (или B), скажем, в интервале меток [120.0, 540.0]? Метки 120.0 и 540.0 существует. Я должен уточнить, что меня интересует только список индексов в качестве ответа на запрос!
- как то же самое, но в случае метки 120.0 и 540.0 не существует, но есть этикетки по значению ниже 120, выше 120 и меньше 540 или выше 540?
- в случае, если ответ для Q1 и Q2 был уникальными значениями индекса, теперь одинаковыми, но с повторениями, как количество строк данных в диапазоне индексов.
Я знаю ответы на вышеуказанные вопросы в случае столбцов, которые не являются индексами, но в случае индексов, после долгих исследований в интернете и экспериментов с функциональностью панды, Я не преуспевать. Единственный метод (без дополнительного программирования), который я вижу сейчас, - это дублирование A и B в качестве столбцов данных в дополнение к индексу.
3 ответов
запрос df на MultiIndex значения, например where (A > 1.7) и (B :
In [536]: result_df = df.loc[(df.index.get_level_values('A') > 1.7) & (df.index.get_level_values('B') < 666)]
In [537]: result_df
Out[537]:
C
A B
3.3 222 43
333 59
5.5 333 56
Следовательно, чтобы получить, например, 'A' значения Индекса, если еще требуется:
In [538]: result_df.index.get_level_values('A')
Out[538]: Index([3.3, 3.3, 5.5], dtype=object)
проблема в том, что в больших данных периодов работы по индексу выбор хуже на 10%, чем сортировка обычных строк. И в повторяющейся работе, в петле накапливалась задержка. Видеть пример:
In [558]: df = store.select(STORE_EXTENT_BURSTS_DF_KEY)
In [559]: len(df)
Out[559]: 12857
In [560]: df.sort(inplace=True)
In [561]: df_without_index = df.reset_index()
In [562]: %timeit df.loc[(df.index.get_level_values('END_TIME') > 358200) & (df.index.get_level_values('START_TIME') < 361680)]
1000 loops, best of 3: 562 µs per loop
In [563]: %timeit df_without_index[(df_without_index.END_TIME > 358200) & (df_without_index.START_TIME < 361680)]
1000 loops, best of 3: 507 µs per loop
для лучшей читаемости, мы можем просто использовать the query()
метод, чтобы избежать длительных df.index.get_level_values()
и reset_index
/set_index
туда и обратно.
вот цель DataFrame
:
In [12]: df
Out[12]:
C
A B
1.1 111 68
222 40
3.3 222 20
333 11
5.5 333 80
6.6 777 51
ответ 1 квартале (A
в границах [3.3, 6.6]
):
In [13]: df.query('3.3 <= A <= 6.6') # for closed interval
Out[13]:
C
A B
3.3 222 20
333 11
5.5 333 80
6.6 777 51
In [14]: df.query('3.3 < A < 6.6') # for open interval
Out[14]:
C
A B
5.5 333 80
и конечно можно поиграть с <, <=, >, >=
для любого вида включение.
аналогично, ответ для Q2 (A
в границах [2.0, 4.0]
):
In [15]: df.query('2.0 <= A <= 4.0')
Out[15]:
C
A B
3.3 222 20
333 11
ответ Q3 (B
в границах [111, 500]
):
In [16]: df.query('111 <= B <= 500')
Out[16]:
C
A B
1.1 111 68
222 40
3.3 222 20
333 11
5.5 333 80
и более того, вы можете комбината запрос для col A
и B
очень естественно!
In [17]: df.query('0 < A < 4 and 150 < B < 400')
Out[17]:
C
A B
1.1 222 40
3.3 222 20
333 11
С "float", как индекс, вы всегда хотите использовать его как столбец, а не прямое действие индексирования. Все они будут работать независимо от того, существуют конечные точки или нет.
In [11]: df
Out[11]:
C
A B
1.1 111 81
222 45
3.3 222 98
333 13
5.5 333 89
6.6 777 98
In [12]: x = df.reset_index()
1 квартале
In [13]: x.loc[(x.A>=3.3)&(x.A<=6.6)]
Out[13]:
A B C
2 3.3 222 98
3 3.3 333 13
4 5.5 333 89
5 6.6 777 98
Q2
In [14]: x.loc[(x.A>=2.0)&(x.A<=4.0)]
Out[14]:
A B C
2 3.3 222 98
3 3.3 333 13
Q3
In [15]: x.loc[(x.B>=111.0)&(x.B<=500.0)]
Out[15]:
A B C
0 1.1 111 81
1 1.1 222 45
2 3.3 222 98
3 3.3 333 13
4 5.5 333 89
если вы хотите вернуть индексы, просто установите их. Это дешевая операция.
In [16]: x.loc[(x.B>=111.0)&(x.B<=500.0)].set_index(['A','B'])
Out[16]:
C
A B
1.1 111 81
222 45
3.3 222 98
333 13
5.5 333 89
если вы действительно хотите фактические значения Индекса
In [5]: x.loc[(x.B>=111.0)&(x.B<=500.0)].set_index(['A','B']).index
Out[5]:
MultiIndex
[(1.1, 111), (1.1, 222), (3.3, 222), (3.3, 333), (5.5, 333)]