【pandas】Indexの基本

pandasのSeriesやDataFrameのインデックスで使用されているIndexの基本について解説します。
目次
pandasのIndex
pandasでよく使用されるSeriesとDataFrameでは、要素のアクセスにインデックスを使用します。pandasでは、このインデックスはIndexクラスとして実装されています。Indexは、値とそのデータ型(dtype)を持っています。
以下のSeriesとDataFrameの作成例で見てみましょう。
import numpy as np
import pandas as pd
# Series
ser = pd.Series([1, 2, 3], index=["A", "B", "C"])
print(ser)
print(ser.index)
print("\n")
# DataFrame
df = pd.DataFrame(
np.arange(9).reshape((3, 3)), index=[1, 2, 3], columns=["A", "B", "C"]
)
print(df)
print(df.index)
print(df.columns)【実行結果】 A 1 B 2 C 3 dtype: int64 Index(['A', 'B', 'C'], dtype='object') A B C 1 0 1 2 2 3 4 5 3 6 7 8 Index([1, 2, 3], dtype='int64') Index(['A', 'B', 'C'], dtype='object')
上記例でindexやcolumnsを表示しいますが、型がIndexオブジェクトとなっていることが分かります。また、dtypeには、インデックス値の型が示されています。
このIndexクラスのオブジェクトは、それ自体に特徴的な部分があります。以降では、Indexオブジェクトの操作や特徴について説明していきます。
Indexオブジェクトの操作の基本
Indexオブジェクトの作成方法
Indexオブジェクトは、以下のようにPythonのリストを受け取って生成することできます。
import pandas as pd ind = pd.Index([1, 2, 3]) print(ind) ind = pd.Index(["A", "B", "C"]) print(ind)
【実行結果】 Index([1, 2, 3], dtype='int64') Index(['A', 'B', 'C'], dtype='object')
Indexオブジェクトに対するアクセス
Indexオブジェクトの要素へは、Pythonのリスト等と同じようにアクセスすることが可能です。
import pandas as pd ind = pd.Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # 要素へのアクセス print(ind[1]) # スライスによるアクセス print(ind[1:9:2]) # 各種情報へのアクセス print(ind.size) print(ind.shape) print(ind.ndim) print(ind.dtype)
【実行結果】 2 Index([2, 4, 6, 8], dtype='int64') 10 (10,) 1 int64
上記例のように、位置を指定したり、スライス記法によって一部を抽出することができます。また、NumPyの配列(ndarray)のように、size、shape、ndim、dtypeといった属性値にアクセスができます。
Indexオブジェクトはイミュータブル(immutable)
Indexオブジェクトは、「イミュータブル(immutable)」で変更ができないという点に特徴があります。
インデックスはデータを識別するために非常に重要な情報です。例えば、簡単にインデックスが変更されてしまうと、データフレームの行の識別が困難になり、誤ったデータ操作や分析結果を引き起こす原因となる可能性があります。pandasにおいてインデックスを表現するIndexオブジェクトがイミュータブル(immutable)であることで安全性が向上するため、この性質は非常に重要な特性です。
Indexオブジェクトがイミュータブル(immutable)であるということを簡単な例で見てみましょう。
import pandas as pd ind = pd.Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # Indexオブジェクトはイミュータブル(immutable)なため要素の変更はできない ind[0] = 10
【実行結果例】 TypeError: Index does not support mutable operations
上記のように、インデックス要素の値を変更しようとすると、TypeErrorとなります。これは、変更を行うような操作はサポートしていないということを示すエラーとなっています。
Indexオブジェクトの集合演算
pandasのIndexオブジェクトは、複数データの結合といった操作を容易にできるようにするために集合演算ができるようになっています。Python組み込みの集合であるsetと同じように演算をすることが可能です。
なお、Python組み込みの集合(set)の演算については「集合(set)の演算と包含関係の判定」でまとめていますので興味があれば参考にしてください。
import pandas as pd
indA = pd.Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
indB = pd.Index([6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
print(f"積集合 A&B: {indA.intersection(indB)}")
print(f"和集合 A|B: {indA.union(indB)}")
print(f"差集合 A-B: {indA.difference(indB)}")
print(f"差集合 B-A: {indB.difference(indA)}")
print(f"排他的論理和 A^B: {indA.symmetric_difference(indB)}")【実行結果】 積集合 A&B: Index([6, 7, 8, 9, 10], dtype='int64') 和集合 A|B: Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], dtype='int64') 差集合 A-B: Index([1, 2, 3, 4, 5], dtype='int64') 差集合 B-A: Index([11, 12, 13, 14, 15], dtype='int64') 排他的論理和 A^B: Index([1, 2, 3, 4, 5, 11, 12, 13, 14, 15], dtype='int64')
上記例のように、積集合(intersection)、和集合(union)、差集合(difference)、排他的論理和(symmetric_difference)といった組み込みの集合(set)と同じメソッドを使用することができます。
様々なタイプのインデックス
上記では、一般的でシンプルなケースでのIndexオブジェクトの話を紹介しました。pandasでは、利用ケースに特化したようなインデックスタイプも用意されているので、それらについても紹介したいと思います。
具体的には以降でMultiIndex、DatetimeIndex、PeriodIndex、CategoricalIndexについて説明します。これらの利用を検討するべきケースとしてまとめてみると以下のようになります。
| 名称 | 用途 |
|---|---|
MultiIndex | 階層的なデータ構造を扱う場合 |
DatetimeIndex | 時系列データ処理等、日時データをインデックスとして使用する場合 |
PeriodIndex | 特定の期間(月、四半期、年など)の単位で分析する場合 |
CategoricalIndex | 限られた数のカテゴリーを持つデータを扱う場合 |
これらのインデックスタイプは、特定種類のデータや特定の分析ニーズに合わせて最適化されているため、データ構造や分析の目的に応じて選択を検討することが重要です。
MultiIndex
MultiIndexは、階層的なデータ構造を扱う場合に適したインデックスです。以下のように作成して使うことができます。
import pandas as pd
# MultiIndexを作成 (from_tuples)
multi_index = pd.MultiIndex.from_tuples(
[("A", 1), ("A", 2), ("B", 1), ("B", 2), ("B", 3)],
names=["Level 1", "Level 2"],
)
print(multi_index, "\n")
# データフレームの作成
df_multi = pd.DataFrame(
data=[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]],
index=multi_index,
columns=["col1", "col2", "col3"],
)
print(df_multi)【実行結果】
MultiIndex([('A', 1),
('A', 2),
('B', 1),
('B', 2),
('B', 3)],
names=['Level 1', 'Level 2'])
col1 col2 col3
Level 1 Level 2
A 1 1 2 3
2 4 5 6
B 1 7 8 9
2 10 11 12
3 13 14 15上記例のように、MultiIndexを作る場合には、MultiIndexクラスのfrom_tuplesメソッドを使用することができます。引数にはタプルで各行に対するインデックスの情報を列挙したリストを指定しています。タプルの1要素目がLevel1、2要素目がLevel2、…というように該当します。また、names引数にリストで各レベルの名称を指定します。
作成されるインデックスはMultiIndexオブジェクトとなります。データフレームもあわせて作成して表示していますが、階層構造を持ったインデックスとなっていることが分かるかと思います。
なお、同様のことをfrom_arraysメソッドを使用して作成することも可能です。
# MultiIndexを作成 (from_arrays)
multi_index = pd.MultiIndex.from_arrays(
[["A", "A", "B", "B", "B"], [1, 2, 1, 2, 3]],
names=["Level 1", "Level 2"],
)上記を見ていただけばわかるように、from_tuplesの場合とインデックスに関する情報の渡し方が異なっています。from_tuplesでは各行のインデックス情報のリストを渡していましたが、from_arraysでは、各レベル毎の要素を含むリストを渡しています。
from_tuplesとfrom_arraysいずれでもMultiIndexは作成できますので、持っているデータ形式や開発者の使いやすさで決めてもらえばよいかと思います。
DatetimeIndex
DatetimeIndexは、時系列データ処理等、日時データをインデックスとして使用する場合に適したインデックスです。以下のように作成して使うことができます。
import pandas as pd
# 時間単位のDatetimeIndexを作成
date_index_h = pd.date_range(
"2024-01-01",
periods=5,
freq="H",
)
print(date_index_h, "\n")
# データフレームの作成
df_time_value = pd.DataFrame(
data=[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]],
index=date_index_h,
columns=["val1", "val2", "val3"],
)
print(df_time_value)【実行結果】
DatetimeIndex(['2024-01-01 00:00:00', '2024-01-01 01:00:00',
'2024-01-01 02:00:00', '2024-01-01 03:00:00',
'2024-01-01 04:00:00'],
dtype='datetime64[ns]', freq='H')
val1 val2 val3
2024-01-01 00:00:00 1 2 3
2024-01-01 01:00:00 4 5 6
2024-01-01 02:00:00 7 8 9
2024-01-01 03:00:00 10 11 12
2024-01-01 04:00:00 13 14 15上記例のようにDatetimeIndexを作成する場合には、date_range関数を使用します。引数としては、開始日時と共に、時間の数をperiodsで、時間間隔をfreqで指定します。
上記例では、"2024-01-01"、period=5、freq="H"を指定していますので、2024-01-01 00:00:00から1時間単位で5つのインデックスを作成します。なお、freqには、"T":分単位、"H":時間単位、"D":日単位等いろいろなオプションがあるので目的に合わせて調べてみてください。
作成されるインデックスはDatetimeIndexオブジェクトとなります。データフレームもあわせて作成して表示していますが、各時間に値を持つようなデータとなっています。このようなデータは、特に設備データの時系列データを表す場合などに最適です。
また、少し異なった指定方法として以下のようにstartとendを指定する方法もあります。
# 最初(start)と最後(end)を指定することも可能
# start、end、periods(時間の数)の3引数を同時に使用することはできないので注意
date_index_s_e = pd.date_range(
start="2024-01-01 00:00:00",
end="2024-01-01 04:00:00",
freq="H",
)
print(date_index_s_e)ほとんど使い方は同じで、startとendの間をfreqの時間間隔で埋めたインデックスが作成されます。なお、start、end、periodsの3引数を同時に使用することはできないので注意が必要です。
PeriodIndex
PeriodIndexは、特定の期間(月、四半期、年など)の単位で分析する場合に適したインデックスです。
DatetimeIndexに似ているかと思うかもしれませんが、DatetimeIndexが時刻に関する概念を持っているのに対して、PeriodIndexはあくまで期間を表現するためのインデックスであるという点で違いがあります。
例えば、2024-01は2024年の1月全体を指しますが、その中に日付や時刻といった考えは含まれません。このため、一定の期間単位(月単位、四半期、年単位等)で集計などの分析を行うようなデータの管理に特に適しています。
PeriodIndexは、以下のように作成して使うことができます。
import pandas as pd
# 月単位のPeriodIndexを作成
monthly_period = pd.period_range(
start="2024-01",
end="2024-12",
freq="M",
)
print(monthly_period, "\n")
# データフレームの作成
df_period = pd.DataFrame(
data=list(range(1, 13)),
index=monthly_period,
columns=["data"],
)
print(df_period)【実行結果】
PeriodIndex(['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06',
'2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12'],
dtype='period[M]')
data
2024-01 1
2024-02 2
2024-03 3
2024-04 4
2024-05 5
2024-06 6
2024-07 7
2024-08 8
2024-09 9
2024-10 10
2024-11 11
2024-12 12上記例のようにPeriodIndexを作成する場合は、period_range関数を使用します。引数としては、開始日のstart、終了日のend、時間間隔のfreqを指定します。
上記例では、start="2024-01"、end="2024-12"、freq="M"としていますので、2024年1月~12月までを月単位で作成したインデックスとなります。なお、freqは、"D":日単位、"M":月単位、"Q":四半期単位等いろいろなオプションが使用できます。freqで指定できるものは、date_rangeと似ていますが概念としては異なりますので両方に同じオプションが必ずあるとは限らない点に注意が必要です。
作成されるインデックスは、PeriodIndexオブジェクトとなります。データフレームもあわせて作成して表示していますが期間を表すようなデータとなっています。一定期間ごとの集計データを扱う場合等に最適です。
CategoricalIndex
CategoricalIndexは、限られた数のカテゴリーを持つデータを扱う場合に適したインデックスです。以下のように作成して使うことができます。
import pandas as pd
# カテゴリーで使うラベルのリスト
category_data = ["High", "Medium", "Low", "Low"]
# CategoricalIndexの作成
# categoriesに指定するものがカテゴリーとして許容するリスト
# ordered=Trueとすることで"Low"<"Medium"<"High"の順序があることを示す
category_index = pd.CategoricalIndex(
category_data,
categories=["Low", "Medium", "High"],
ordered=True,
)
print(category_index, "\n")
# データフレームの作成
df_categorical = pd.DataFrame(
data=[[70, 80, 90], [40, 50, 60], [10, 20, 30], [10, 5, 10]],
index=category_index,
columns=["col1", "col2", "col3"],
)
print(df_categorical)【実行結果】
CategoricalIndex(['High', 'Medium', 'Low', 'Low'], categories=['Low', 'Medium', 'High'], ordered=True, dtype='category')
col1 col2 col3
High 70 80 90
Medium 40 50 60
Low 10 20 30
Low 10 5 10上記例のようにCategoricalIndexを作成する場合は、CategoricalIndexクラスのオブジェクトを生成して使用します。引数で渡しているものが少しわかりにくいかもしれませんが、category_dataが実際にデータに割り当てられるインデックスのリストです。categories引数で指定しているのは、カテゴリーとして許容するリストとなっており、orderd=Trueとするとcategoriesで指定した順序性があることを示します。
上記の例でいうとカテゴリーとして許容されるのは、"Low"、"Medium"、"High"の3つで、ordered=Trueとすることで"Low"<"Medium"<"High"の順序があることを示しています。
作成されるインデックスは、CategoricalIndexオブジェクトなります。データフレームもあわせて作成して表示していますが、上からHigh、Medium、Low、Lowというカテゴリラベルが付与されたデータであると思ってもらえれば分かりやすいかと思います。このようにデータをカテゴリ分けして扱いたい場合には最適なインデックスです。
まとめ
pandasのSeriesやDataFrameのインデックスで使用されているIndexの基本について解説しました。
Indexは、SeriesとDataFrameでは、要素のアクセスする際に使用されます。Indexの作成方法やアクセス方法、演算などについて紹介をしています。また、その他の様々なインデックスの例ということでMultiIndex、DatetimeIndex、PeriodIndex、CategoricalIndexといったインデックスについても簡単に紹介しました。
Indexは、SeriesやDataFrameを適切に操作するために内容を十分に理解しておくべき事項です。ぜひ、Indexの理解を深めて、SeriesやDataFrameを適切に扱いましょう。
Indexに関する公式ドキュメントの記載はこちらを参照してください。
上記で紹介しているソースコードについてはgithubにて公開しています。参考にしていただければと思います。







