0Pricing
Pandas & NumPy Academy · レッスン

MultiIndexからのデータ選択

タプル、スライス、pd.IndexSliceヘルパーを使った.locで、外側と内側のインデックスレベルからデータを取得します。

「MultiIndexからのデータ選択」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

階層データを操作する

MultiIndexを用意したら、データの一部を効率的に取得する方法が必要です。Pandasには、そのための3つのツールがあります。正確なラベル選択には.locとタプル、レベルをまたぐ範囲選択にはslice()とpd.IndexSlice、特定のレベル値で断面を選択するには.xs()を使います。これらのアクセスパターンを習得することで、階層インデックスの能力を十分に活用できるようになります。

import pandas as pd
import numpy as np

# Setup: GDP data by country and year
df_flat = pd.DataFrame({
    'country': ['USA','USA','USA','UK','UK','UK','DE','DE','DE'],
    'year': [2021, 2022, 2023, 2021, 2022, 2023, 2021, 2022, 2023],
    'gdp_bn': [23000, 25000, 26000, 3000, 3100, 3200, 4100, 4200, 4350]
})
df = df_flat.set_index(['country', 'year']).sort_index()
print(df)

外側のレベルを.locで選択する

外側のレベルのラベルを1つ.loc[]に渡すと、そのグループのすべての行を取得できます。2レベルのMultiIndex(国、年)でdf.loc['USA']を実行すると、USAのすべての行が返され、内側のインデックス(年)だけが残ったDataFrameになります。この動作はレベルの削除と呼ばれます。外側のレベルで特定の値を選択すると、Pandasは返されるオブジェクトのインデックスからそのレベルを削除します。

import pandas as pd

df_flat = pd.DataFrame({
    'country': ['USA','USA','USA','UK','UK','UK'],
    'year': [2021, 2022, 2023, 2021, 2022, 2023],
    'gdp_bn': [23000, 25000, 26000, 3000, 3100, 3200]
})
df = df_flat.set_index(['country', 'year']).sort_index()

# Select all USA rows
usa = df.loc['USA']
print('All USA rows:')
print(usa)
print('\nRemaining index type:', usa.index.name)

特定のタプルを.locで選択する

両方のインデックスレベルで識別される1行を取得するには、タプルを.loc[]に渡します。df.loc[('USA', 2022)]のように記述します。これにより、その(外側、内側)のラベルの組み合わせに完全に一致するSeriesが返されます(列が1つの場合はスカラーになります)。SeriesではなくDataFrameを取得したい場合は、タプルをリストに入れてdf.loc[[('USA', 2022)]]のように渡す必要があります。

import pandas as pd

df_flat = pd.DataFrame({
    'country': ['USA','USA','USA','UK','UK','UK'],
    'year': [2021, 2022, 2023, 2021, 2022, 2023],
    'gdp_bn': [23000, 25000, 26000, 3000, 3100, 3200],
    'cpi': [3.2, 5.1, 4.8, 2.5, 3.4, 3.0]
})
df = df_flat.set_index(['country', 'year']).sort_index()

# Single row as Series
print('USA 2022 (Series):')
print(df.loc[('USA', 2022)])

# Single row as DataFrame
print('\nUSA 2022 (DataFrame):')
print(df.loc[[('USA', 2022)]])

タプルのリストで複数の行を選択する

複数の特定の行を一度に選択するには、タプルのリストを.loc[]に渡します。これは、複合キーで識別される連続していない行の一部を取得する場合に便利です。たとえば、ドイツを除き、USAとUKの2022年のデータを選択できます。結果として返されるDataFrameでは、MultiIndexが維持されます。

import pandas as pd

df_flat = pd.DataFrame({
    'country': ['USA','USA','UK','UK','DE','DE'],
    'year': [2022, 2023, 2022, 2023, 2022, 2023],
    'gdp_bn': [25000, 26000, 3100, 3200, 4200, 4350]
})
df = df_flat.set_index(['country', 'year']).sort_index()

# Select specific (country, year) combinations
subset = df.loc[[('USA', 2022), ('UK', 2023), ('DE', 2022)]]
print(subset)

pd.IndexSliceでスライスする

