見出し画像

第2回 RangeIndex, Int64Index, Float64Index, Index, Indexが持つ便利関数

様々なIndex

前回の記事では、IndexクラスがDataFrameの行名や列名を管理していることを説明しました。一見シンプルな役割なのですが、実際には下記のような様々なIndexクラスが準備されています。Indexクラスが持つ便利な関数の一部を紹介します。

Indexクラス一覧
・Index
・RangeIndex
・Int64Index, Float64Index
・CategoricalIndex
・MultiIndex
・IntervalIndex
・DatetimeIndex, TimedeltaIndex, PeriodIndex

どうでしょう、みなさん全てのIndexクラスを知っているでしょうか?普通にpandasを使っていると、これらのIndexクラスを意識することはないでしょう。実は私も最初は全然知らないで使っていました。しかし、これらのIndexクラスは様々なデータ処理と密接に関わり、裏側で処理の実現を支えてくれているのです。そして、この裏側を理解することでより効率の良いpandasのコードをかけるようになれます。本連載では、今後、ここに表記されているIndexクラスを密接な関係のある処理と合わせて各記事で解説していきます。今回の記事では、Indexクラスの基本的な型であるRangeIndex, Int64Index, Float64Index, Indexを説明します。最後に、Indexクラスが共通にもつ便利な関数を紹介します。

RangeIndex

前回も説明しましたが、DataFrameを生成した際に行名と列名を指定しないと、自動でRangeIndexが設定されます。RangeIndexは、整数の等差数列を設定できるIndexです。(小数は設定することはできません。)

スクリーンショット 2019-10-27 11.49.23

スクリーンショット 2019-10-27 10.25.44

自動生成の場合は、0から始まり1ずつ増えていくRangeIndexが生成されますが、特定の値から始まり特定の値ずつ増えていくRangeIndexを生成することもできます。

// RangeIndexの生成。
pd.RangeIndex(start=開始の値, stop=終了条件の値, step=ステップ幅)

スクリーンショット 2019-10-27 10.42.41

さて、ここまでの説明で分かったかもしれませんが、RangeIndexは設定している行名/列名を持っているわけではありません。startとstopとstepの値を保持しているだけです。一見、不便そうに見えますが、これにはとても良い点があります。それは、データサイズが常に小さいままであるという点です。次のInt64Indexの説明後に、比較して紹介します。

Int64Index

Int64Indexは、RangeIndexと同様に整数を扱うIndexクラスです。ただし、RangeIndexと異なり、等差数列である必要がありません。また、RangeIndexと異なり、設定している行名/列名を持っています。

// Int64Indexの生成。
pd.Int64Index(data=設定する整数の列)

RangeIndexとInt64Indexのデータサイズの違い

では、RangeIndexとInt64Indexではデータサイズがどの程度異なるのでしょうか?実際に試してみましょう。

スクリーンショット 2019-10-27 12.00.37

上記のように同じ10万個の値をもつIndexでも、RangeIndexは112バイトなのに対してInt64Indexは800,032バイトものサイズになります。当然indexが持つ値が増えれば増えるほどこの差は広がっていきます。そのため、膨大な行や列をもつDataFrameを扱う際には、RangeIndexがとても役に立ちます。そのため、reset_index関数を必要に応じて行うことはとても重要なのです。

スクリーンショット 2019-10-27 12.27.43

このように、1行データが少ないのにも関わらず、RangeIndexクラスがInt64Indexクラスに変更される必要があったために、データサイズが大きくなってしまっています。reset_index関数を使えば、RangeIndexクラスに戻り、データサイズが小さくなることが分かります。

Float64Index

Float64Indexは、小数を扱うIndexクラスです。小数であること以外は、Int64Indexと同様です。

// Float64Indexの生成。
pd.Float64Index(data=設定する小数の列)

スクリーンショット 2019-10-27 12.50.49

Index

Indexクラスは、文字列を扱うIndexクラスです。文字列であること以外は、Int64Indexと同様です。

// Indexの生成。
pd.Index(data=設定する文字列の列)

スクリーンショット 2019-10-27 13.17.45


Indexクラスが持つ便利な関数

Indexクラスは便利な様々な関数を持っています。Indexクラスが関数を持っているのを結構知らない人も多いので、これを機会にぜひ知っておいてもらいです。今回の記事ではIndexクラスの種類に限らず、使う機会が多い関数を紹介します!

astype関数

