2016-12-26 3 views
2

Я хочу выбрать и изменить значение ячейки dataframe. Для этого фрейма данных используются 2 индекса: «datetime» и «idx». Оба содержат метки, которые являются уникальными и последовательными. Индекс «datetime» имеет метку datetime типа datetime, а «idx» имеет целые знаковые метки.Нарезка и присвоение значений мультииндексированных данных для данных pandas из уникальных последовательных индексов

import numpy as np 
import pandas as pd 

dt = pd.date_range("2010-10-01 00:00:00", periods=5, freq='H') 
d = {'datetime': dt, 'a': np.arange(len(dt))-1,'b':np.arange(len(dt))+1} 
df = pd.DataFrame(data=d) 
df.set_index(keys='datetime',inplace=True,drop=True) 
df.sort_index(axis=0,level='datetime',ascending=False,inplace=True) 

df.loc[:,'idx'] = np.arange(0, len(df),1)+5 
df.set_index('idx',drop=True,inplace=True,append=True) 
print(df) 

'Вот dataframe:

      a b 
datetime   idx  
2010-10-01 04:00:00 5 3 5 
2010-10-01 03:00:00 6 2 4 
2010-10-01 02:00:00 7 1 3 
2010-10-01 01:00:00 8 0 2 
2010-10-01 00:00:00 9 -1 1 

' Скажем, я хочу, чтобы получить строку, где IDX = 5. Как мне это сделать? Я мог бы использовать это:

print(df.iloc[0]) 

Тогда я получить результат ниже:

a 3 
b 5 
Name: (2010-10-01 04:00:00, 5), dtype: int32 

Но я хочу, чтобы получить доступ и установить значение в этой ячейке, где IDX = 5, столбец = «а» , , указав значение idx и имя столбца 'a'. Как мне это сделать?

Прошу совета.

+0

Если ваша проблема решена, подумайте о принятии ответа MaxU. Это гораздо более подробно. – MYGz

+1

Хорошо, я принял ответ MaxU. Тем не менее, я думаю, что я поеду с вашим решением, поскольку я тестировал его быстрее (1,28 мс против 2,77 мс) и короче, без необходимости конвертировать целое число в строку, а затем конкатенировать строку «idx» для ввода в функцию eval. ..также, так как я буду использовать это для for-loops. – ConanG

+0

Да. Поскольку xs не будет пересекать весь столбец для поиска значения idx. Он рассчитает хэш-значение 5 и выберет его в 1 раз. Другой индекс i.e индекс datetime слишком длинный для записи в нарезке: | – MYGz

ответ

5

Вы можете использовать DatFrame.query() метод для запроса мультииндексных ДФЙ:

In [54]: df 
Out[54]: 
         a b 
datetime   idx 
2010-10-01 04:00:00 5 3 5 
2010-10-01 03:00:00 6 2 4 
2010-10-01 02:00:00 7 1 3 
2010-10-01 01:00:00 8 0 2 
2010-10-01 00:00:00 9 -1 1 

In [55]: df.query('idx==5') 
Out[55]: 
         a b 
datetime   idx 
2010-10-01 04:00:00 5 3 5 

In [56]: df.query('idx==5')['a'] 
Out[56]: 
datetime    idx 
2010-10-01 04:00:00 5  3 
Name: a, dtype: int32 

Или вы можете использовать DataFrame.eval() метод, если вам необходимо установить/обновить некоторые клетки:

In [61]: df.loc[df.eval('idx==5'), 'a'] = 100 

In [62]: df 
Out[62]: 
          a b 
datetime   idx 
2010-10-01 04:00:00 5 100 5 
2010-10-01 03:00:00 6  2 4 
2010-10-01 02:00:00 7  1 3 
2010-10-01 01:00:00 8  0 2 
2010-10-01 00:00:00 9  -1 1 

Объяснение:

In [59]: df.eval('idx==5') 
Out[59]: 
datetime    idx 
2010-10-01 04:00:00 5  True 
2010-10-01 03:00:00 6  False 
2010-10-01 02:00:00 7  False 
2010-10-01 01:00:00 8  False 
2010-10-01 00:00:00 9  False 
dtype: bool 

In [60]: df.loc[df.eval('idx==5')] 
Out[60]: 
         a b 
datetime   idx 
2010-10-01 04:00:00 5 3 5 

PS Если у вашего оригинального MultiIndex нет nam эс, вы можете легко установить их с помощью rename_axis() метода:

(немного дороже) решения
df.rename_axis(('datetime','idx')).query(...) 

Альтернативы - использование sort_index() + pd.IndexSlice[]:

In [106]: df.loc[pd.IndexSlice[:,5], ['a']] 
... 
skipped 
... 
KeyError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (2), lexsort depth (0)' 

так что мы должны были бы сортировать индекс первым:

In [107]: df.sort_index().loc[pd.IndexSlice[:,5], ['a']] 
Out[107]: 
         a 
datetime   idx 
2010-10-01 04:00:00 5 3 
+1

Ему нужно изменить значение столбца 'a' после запроса. – MYGz

+0

@MYGz, спасибо за подсказку! Я расширил свой ответ – MaxU

3

Еще один способ сделать это.

Выберите значение:

df.xs(5, level=-1) 

Заданное значение:

df.set_value(df.xs(5, level=-1).index, 'a', 100) 
+2

, это работает, только если '5' является уникальным в' MultiIndex' – piRSquared

+0

@piRSquared Hmm. Ты прав. В этом случае ему придется использовать оба ключа. В этом случае даже eval или любой другой метод не будут работать. Правильно? – MYGz

+1

Это ограничение с 'set_value'. 'set_value' работает очень быстро, но работает только на отдельных ячейках. Если '5' не является уникальным, то' df.xs (5, level = -1) .index' не будет скаляром. присвоение 'loc' не имеет этой проблемы, но медленнее. – piRSquared

0

В случае, если для использования в цикле в большом наборе данных, я понял, это примерно в 20 раз быстрее сначала извлечь столбцы кадра данных в тип pandas Series, а затем продолжить операции выбора и назначения.

Или

Еще быстрее (почти 10000 раз быстрее) в Numpy массив, если индекс метки случается последовательные целые числа.

Решение MYGz было хорошим, но в моем случае использования для цикла было слишком медленным, чтобы быть выполнимым, поскольку эти операции занимали большую часть времени.

Смежные вопросы