pd.IndexSlice(一般的にidxという別名で使われます)を使うと、冗長なタプルスライスを手動で構築せずに、MultiIndexの各レベルに対する範囲スライスを記述できます。構文はdf.loc[idx[outer_slice, inner_slice], column_slice]です。たとえば、df.loc[idx['UK':'USA', 2022:2023], :]は、外側のレベルがUKからUSAまで、内側のレベルが2022年から2023年までのすべての行を選択します。これを正しく動作させるには、インデックスがソートされている必要があります。

import pandas as pd
import numpy as np

years = [2021, 2022, 2023]
countries = ['DE', 'UK', 'USA']
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'gdp': np.random.randint(3000, 26000, 9)}, index=mi)

idx = pd.IndexSlice

# Select UK and USA for years 2022 and 2023
subset = df.loc[idx['UK':'USA', 2022:2023], :]
print(subset)

.xs()で断面にアクセスする

df.xs(key, level=)は、他のレベルにどのような値が入っているかにかかわらず、特定のレベルが指定した値と等しいすべての行を選択します。外側のレベルから順に指定する必要がある.locとは異なり、.xsではレベル名を使って任意のレベルに直接アクセスできます。たとえば、df.xs(2022, level='year')は、'USA'、'UK'、'DE'を指定しなくても、すべての国の2022年の行を返します。

import pandas as pd
import numpy as np

countries = ['DE', 'UK', 'USA']
years = [2021, 2022, 2023]
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'gdp': [4100,4200,4350, 3000,3100,3200, 23000,25000,26000]}, index=mi)

# All countries for year 2022 (inner level)
print('All data for year 2022:')
print(df.xs(2022, level='year'))

# All years for UK (outer level)
print('\nAll years for UK:')
print(df.xs('UK', level='country'))

MultiIndexの列にアクセスする

DataFrameの列にMultiIndexがある場合は、タプルを使って特定の列にアクセスします。df[('revenue', 'Q1')]のように記述します。外側のレベルに属するすべての列(たとえば、revenueに属するすべての列)を選択するには、df['revenue']を使います。これにより、その外側のキーの下にある内側のレベルの列がすべて含まれるDataFrameが返されます。.locと組み合わせれば、pd.IndexSliceのパターンを列のMultiIndexにも使用できます。

import pandas as pd
import numpy as np

metrics = ['revenue', 'cost']
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
cols = pd.MultiIndex.from_product([metrics, quarters], names=['metric', 'quarter'])
df = pd.DataFrame(
    np.random.randint(50, 200, (3, 8)),
    columns=cols,
    index=['USA', 'UK', 'DE']
)

# Access all revenue columns
print('Revenue columns:')
print(df['revenue'])

# Access a specific cell
print('\nUSA revenue Q1:', df.loc['USA', ('revenue', 'Q1')])

すべての外側キーに対して内側のレベルを選択する

すべての外側レベルの値について、内側レベルの値を1つ選択するには、外側のレベルにslice(None)を指定して.locと組み合わせます。df.loc[(slice(None), 2022), :]と記述すると、すべての国の2022年の行が選択されます。pd.IndexSliceを使った書き方のほうが読みやすく、df.loc[idx[:, 2022], :]と記述できます。このパターンは、特定の時点におけるすべてのエンティティのスナップショットを取得したい場合によく必要になります。

import pandas as pd
import numpy as np

countries = ['DE', 'UK', 'USA']
years = [2021, 2022, 2023]
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({'gdp': [4100,4200,4350, 3000,3100,3200, 23000,25000,26000]}, index=mi)

idx = pd.IndexSlice

# All countries for year 2022 (using IndexSlice)
all_2022 = df.loc[idx[:, 2022], :]
print('All countries in 2022:')
print(all_2022)

MultiIndex選択でよくある落とし穴

よくある落とし穴は3つあります。1) ソートされていないインデックス:ソートされていないMultiIndexをスライスすると、UnsortedIndexErrorが発生するか、誤った結果が返されます。必ず最初にsort_index()を呼び出してください。2) キーとしてタプルを使った場合のKeyError:タプルを.loc[]で囲まずに渡すと、Pythonはそれを位置インデックスとして解釈します。MultiIndexへのラベルベースのアクセスには、必ず.locを使用してください。3) レベルの不一致:groupbyの後では、MultiIndexのレベル名が想定と異なる場合があります。スライスする前にdf.index.namesを確認してください。

