Изменение подмножества pandas MultiIndex - PullRequest
4 голосов
/ 04 февраля 2020

У меня есть pandas DataFrame с MultiIndex, и я ищу быстрый способ изменить подмножество одного из моих уровней MultiIndex для некоторых уровней. Вот пример, где мне нужно изменить 2 индекса (0, 10) и (9, 25) и изменить их «конечный» уровень.

import pandas as pd

# Make up some data
data = pd.DataFrame({
    'start': [0, 12, 9, 24],
    'end': [10, 20, 25, 32],
    'col1': ['a', 'b', 'a', 'd'],
    'col2': [1, 1, 2, 2]
}).set_index(['start', 'end'])

# Idx to change for the "end" level
idx_to_change = {(0, 10), (9, 25)}

### A cumbersome way to do it ###
data.reset_index(inplace=True)
subset = [True if (s, t) in idx_to_change else False for (s, t, _, _) in data.values]
data.loc[subset, 'end'] += 10

# Update the data
data.set_index(['start', 'end'], inplace=True)

Как видите, это занимает немного кода, чтобы изменить некоторые индексы (и это может быть особенно медленно). Знаете ли вы о лучшем способе сделать это?

Спасибо за вашу помощь

Ответы [ 3 ]

3 голосов
/ 04 февраля 2020

Одним из способов является переназначение индекса на pd.MultiIndex:

idx_to_change = {(0, 10), (9, 25)}

data.index = pd.MultiIndex.from_tuples([i if i not in idx_to_change else (i[0],i[1]+10) for i in data.index], names=("start","end"))
print (data)

          col1  col2
start end           
0     20     a     1
12    20     b     1
9     35     a     2
24    32     d     2
1 голос
/ 04 февраля 2020

Можно преобразовать MultiIndex во фрейм данных, изменить его, а затем назначить обратно в качестве индекса.

data = pd.DataFrame({
    'start': [0, 12, 9, 24],
    'end': [10, 20, 25, 32],
    'col1': ['a', 'b', 'a', 'd'],
    'col2': [1, 1, 2, 2]
}).set_index(['start', 'end'])

# extract & modify the index
idx = data.index.to_frame()
idx.loc[[(0,10), (9,25)], 'end'] += 10

# assign it back

# in more recent versions of pandas (0.24+) the MultiIndex can be created 
# directly from the data frame
data.index = pd.MultiIndex.from_frame(idx[['start', 'end']])

# with earlier versions the trick is to convert the dataframe `idx` to 
# desired MultiIndex
data.index = idx.reset_index(drop=True).set_index(['start','end']).index


data
# outputs
          col1  col2
start end
0     20     a     1
12    20     b     1
9     35     a     2
24    32     d     2
0 голосов
/ 04 февраля 2020

Одним из способов является то, что вы можете взять индексы в виде списка и переназначить его после обновления;

idx_to_change = {(0, 10), (9, 25)}
as_list = data.index.tolist()
for idx_change in idx_to_change:
    idx = as_list.index(idx_change)
    as_list[idx] = (as_list[idx][0], list(as_list[idx])[1] + 10) #tuple is immutable so need to be converted to list
data.index = as_list

Надеюсь, это поможет.

...