pandasのSeries
やDataFrame
のインデックスで使用されているIndex
の基本について解説します。
Contents
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にて公開しています。参考にしていただければと思います。