import pandas as pd

# Unsorted MultiIndex slicing
tuples = [('B', 2), ('A', 1), ('B', 1), ('A', 2)]
mi = pd.MultiIndex.from_tuples(tuples, names=['letter', 'num'])
df = pd.DataFrame({'value': [10, 20, 30, 40]}, index=mi)

print('Is sorted:', df.index.is_monotonic_increasing)
# Sort before slicing
df = df.sort_index()
print('After sort:', df.index.is_monotonic_increasing)

idx = pd.IndexSlice
print('\nSlice A:')
print(df.loc[idx['A', :], :])

実践例:四半期レポート

具体的な使用例として、(地域、四半期)をインデックスとする売上データから、年末レポート用にすべての地域の第4四半期を抽出するとします。.xs('Q4', level='quarter')を使えば、この断面を1回の呼び出しで取得できます。その後、.sum()で合計を計算します。この「groupby集計 → MultiIndexの結果 → 断面の抽出」というパターンは、業務レポートのパイプラインで非常によく使われます。

import pandas as pd
import numpy as np

regions = ['North', 'South', 'East', 'West']
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
mi = pd.MultiIndex.from_product([regions, quarters], names=['region', 'quarter'])

np.random.seed(42)
df = pd.DataFrame({
    'sales': np.random.randint(200, 500, 16),
    'units': np.random.randint(50, 150, 16)
}, index=mi)

# Extract Q4 performance across all regions
q4 = df.xs('Q4', level='quarter')
print('Q4 Results by Region:')
print(q4)
print('\nQ4 Total Sales:', q4['sales'].sum())

MultiIndexの選択と列を組み合わせる

.loc[row_indexer, column_list]を使うと、行と列を同時に選択できます。MultiIndexでは、行インデクサーにタプル、タプルのリスト、またはIndexSliceを指定し、列インデクサーには列名または列名のリストを指定します。これにより、階層化されたDataFrameから、必要な範囲だけを持つ正確な長方形のサブテーブルを1つの式で抽出できます。

import pandas as pd
import numpy as np

countries = ['DE', 'UK', 'USA']
years = [2021, 2022, 2023]
mi = pd.MultiIndex.from_product([countries, years], names=['country', 'year'])
df = pd.DataFrame({
    'gdp': [4100,4200,4350, 3000,3100,3200, 23000,25000,26000],
    'inflation': [1.5, 2.1, 2.8, 2.0, 3.4, 2.9, 3.2, 5.1, 4.8],
    'unemployment': [5.0, 4.8, 4.5, 4.5, 4.2, 4.0, 3.8, 3.5, 3.3]
}, index=mi)

idx = pd.IndexSlice

# UK and USA, years 2022-2023, only gdp and inflation
result = df.loc[idx['UK':'USA', 2022:2023], ['gdp', 'inflation']]
print(result)

理解度チェック

このレッスンで学んだMultiIndexの選択について理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、特定の(外側、内側)のラベルの組み合わせを選択するために.locとタプルを使うこと、任意のレベルをまたぐ範囲スライスにはpd.IndexSliceを使うこと、外側のキーに関係なく任意のレベルの断面を抽出するには.xs()を使うことを学びました。UnsortedIndexErrorを避けるため、必ず最初にインデックスをソートしてください。次は、インデックスのアラインメントと再インデックス化、つまりPandasが2つのDataFrameを共通のインデックスにそろえる方法を学びます。

よくある質問

「MultiIndexからのデータ選択」レッスンは無料ですか?

はい。「MultiIndexからのデータ選択」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「MultiIndexからのデータ選択」で何を学びますか?

タプル、スライス、pd.IndexSliceヘルパーを使った.locで、外側と内側のインデックスレベルからデータを取得します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「MultiIndexからのデータ選択」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. MultiIndexの作成
  2. MultiIndexからのデータ選択
  3. インデックスの整列と再インデックス
  4. ソート済みインデックスのパフォーマンス上の利点
← Pandas & NumPy Academyに戻る