Определенно выглядит как ошибка.
s1.index.tolist() возвращается к ожидаемому значению без «бара».
>>> s1.index.tolist()
[('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two')]
s1 ["bar"] возвращает нулевую серию.
>>> s1["bar"]
Series([], dtype: float64)
Стандартные методы отменяют это, кажется, не работает, либо:
>>> del s1["bar"]
>>> s1["bar"]
Series([], dtype: float64)
>>> s1.__delitem__("bar")
>>> s1["bar"]
Series([], dtype: float64)
Однако, как и ожидалось, пытаясь захватить новый ключ вызывает исключение KeyError:
>>> s1["booz"]
... KeyError: 'booz'
Основное отличие заключается в том, что вы действительно смотрите исходный код между ними в pandas.core.index.py
class MultiIndex(Index):
...
def _get_levels(self):
return self._levels
...
def _get_labels(self):
return self._labels
# ops compat
def tolist(self):
"""
return a list of the Index values
"""
return list(self.values)
Таким образом, index.tolist() и _labels не имеют доступа к одному и тому же фрагменту общей информации, на самом деле они даже не близки.
Итак, мы можем использовать это, чтобы вручную обновить результирующий индексатор.
>>> s1.index.labels
FrozenList([[1, 1, 2, 2], [0, 1, 0, 1]])
>>> s1.index._levels
FrozenList([[u'bar', u'baz', u'foo'], [u'one', u'two']])
>>> s1.index.values
array([('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two')], dtype=object)
Если мы сравним это с начальным multindexed индексом, мы получим
>>> s.index.labels
FrozenList([[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])
>>> s.index._levels
FrozenList([[u'bar', u'baz', u'foo'], [u'one', u'two']])
Так _levels атрибуты не обновляются, а значения есть.
EDIT: Переопределение было не так просто, как я думал.
EDIT: написал пользовательскую функцию, чтобы исправить это поведение
from pandas.core.base import FrozenList, FrozenNDArray
def drop(series, level, index_name):
# make new tmp series
new_series = series.drop(index_name)
# grab all indexing labels, levels, attributes
levels = new_series.index.levels
labels = new_series.index.labels
index_pos = levels[level].tolist().index(index_name)
# now need to reset the actual levels
level_names = levels[level]
# has no __delitem__, so... need to remake
tmp_names = FrozenList([i for i in level_names if i != index_name])
levels = FrozenList([j if i != level else tmp_names
for i, j in enumerate(levels)])
# need to turn off validation
new_series.index.set_levels(levels, verify_integrity=False, inplace=True)
# reset the labels
level_labels = labels[level].tolist()
tmp_labels = FrozenNDArray([i-1 if i > index_pos else i
for i in level_labels])
labels = FrozenList([j if i != level else tmp_labels
for i, j in enumerate(labels)])
new_series.index.set_labels(labels, verify_integrity=False, inplace=True)
return new_series
Пример пользователя:
>>> s1 = drop(s, 0, "bar")
>>> s1.index
MultiIndex(levels=[[u'baz', u'foo'], [u'one', u'two']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
>>> s1.index.tolist()
[('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two')]
>>> s1["bar"]
...
KeyError: 'bar'
EDIT: Это, кажется, специфичные для dataframes/серии с multiindexing, как стандартные панд. Класс core.index.Index не имеет одинаковых ограничений. Я бы рекомендовал подать отчет об ошибке.
Рассмотрим ту же серию со стандартным индексом:
>>> s = p.Series(np.random.randn(6))
>>> s.index
Int64Index([0, 1, 2, 3, 4, 5], dtype='int64')
>>> s.drop(0, inplace=True)
>>> s.index
Int64Index([1, 2, 3, 4, 5], dtype='int64')
То же самое верно и для dataframe
>>> df = p.DataFrame([np.random.randn(6), np.random.randn(6)])
>>> df.index
Int64Index([0, 1], dtype='int64')
>>> df.drop(0, inplace=True)
>>> df.index
Int64Index([1], dtype='int64')
Это звучит как ошибка, нет? –
@AmiTavory Может быть. Во всяком случае, вопрос все еще стоит. :-) – joaquin
совершенно! точка, возможно, возможно, помимо поиска обходного пути - вы можете записать ее как ошибку? кредит для его поиска принадлежит вам. –