2015-02-04 1 views
2

У меня есть два вопроса, касающиеся мультииндексов данных pandas dataframe.Pandas multi-index лучший способ среза для диапазонов подчиненных уровней

Предположим, у меня есть данные рамки DF следующим образом:

        data 
    port       bm pf 
    sector instrument date 
    1  A   2013-01-14 0 0 
         2013-01-15 5 5 
         2013-01-16 10 10 
         2013-01-17 15 15 
         2013-01-18 20 20 

который может быть создан с помощью следующего кода:

import pandas as pd 
date = pd.bdate_range('2013-01-14','2013-01-20').repeat(5) 
sector = [1,1,1,2,2] * 5 
df = pd.DataFrame(dict(port=['pf']*25,sector=sector,instrument=list('ABCDE')*5,date=date,data=xrange(25))) 
df = pd.concat([df,pd.DataFrame(dict(port=['bm']*25,sector=sector,instrument=list('ABCDE')*5,date=date,data=xrange(25)))],axis=0) 
df = df.set_index(['port','sector','instrument','date']) 
df = df.unstack('port') 

Я хочу, чтобы получить два набора результатов: все значения на 2013-01-17 и все значения с 2013-01-17 до конца серии.

Для первого я знаю, что я могу использовать один из следующих подходов:

idx = pd.IndexSlice 
targetdate = pd.Timestamp('2013-01-17') 
slicer = (slice(None),slice(None),targetdate) 

1) df.loc[slicer,:]

2) df.xs(pd.Timestamp('2013-01-17'),level=2)

3) df.xs(slicer,)

4) df[idx[:,:,targetdate],:]

Все они кажутся довольно неуклюжими. Есть ли более очевидный способ, которым я не хватает? Какие еще способы добиться этого. Наверное, я надеюсь, что есть что-то вроде df.loc(level=2)[targetdate] (что, конечно, не работает).

Для второго я только пришел с одним решением

query = df.index.get_level_values(2) >= pd.Timestamp('2013-01-17') 
df[query] 

Снова есть более эффективный способ сделать это?

Последний вопрос с бонусом: что делает df.index.get_loc_level()? Я чувствую, что это должно помочь в этом, но я понятия не имею, как его использовать.

Благодаря

ответ

4

Я думаю, что это маскировка, как вы делаете, это будет очень хорошо здесь:

query = df.index.get_level_values(2) >= pd.Timestamp('2013-01-17') 
df[query] 

, если у вас есть много повторения в датах можно улучшить работу с чем-то более низким -уровень:

query = (df.index.levels[2] >= pd.Timestamp("2013-01-17"))[df.index.labels[2]] 
df[query] 

Я, вероятно, получить выкрикнул за это ...! Но в некоторых случаях это будет значительно быстрее.


get_loc_level является подобным ВМ, то есть этикетки на основе, а не по позиции:

Получить целое местонахождения срезе для запрошенной метки или кортежа

In [21]: df.index.get_loc_level(2) 
Out[21]: 
(slice(15, 25, None), 
MultiIndex(levels=[[u'A', u'B', u'C', u'D', u'E'], [2013-01-14 00:00:00, 2013-01-15 00:00:00, 2013-01-16 00:00:00, 2013-01-17 00:00:00, 2013-01-18 00:00:00]], 
      labels=[[3, 3, 3, 3, 3, 4, 4, 4, 4, 4], [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]], 
      names=[u'instrument', u'date'])) 

по умолчанию это берет первый индекс, но вы можете пройти еще ...

In [21]: df.index.get_loc_level((1, "A")) 
Out[21]: 
(slice(0, 5, None), <class 'pandas.tseries.index.DatetimeIndex'> 
[2013-01-14, ..., 2013-01-18] 
Length: 5, Freq: None, Timezone: None) 
+0

Спасибо @ Andy я мог бы просто проверить, есть ли у вас какие-либо мысли по первому вопросу? Существуют ли более эффективные способы выбора элементов из индекса даты, кроме четырех, описанных выше? .. и спасибо за объяснение get_loc_level. Вы можете использовать примеры использования, которые вы могли бы поделиться. Где я могу его применить? –

+0

@TahnoonPasha tbh Я считаю get_loc_level почти частным/низкоуровневым, я предпочитаю использовать 'xs' (поперечное сечение), который, я думаю, лучше описывает функциональность. Что касается эффективности, __try__ большой кадр/пример с '% timeit' - я подозреваю, что моя вторая строка будет самой быстрой (это было в тесте, которое я сделал, хотя я не пробовал все ваши перестановки). –

+0

спасибо @ Энди. Цените свою помощь в этом –