404 Not Found

404 Not Found


nginx

インデックスシステム【Pandasの核心機能】

Index(インデックス)は、Pandasの中で最も過小評価されている一方で、最も強力な機能です。Indexは単なる「行ラベル」ではなく、データアラインメントの中核となる仕組みであり、SeriesやDataFrameが算術演算でやり取りする際に、値を自動的に照合する「キー」として機能します。Indexを理解すれば、なぜPandasがNumPyよりもデータ分析に適しているのかが分かるでしょう。本セクションでは、Indexの本質、種類、そしてアラインメントの仕組みについて深く掘り下げます。

注意: 以下のコードは、ローカルのPython環境で実行する必要があります。

1. 学習内容



2. アリスの2ヶ月間売上アラインメント問題

(1) 課題:行が揃っていない問題

アリスのコーヒーショップは、1月と2月で営業日が異なります(1月は31日、2月は28日)。また、休業日もあります。彼女は2ヶ月分のデータを統合して比較する必要があります:

PYTHON
import pandas as pd

# 1月の売上(一部休業日あり)
jan = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350, 'Thu': 410, 'Fri': 390})
# 2月の売上(異なる曜日、月・火は休業)
feb = pd.Series({'Wed': 370, 'Thu': 420, 'Fri': 400, 'Sat': 550, 'Sun': 510})

# NumPy方式:位置ごとに足し算してしまう — 間違い!
# Pandas:インデックスラベルで自動的にアラインメント
total = jan + feb
print(total)
# Fri    790.0   ← 一致!
# Mon      NaN   ← janにのみ存在
# Sat      NaN   ← febにのみ存在
# Sun      NaN   ← febにのみ存在
# Thu    830.0   ← 一致!
# Tue      NaN   ← janにのみ存在
# Wed    720.0   ← 一致!
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(2) 解決策:自動インデックスアラインメント

Pandasが算術演算を実行する際、インデックスラベルに基づいて自動的にアラインメントを行います。一致するラベルの値同士が加算され、一致しないラベルはNaNで埋められます。データの行を手動で照合する必要は一切ありません。

▶ サンプル:アラインメント操作とfill_value(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

jan = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350, 'Thu': 410, 'Fri': 390})
feb = pd.Series({'Wed': 370, 'Thu': 420, 'Fri': 400, 'Sat': 550, 'Sun': 510})

# 欠損値を0で埋めて、よりクリーンに比較
total = jan.add(feb, fill_value=0)
print(total.sort_index())
# Fri    790.0
# Mon    320.0   ← janのみ、feb=0
# Sat    550.0   ← febのみ、jan=0
# Sun    510.0   ← febのみ、jan=0
# Thu    830.0
# Tue    280.0   ← janのみ、feb=0
# Wed    720.0
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(3) メリット:インデックスアラインメントは微妙なバグを防ぐ

NumPyを使って位置で加算した場合、jan[0] + feb[0]320 + 370 = 690 となりますが、月曜日と水曜日はまったく同じ日ではありません!インデックスアラインメントを使えば、エラーの温床となる「位置による照合」から解放されます。



3. Indexの本質と種類

(1) Indexは通常の配列ではない

Indexは、ラベルベースのインデックス指定とアラインメントのために設計された、不変のndarrayに似たオブジェクトです。主な特徴は以下の通りです:

100%
graph TB
    IDX["Index(基底)"] --> RI["RangeIndex<br/>自動生成される 0,1,2,..."]
    IDX --> DI["DatetimeIndex<br/>時間ベースのラベル"]
    IDX --> CI["CategoricalIndex<br/>有限のカテゴリ集合"]
    IDX --> MI["MultiIndex<br/>階層的なラベル"]
    IDX --> GI["汎用Index<br/>任意のラベル"]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(2) Indexの種類の比較

