Saya membuat sedikit fungsi dari jawaban cxrodgers , yang IMHO adalah solusi terbaik karena bekerja murni pada indeks, terlepas dari bingkai atau seri data apa pun.
Ada satu perbaikan yang saya tambahkan: to_frame()metode ini akan menemukan nama baru untuk tingkat indeks yang tidak memilikinya. Dengan demikian indeks baru akan memiliki nama yang tidak ada di indeks lama. Saya menambahkan beberapa kode untuk mengembalikan perubahan nama ini.
Di bawah ini adalah kodenya, saya telah menggunakannya sendiri untuk sementara waktu dan tampaknya berfungsi dengan baik. Jika Anda menemukan masalah atau kasus tepi, saya akan sangat berkewajiban untuk menyesuaikan jawaban saya.
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
Itu melewati kode unittest berikut:
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, karenadf.columnstidak memiliki metode "set_index" seperti indeks, yang selalu mengganggu saya.