나는 cxrodgers answer 에서 약간의 기능을 만들었습니다. IMHO는 데이터 프레임이나 시리즈에 관계없이 순전히 인덱스에서 작동하기 때문에 최상의 솔루션입니다.
내가 추가 한 수정 사항이 하나 있습니다.이 to_frame()메서드는 인덱스 수준이없는 새 이름을 발명합니다. 따라서 새 색인은 이전 색인에 존재하지 않는 이름을 갖게됩니다. 이 이름 변경을 되 돌리는 코드를 추가했습니다.
아래는 코드입니다. 한동안 직접 사용해 보았는데 제대로 작동하는 것 같습니다. 문제 나 엣지 케이스를 찾으면 대답을 조정해야 할 의무가 많습니다.
import pandas as pd
def _handle_insert_loc(loc: int, n: int) -> int:
"""
Computes the insert index from the right if loc is negative for a given size of n.
"""
return n + loc + 1 if loc < 0 else loc
def add_index_level(old_index: pd.Index, value: Any, name: str = None, loc: int = 0) -> pd.MultiIndex:
"""
Expand a (multi)index by adding a level to it.
:param old_index: The index to expand
:param name: The name of the new index level
:param value: Scalar or list-like, the values of the new index level
:param loc: Where to insert the level in the index, 0 is at the front, negative values count back from the rear end
:return: A new multi-index with the new level added
"""
loc = _handle_insert_loc(loc, len(old_index.names))
old_index_df = old_index.to_frame()
old_index_df.insert(loc, name, value)
new_index_names = list(old_index.names)
new_index_names.insert(loc, name)
new_index = pd.MultiIndex.from_frame(old_index_df, names=new_index_names)
return new_index
다음 unittest 코드를 전달했습니다.
import unittest
import numpy as np
import pandas as pd
class TestPandaStuff(unittest.TestCase):
def test_add_index_level(self):
df = pd.DataFrame(data=np.random.normal(size=(6, 3)))
i1 = add_index_level(df.index, "foo")
self.assertEqual([None, None], i1.names)
self.assertTrue(np.all(i1.get_level_values(0) == "foo"))
self.assertTrue(np.all(i1.get_level_values(1) == df.index))
i2 = add_index_level(i1, ["x", "y"]*3, name="xy", loc=2)
i3 = add_index_level(i2, ["a", "b", "c"]*2, name="abc", loc=-1)
self.assertEqual([None, None, "xy", "abc"], i3.names)
self.assertTrue(np.all(i3.get_level_values(0) == "foo"))
self.assertTrue(np.all(i3.get_level_values(1) == df.index))
self.assertTrue(np.all(i3.get_level_values(2) == ["x", "y"]*3))
self.assertTrue(np.all(i3.get_level_values(3) == ["a", "b", "c"]*2))
axis=1때문에 를 추가하여 열에 레벨을 추가하는 데 특히 좋습니다df.columns.