2013-12-11 5 views
10

Создание моего dataframe:значения индекса Переименования в мультииндексных dataframe

from pandas import * 
arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
      ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']] 

tuples = zip(*arrays) 

index = MultiIndex.from_tuples(tuples, names=['first','second']) 
data = DataFrame(randn(8,2),index=index,columns=['c1','c2']) 

data 
Out[68]: 
        c1  c2 
first second      
bar one  0.833816 -1.529639 
     two  0.340150 -1.818052 
baz one -1.605051 -0.917619 
     two -0.021386 -0.222951 
foo one  0.143949 -0.406376 
     two  1.208358 -2.469746 
qux one -0.345265 -0.505282 
     two  0.158928 1.088826 

Я хотел бы переименовать «первый» значение индекса, такие как «бар» -> «кошку», «Баз» -> "собаки »и т. д. Однако каждый пример, который я прочитал, либо работает на одноуровневом индексе, либо/или проходит через весь индекс, чтобы эффективно воссоздать его с нуля. Я думал что-то вроде:

data = data.reindex(index={'bar':'cat','baz':'dog'}) 

но это не работает, и я не ожидаю, что он будет работать с несколькими индексами. Могу ли я сделать такую ​​замену без цикла через весь индекс данных?

Начало Редактирование

Я Есмь колеблющимся, чтобы обновить 0,13 до релиза, так что я использовал следующий обходной путь:

index = data.index.tolist() 
for r in xrange(len(index)): 
    index[r] = (codes[index[r][0]],index[r][1]) 

index = pd.MultiIndex.from_tuples(index,names=data.index.names) 
data.index = index 

Где предыдущий Defined словарь код: строковых пар. На самом деле это не такая высокая производительность, как я ожидал (требуется пара секунд для работы более ~ 1,1 миллиона строк). Это не так красиво, как однострочный, но он работает.

Торцевые Редактировать

+1

В настоящее время это расширенное предложение для будущей версии pandas: https://github.com/pydata/pandas/issues/4160 (@unutbu soln works ATM пока) – Jeff

ответ

16

Используйте set_levels метод (new in version 0.13.0):

data.index.set_levels([[u'cat', u'dog', u'foo', u'qux'], 
         [u'one', u'two']], inplace=True) 

дает

    c1  c2 
first second      
cat one -0.289649 -0.870716 
     two -0.062014 -0.410274 
dog one  0.030171 -1.091150 
     two  0.505408 1.531108 
foo one  1.375653 -1.377876 
     two -1.478615 1.351428 
qux one  1.075802 0.532416 
     two  0.865931 -0.765292 

Чтобы переназначить уровень на основе Словаре, вам можешь использовать такую ​​функцию, как это:

def map_level(df, dct, level=0): 
    index = df.index 
    index.set_levels([[dct.get(item, item) for item in names] if i==level else names 
         for i, names in enumerate(index.levels)], inplace=True) 

dct = {'bar':'cat', 'baz':'dog'} 
map_level(data, dct, level=0) 

Вот работоспособный пример:

import numpy as np 
import pandas as pd 

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
      ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']] 
tuples = zip(*arrays) 
index = pd.MultiIndex.from_tuples(tuples, names=['first','second']) 
data = pd.DataFrame(np.random.randn(8,2),index=index,columns=['c1','c2']) 
data2 = data.copy() 

data.index.set_levels([[u'cat', u'dog', u'foo', u'qux'], 
         [u'one', u'two']], inplace=True) 
print(data) 
#      c1  c2 
# first second      
# cat one  0.939040 -0.748100 
#  two -0.497006 -1.185966 
# dog one -0.368161 0.050339 
#  two -2.356879 -0.291206 
# foo one -0.556261 0.474297 
#  two  0.647973 0.755983 
# qux one -0.017722 1.364244 
#  two  1.007303 0.004337 

def map_level(df, dct, level=0): 
    index = df.index 
    index.set_levels([[dct.get(item, item) for item in names] if i==level else names 
         for i, names in enumerate(index.levels)], inplace=True) 
dct = {'bar':'wolf', 'baz':'rabbit'} 
map_level(data2, dct, level=0) 
print(data2) 
#      c1  c2 
# first second      
# wolf one  0.939040 -0.748100 
#  two -0.497006 -1.185966 
# rabbit one -0.368161 0.050339 
#  two -2.356879 -0.291206 
# foo one -0.556261 0.474297 
#  two  0.647973 0.755983 
# qux one -0.017722 1.364244 
#  two  1.007303 0.004337 
+0

0.13 все еще находится в разработке, я все еще запуск 0.12.0. Есть ли какие-либо указания относительно стабильности 0,13x? Я не вижу много документации для .index.set_levels. В приведенном выше примере уровни настройки просты, так как у нас есть только два уровня. Можно ли передать словарь для замены только значений в одном индексе, не касаясь (или не указывая значения) других осей? – tnknepp

+1

не работает в 0.16 больше –

+1

Работает отлично для меня в 0.16.2 и 0.18.1 – joris

1

set_levels Метод причинял мои новые имена столбцов, чтобы быть в порядке. Поэтому я нашел другое решение, которое не очень чистое, но работает хорошо. Способ заключается в print df.index (или эквивалентно df.columns), а затем скопируйте и вставьте результат с измененными желаемыми значениями. Например:

print data.index 

мультииндексных (уровни = [[ 'бар', 'База', 'Foo', 'QUX'], [ 'один', 'два']], метко = [[ 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]], names = ['first', 'second'])

data.index = MultiIndex(levels=[['new_bar', 'new_baz', 'new_foo', 'new_qux'], 
           ['new_one', 'new_two']], 
         labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]], 
         names=['first', 'second']) 

Мы можем иметь полный контроль над именами путем редактирования этикетки, а также.Например:

data.index = MultiIndex(levels=[['bar', 'baz', 'foo', 'qux'], 
           ['one', 'twooo', 'three', 'four', 
           'five', 'siz', 'seven', 'eit']], 
         labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 3, 4, 5, 6, 7]], 
         names=['first', 'second']) 

Обратите внимание, что в этом примере мы уже сделали что-то вроде from pandas import MultiIndex или from pandas import *.

+0

У меня такая же проблема с set_levels, что отличает новые имена столбцов. Я думаю, что он помещает новые имена столбцов на основе предыдущего параметра «метки» MultiIndex. Хорошее обходное решение. – Eddy

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