astype関数は、Indexクラスの値の型を変えます。つまり同時にIndexクラスの種類も変えるということです。使うケースとしては、文字列から数値に変化させたり、文字列からカテゴリ値に変化させるケースでしょう。

// indexクラスの型を変換。
index.astype(dtype=変換する型名)

スクリーンショット 2019-10-27 14.17.12

to_XXX関数

to_XXX関数は、Indexクラスを他のデータ型に変換する関数です。PythonのlistやnumpyのndarrayやpandasのSeriesやDataFrameに変換できます。

# Pythonのlistに変換。
index.to_list()

# numpyのndarrayに変換。
index.to_numpy()

# pandasのSeriesに変換。
index.to_series()

# pandasのDataFrameに変換。
index.to_frame(name=列名)

スクリーンショット 2019-10-27 17.13.58

contains関数, isin関数

contains関数は、引数の値がindexの値内に存在するか判定する関数です。isin関数は、引数のリストの各値がindexの値内に存在するか判定する関数です。必要なデータ列が存在するのかを確認する時などに利用します。

# indexの値内に引数の値が存在するか判定。
index.contains(判定する値)

# indexの値内に引数の列の各値が存在するか判定。
index.isin(判定する値のリスト)

スクリーンショット 2019-10-27 14.07.19

difference関数, join関数, intersection関数

difference関数は、呼び出し元のindex内の値には存在し、引数のindex内の値には存在しない値を抽出します。join関数は、引数の2つのindexの値を結合する関数です。how引数に結合方式を指定することができます。intersection関数は、呼び出し元と引数のindexの値の両方に存在する値を抽出する関数です。join関数の引数howにinnerを指定した時と同じ動作をします。

これらの関数は、元々のindexが同じDataFrame間で利用することが多いです。例えば、dropnaした後のDataFrameのindexを引数に、元のDataFrameのindexを呼び出し元として、difference関数を呼び出すことで欠損値が存在するデータのindex値を取得するために利用します。

# 呼び出し元にはあり、引数には存在しないindexの値の抽出。
index.difference(比較するindex)

# 結合を行う。引数のhowは結合方式(inner, outer, left, right)を指定できます。
pd.Index.join(結合するindex1, 結合するindex2, how=結合方式)

# 呼び出し元と引数の両方に存在するIndexの値を抽出。
index.intersection(比較するindex)

スクリーンショット 2019-10-27 14.07.44

unique関数, drop_duplicates関数

unique関数は、重複しているindexの値を削除し、全て一意なindexの値を取得します。drop_duplicates関数も同様です。indexの値は、同じ値を複数設定することができますが、意図せぬ動作をすることが多く、オススメすることはできません。トラブルを防ぐために、必要に応じて対処しましょう。

スクリーンショット 2019-10-27 14.07.56


活用例:Indexを用いたモデルによるデータ補間処理

DataFrame上にあるカラムの欠損値を、欠損していないその他のカラムを用いた機械学習モデルの予測から補間処理をしたい時、皆さんはどのように書いているでしょうか?もしかして、元のDataFrameをコピーしてしまうような処理を多用していないでしょうか?

色々な実現方法がありますが、元のDataFrameをコピーしてしまうと大抵の場合パフォーマンスが悪くなります。しかし、もしあなたがIndexクラスをうまく活用できるのであれば、そのようなコードを書くこと必要ありません。

それでは、Indexクラスをうまく活用したモデルによる補間処理のコードを確認してみましょう。下記は、カラム'd'の線形モデルによるデータ補完を行なっているコードです。

スクリーンショット 2019-12-15 15.17.04

上記のコードのように、欠損のある行名(na_index)を取得した後、difference関数を用いることで、欠損のない行名(not_na_index)を簡単に取得することができます。このnot_na_indexとna_indexがあれば、補間モデルの学習と適用に利用するデータをDataFrameオブジェクトから簡単に取り出すことができます。

上記のコードは、他にも色々書き方はできますが、伝えたいことはIndexクラスを怖がらずに、うまく付き合うと良いことがあるということです。例えば、上記の問題を最初にtarget = df['d'].dropna().reset_index(drop=True)など書いてしまうと、欠損していないカラム'd'の値は取得できますが、この先が大変です。本連載で、Indexクラスと皆様が仲良くなることを願っています!


まとめ

今回は、代表的なIndexクラスの紹介や便利な関数の紹介でした。まだまだIndexクラスの初歩的な解説ですが、まずはreset_index関数の意味などしっかり理解していただければと思います。

この記事が気に入ったらサポートをしてみませんか?