একটি পান্ডাস মাল্টিআইডেক্সে একটি স্তর প্রস্তুত করুন


105

কিছু গ্রুপিংয়ের পরে মাল্টিআইডেক্স সহ আমার একটি ডেটাফ্রেম তৈরি হয়েছে:

import numpy as np
import pandas as p
from numpy.random import randn

df = p.DataFrame({
    'A' : ['a1', 'a1', 'a2', 'a3']
  , 'B' : ['b1', 'b2', 'b3', 'b4']
  , 'Vals' : randn(4)
}).groupby(['A', 'B']).sum()

df

Output>            Vals
Output> A  B           
Output> a1 b1 -1.632460
Output>    b2  0.596027
Output> a2 b3 -0.619130
Output> a3 b4 -0.002009

আমি মাল্টিআইডেক্সে কীভাবে কোনও স্তরকে পূর্বে অগ্রিম করব যাতে আমি এটিকে এমন কিছুতে পরিণত করি:

Output>                       Vals
Output> FirstLevel A  B           
Output> Foo        a1 b1 -1.632460
Output>               b2  0.596027
Output>            a2 b3 -0.619130
Output>            a3 b4 -0.002009

উত্তর:


139

এক লাইনে এটি করার একটি দুর্দান্ত উপায় pandas.concat():

import pandas as pd

pd.concat([df], keys=['Foo'], names=['Firstlevel'])

আরও ছোট একটি উপায়:

pd.concat({'Foo': df}, names=['Firstlevel'])

এটি অনেকগুলি ডেটা ফ্রেমে সাধারণীকরণ করা যেতে পারে, দস্তাবেজগুলি দেখুন


28
এটি যোগ করে কলামগুলিতে একটি স্তর যুক্ত করার জন্য বিশেষত দুর্দান্ত axis=1, যেহেতু df.columnsসূচকের মতো "সেট_ইন্ডেক্স" পদ্ধতিটি নেই, যা সর্বদা আমাকে বাগড করে।
রুটার ক্যাসিজ

4
এটি দুর্দান্ত কারণ এটি pd.Seriesবস্তুগুলির জন্যও কাজ করে, যদিও বর্তমানে গৃহীত উত্তর (2013 থেকে) তা দেয় না।
জন

4
আর কাজ হচ্ছে না। প্রকারের ত্রুটি: অনিবার্য প্রকার: 'তালিকা'
সিডুয়েট

4
এটি বুঝতে আমার কিছুটা সময় লেগেছে যে প্রথম যুক্তির FirstLevelমতো আপনার যদি একাধিক কী ['Foo', 'Bar']থাকে তবে একই দৈর্ঘ্যও হওয়া দরকার, অর্থাত্ [df] * len(['Foo', 'Bar'])!
mrclng

7
এবং আরও সংক্ষিপ্ত:pd.concat({'Foo': df}, names=['Firstlevel'])
কাদে

128

আপনি প্রথমে এটি একটি সাধারণ কলাম হিসাবে যুক্ত করতে পারেন এবং তারপরে এটি বর্তমান সূচীতে যুক্ত করতে পারেন, সুতরাং:

df['Firstlevel'] = 'Foo'
df.set_index('Firstlevel', append=True, inplace=True)

এবং প্রয়োজন হলে ক্রমটি পরিবর্তন করুন:

df.reorder_levels(['Firstlevel', 'A', 'B'])

যার ফলাফল:

                      Vals
Firstlevel A  B           
Foo        a1 b1  0.871563
              b2  0.494001
           a2 b3 -0.167811
           a3 b4 -1.353409

4
যদি আপনি এটি কোনও মাল্টিআইন্ডেক্স কলাম সূচী দিয়ে ডেটাফ্রেম দিয়ে করেন তবে এটি স্তরগুলি যুক্ত করে, যা সম্ভবত বেশিরভাগ ক্ষেত্রেই গুরুত্বপূর্ণ নয়, তবে আপনি যদি অন্য কোনও কিছুর জন্য মেটাডেটার উপর নির্ভর করে থাকেন।
nnot101

23

আমি মনে করি এটি আরও সাধারণ সমাধান:

# Convert index to dataframe
old_idx = df.index.to_frame()

# Insert new level at specified location
old_idx.insert(0, 'new_level_name', new_level_values)

# Convert back to MultiIndex
df.index = pandas.MultiIndex.from_frame(old_idx)

অন্যান্য উত্তরের চেয়ে কিছু সুবিধা:

  • নতুন স্তরটি কেবল শীর্ষে নয়, যে কোনও স্থানে যুক্ত করা যেতে পারে।
  • এটি সূচকে নিখুঁতভাবে ম্যানিপুলেশন এবং কনটেনটেশন ট্রিকের মতো ডেটা ম্যানিপুলেট করার প্রয়োজন হয় না।
  • এটি একটি মধ্যবর্তী পদক্ষেপ হিসাবে একটি কলাম যুক্ত করার প্রয়োজন হয় না, যা বহু-স্তরের কলাম সূচকগুলি ভেঙে দিতে পারে।

2

আমি সিএক্সরোডার্স জবাবের বাইরে একটি সামান্য ফাংশন করেছি , যা কোনও তথ্য ফ্রেম বা সিরিজ থেকে পৃথক করে কোনও সূচীতে খাঁটিভাবে কাজ করে তাই আইএমএইচও সবচেয়ে ভাল সমাধান।

আমি যুক্ত করেছিলাম একটি ফিক্স: 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)  # sometimes new index level names are invented when converting to a df,
    new_index_names.insert(loc, name)        # here the original names are reconstructed
    new_index = pd.MultiIndex.from_frame(old_index_df, names=new_index_names)
    return new_index

এটি নিম্নলিখিত ইউনিটেস্ট কোডটি পাস করেছে:

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")

        # it does not invent new index names where there are missing
        self.assertEqual([None, None], i1.names)

        # the new level values are added
        self.assertTrue(np.all(i1.get_level_values(0) == "foo"))
        self.assertTrue(np.all(i1.get_level_values(1) == df.index))

        # it does not invent new index names where there are missing
        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)

        # the new level values are added
        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))

        # df.index = i3
        # print()
        # print(df)

0

পান্ডাস দিয়ে স্ক্র্যাচ থেকে এটিকে কীভাবে তৈরি করবেন ?

df.index = p.MultiIndex.from_tuples(
    [(nl, A, B) for nl, (A, B) in
        zip(['Foo'] * len(df), df.index)],
    names=['FirstLevel', 'A', 'B'])

একইভাবে সিএক্সরোডারের দ্রবণের ক্ষেত্রেও এটি একটি নমনীয় পদ্ধতি এবং ডেটাফ্রেমের জন্য অন্তর্নিহিত অ্যারেটি সংশোধন করা এড়িয়ে যায়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.