種類 作成方法 典型的なユースケース 特殊な機能
RangeIndex デフォルト インデックスを指定しない場合 メモリ効率が良い
Index 手動で指定 文字列/数値ラベル 汎用的
DatetimeIndex pd.date_range 時系列データ 頻度/オフセット/リサンプリング
CategoricalIndex dtype='category' 有限のカテゴリ 順序付き/順序なしカテゴリ
MultiIndex from_tuples/from_product 階層データ 複数レベルの選択

▶ サンプル:Indexの種類の確認(難易度 ⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

# RangeIndex(デフォルト)
s1 = pd.Series([1, 2, 3])
print(type(s1.index))   # <class 'pandas.core.indexes.range.RangeIndex'>

# 汎用Index(文字列ラベル)
s2 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
print(type(s2.index))   # <class 'pandas.core.indexes.base.Index'>

# DatetimeIndex
dates = pd.date_range('2026-01-01', periods=5)
s3 = pd.Series([100, 200, 150, 300, 250], index=dates)
print(type(s3.index))   # <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。


4. set_index と reset_index

(1) set_index:列を行ラベルにする

▶ サンプル:set_indexの使い方(難易度 ⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

df = pd.DataFrame({
    'product': ['Coffee', 'Tea', 'Juice'],
    'price': [4.50, 3.80, 5.20],
    'category': ['Hot', 'Hot', 'Cold']
})

# productをインデックスに設定
df_indexed = df.set_index('product')
print(df_indexed)
#          price category
# product
# Coffee   4.50      Hot
# Tea      3.80      Hot
# Juice    5.20     Cold

print(df_indexed.loc['Coffee', 'price'])  # 4.5

# 設定後に列を削除(デフォルトはTrue)
# 列を残す場合:drop=False
df_keep = df.set_index('product', drop=False)
print(df_keep.columns)  # 'product' がまだ残っている
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(2) reset_index:行ラベルを列に戻す

▶ サンプル:reset_indexの使い方(難易度 ⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

df = pd.DataFrame({
    'price': [4.50, 3.80, 5.20]
}, index=['Coffee', 'Tea', 'Juice'])

# インデックスを列に戻す
df_reset = df.reset_index()
print(df_reset)
#    index  price
# 0  Coffee   4.50
# 1     Tea   3.80
# 2    Juice   5.20

# 新しい列に名前を付ける
df_reset2 = df.reset_index(names='product')
print(df_reset2.columns)  # Index(['product', 'price'])

# インデックスを完全に破棄(列として残さない)
df_drop = df.reset_index(drop=True)
print(df_drop)
#    price
# 0   4.50
# 1   3.80
# 2   5.20
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(3) set_index と reset_index の比較

操作 set_index reset_index
方向 列 → 行ラベル 行ラベル → 列
元の列 デフォルトで削除(drop=True) 新しい列として保持
デフォルトのインデックス なし(列を指定する必要がある) RangeIndex(0,1,2,...)
インプレース変更 デフォルトでは行わない(inplace=False) デフォルトでは行わない


5. インデックスアラインメントの詳細

(1) アラインメントのルール

2つのPandasオブジェクト(SeriesまたはDataFrame)を演算で組み合わせる場合:

  1. 両方のIndexの和集合が計算されます
  2. 一致するラベルに対して演算が行われます
  3. 一致しないラベルはNaNで埋められます
100%
graph LR
    A["Series A<br/>{a:1, b:2, c:3}"] --> ADD["A + B"]
    B["Series B<br/>{b:20, c:30, d:40}"] --> ADD
    ADD --> R["結果<br/>{a:NaN, b:22, c:33, d:NaN}"]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

▶ サンプル:DataFrameのアラインメント(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['x', 'y', 'z'])
df2 = pd.DataFrame({'A': [10, 20, 30]}, index=['y', 'z', 'w'])

result = df1 + df2
print(result)
#       A
# w   NaN
# x   NaN
# y  22.0
# z  33.0

# fill_valueを指定した場合
result2 = df1.add(df2, fill_value=0)
print(result2)
#       A
# w  30.0
# x   1.0
# y  22.0
# z  33.0
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

ヒント: インデックスアラインメントは、+, -, *, / 演算子だけでなく、add/sub/mul/div などのメソッドでも発生します。fill_value パラメータは、ラベルが欠けている側にのみ適用されます。両側に欠けている場合、結果は依然としてNaNになります。



6. reindex と align

(1) reindex:インデックスを再構成する

▶ サンプル:reindexの使い方(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

s = pd.Series([320, 280, 350], index=['Mon', 'Tue', 'Wed'])

# 新しいラベルを含むようにインデックスを再構成(NaNで埋める)
s_full = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
print(s_full)
# Mon    320.0
# Tue    280.0
# Wed    350.0
# Thu      NaN
# Fri      NaN

# 欠損値を埋める
s_filled = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], fill_value=0)
print(s_filled)

# 前方埋め(前の値を使用)
s_ffill = s.reindex(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], method='ffill')
print(s_ffill)
# ThuにはWedの値(350)が入る
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(2) align:2つのSeriesを同時にアラインメントする

▶ サンプル:alignメソッド(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

s1 = pd.Series({'a': 1, 'b': 2, 'c': 3})
s2 = pd.Series({'b': 20, 'c': 30, 'd': 40})

# 両方をインデックスの和集合にアラインメント
s1_aligned, s2_aligned = s1.align(s2)
print(s1_aligned)
# a    1.0
# b    2.0
# c    3.0
# d    NaN

print(s2_aligned)
# a     NaN
# b    20.0
# c    30.0
# d    40.0

# fill_valueを指定してアラインメント
s1_f, s2_f = s1.align(s2, fill_value=0)
print(s1_f)
# a    1
# b    2
# c    3
# d    0
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

(3) reindex と align の比較

メソッド 目的 ユースケース
reindex 単一のオブジェクトを新しいインデックスに再構成する インデックスの拡張や並べ替え
align 2つのオブジェクトを同時にアラインメントする 2つのオブジェクトを互いに整合させる


7. よく使うIndexのプロパティとメソッド

(1) クイックリファレンス

プロパティ/メソッド 説明 結果の例
idx.is_unique すべてのラベルが一意かどうか True / False
idx.is_monotonic_increasing ラベルが単調増加かどうか True / False
idx.has_duplicates 重複が存在するかどうか True / False
idx.nunique() 一意な値の数 7
idx.duplicated() 重複のブールマスク ブール配列
idx.drop_duplicates() 重複を削除 新しいIndex

▶ サンプル:Indexプロパティの確認(難易度 ⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd

idx1 = pd.Index(['a', 'b', 'c', 'd'])
idx2 = pd.Index(['a', 'b', 'b', 'c'])

print(idx1.is_unique)       # True
print(idx2.is_unique)       # False
print(idx2.has_duplicates)  # True
print(idx1.nunique())       # 4
print(idx2.duplicated())    # [False, False, True, False]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。


8. 総合サンプル:月次売上データのアラインメントと再構成

▶ サンプル:2ヶ月間の売上アラインメントワークフロー(難易度 ⭐⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。
PYTHON
import pandas as pd
import numpy as np

# ============================================
# 総合サンプル:Indexを使った月次売上データの
# アラインメントと再構成
# ============================================

# 1. 2ヶ月分の日次売上(異なる日付)
jan = pd.Series({
    '2026-01-06': 320, '2026-01-07': 280, '2026-01-08': 350,
    '2026-01-09': 410, '2026-01-10': 390
}, name='jan_sales')
feb = pd.Series({
    '2026-02-04': 370, '2026-02-05': 420, '2026-02-06': 400,
    '2026-02-07': 550
}, name='feb_sales')

# 2. インデックスの情報
print("=== インデックス分析 ===")
print(f"1月の一意性: {jan.index.is_unique}")    # True
print(f"2月の一意性: {feb.index.is_unique}")    # True

# 3. 両月を共通フォーマットにアラインメント
jan_a, feb_a = jan.align(feb, fill_value=0)
print(f"\n=== アラインメント後のデータ ===")
comparison = pd.DataFrame({'jan': jan_a, 'feb': feb_a})
print(comparison)

# 4. DataFrameにインデックスを設定してラベルベースでアクセス
df = pd.DataFrame({
    'product': ['Latte', 'Cappuccino', 'Espresso', 'Mocha', 'Americano'],
    'price': [5.50, 4.80, 3.50, 5.20, 3.00],
    'category': ['Specialty', 'Specialty', 'Classic', 'Specialty', 'Classic']
})
print(f"\n=== カテゴリ別の商品 ===")
df_cat = df.set_index('category')
print(df_cat.loc['Specialty', ['product', 'price']])

# 5. すべての曜日が揃うようにインデックスを再構成
weekday_sales = pd.Series(
    [320, 280, 350, 410, 390],
    index=['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
)
full_week = weekday_sales.reindex(
    ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    fill_value=0
)
print(f"\n=== 1週間すべての売上 ===")
print(full_week)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値はpandasのバージョンによって若干異なる場合があります。

❓ よくある質問

Q Indexに重複するラベルを持たせることはできますか?
A できます。Pandasは重複するIndexラベルを許可しますが、重複ラベルにアクセスすると複数の値(スカラーではなくSeries)が返され、パフォーマンスも低下します。一意性の確認には s.index.is_unique を使用してください。可能な限りIndexを一意に保つことがベストプラクティスです。
Q set_indexでデータは失われますか?
A デフォルトでは、drop=Trueにより列がDataFrameから削除され、インデックスに変換されます。列を残したい場合は、df.set_index('col', drop=False) を使用してください。インデックスの情報は、reset_indexでいつでも列に戻すことができます。
Q reindexとlocの違いは何ですか?
A reindexは新しいラベルを導入できます(fill_valueで埋められます)が、locは既存のラベルにしかアクセスできません(存在しないラベルにアクセスするとKeyErrorが発生します)。reindexの目的は「インデックスを指定した形式に再構成すること」であり、locの目的は「ラベルでデータを選択すること」です。
Q CategoricalIndexはいつ使うべきですか?
A ラベルが有限のカテゴリ集合(曜日、月、州名など)から来る場合、CategoricalIndexはメモリを節約し、ラベルのドメインを強制します。たとえば、reindexで1週間の7日間すべてを生成したい場合にCategoricalIndexを使用します。
Q Indexが不変なら、どうやって変更するのですか?
A Indexオブジェクト自体は不変ですが、df.index = new_index で完全に置き換えるか、df.rename(index=...) でラベルの名前を変更できます。Indexの個々の要素に代入することはできません。
Q reset_indexのdropパラメータは何をするのですか?
A drop=Trueの場合、元のインデックスは破棄され(列として保持されず)、クリーンなRangeIndexが得られます。drop=False(デフォルト)の場合、元のインデックスは通常の列として復元されます。よくあるユースケースとして、groupbyの後に reset_index(drop=True) を呼び出して、グループ化キーをクリアする使い方があります。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):5つの都市の人口データを持つSeriesを作成してください。DataFrameに対してset_indexとreset_indexを使い、列とインデックスの間で変換を行い、インデックスがどのように変化するか観察してください。
  2. 中級(難易度 ⭐⭐):部分的に重複するインデックスを持つ2つのSeriesを作成してください。+ 演算子と add(fill_value=0) の両方を使って加算し、その違いを比較してください。その後、alignメソッドを使って両方のSeriesをアラインメントしてください。
  3. 挑戦(難易度 ⭐⭐⭐):DatetimeIndexを使って2ヶ月分(1月と2月、日付は異なる)の売上データを作成してください。reindexを使って両月のすべての日付を埋め(欠損は0で埋める)、2ヶ月間の前日比成長率を計算してください。

← 前へ:DataFrameのコア · 次へ:データ型 →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%