見出し画像

第1回 DataFrameとIndexの関係

DataFrameとは

DataFrameとは、データ行列を扱うクラスです。Pandasを利用する際に必ず利用するクラスと言っていいでしょう。DataFrameは便利な関数を持っており、中身を意識せずに、様々な処理を実現できます。ただし、きちんと理解していないと、より良いPandasコードを書くことはできません。そして、Pandasをきちんと理解する為のポイントとなるのは、PandasのIndexクラスなのです。

皆さんの中にもよく分からないけどDataFrameのオブジェクトからreset_index関数を呼び出している人がいると思います。reset_index関数は、一体何をしているのか?これを理解するために、今回はDataFrameとIndexの関係を解説します。

DataFrameの構造

先ほどDataFrameは、データ行列を扱っていると説明しましたが、正確には、DataFrameは行名と列名も管理しています。そして、行名と列名を管理するクラスこそが、Indexクラスなのです。具体的には下記の図のような構造になっています。

画像1

行名は、DataFrameオブジェクトのindexプロパティにIndexオブジェクトとして保持しています。同様に、列名は、DataFrameオブジェクトのcolumnsプロパティにIndexオブジェクトとして保持しています。(ちなみに、DataFrameオブジェクトのaxesプロパティにアクセスすれば、indexとcolumnsのリストとしてまとめて取得できます。)

データ行列は、DataFrameオブジェクトの_seriesプラパティ全データ列のdictオブジェクト(keyは列名、valueはデータ列のSeriesオブジェクト)として保持しています。ただし、_seriesプロパティは直接利用することは推奨されていません。その代わりに、DataFrameオブジェクトのvaluesプロパティを利用することで、numpyのndarrayとして全行列のデータ値を取得できます。

DataFrameの構造を確認するコード

画像2

画像3

画像4

画像5

画像6

DataFrameへのアクセス

valuesプロパティでDataFrameの全データ値を取得することができますが、特定の列や行を指定して取り出すための関数も提供されています。このような関数はいくつか使い方に応じて提供されていますが、しっかり理解しないと混乱を招きます。その理解の大きな手助けになるのは、Indexクラスを経由したアクセスなのか、Indexクラスを経由しないアクセスなのかを把握することです。

Indexクラスを経由しないアクセス

Indexクラスを経由しないということは、つまり行名と列名を用いないでアクセスするということです。その場合、行番号または列番号を用いてアクセスすることになります。

アクセスする関数の一つとして、iloc関数があります。iloc関数は、行番号と列番号を指定して、データを取得する関数です。具体的には、下記の通りです。

// 指定した行番号のSeriesオブジェクトを取得。
df.iloc[行番号]

// 指定した行番号のリストのDataFrameオブジェクトを取得。
df.iloc[行番号リスト]

// 指定した列番号のSeriesオブジェクトを取得。
// :は、全ての行/列番号のリストの指定を意味します。
df.iloc[:, 列番号]

// 指定した行番号と列番号のデータ値を取得。
df.iloc[行番号, 列番号]

// 指定した行番号リストと列番号リストのDataFrameオブジェクトを取得。
df.iloc[行番号リスト, 列番号リスト]

iloc関数は、1次元目に行番号、2次元目に列番号を指定することで、データを取得できる関数です。指定方法で、返り値のデータ型が異なることに注意してください。

iloc関数だけでなく、iat関数でも行番号と列番号を指定してデータ値を取得することができます。ただし、iat関数は、必ず行番号と列番号を1つずる指定して、1つのデータ値を取得する関数です。

// 指定した行番号と列番号のデータ値を取得。
df.iat[行番号, 列番号]

行番号、列番号を利用したデータ取得を行う関数は、関数の最初にiが基本的についています。iがついていたら、行番号、列番号の取得だなと意識しましょう。

// 指定した行名のSeriesオブジェクトを取得。
df[列名]

// 指定した列名リストのDataFrameオブジェクトを取得。
df[列名リスト]

Indexクラスを経由しないアクセスのサンプルコード

画像7

画像8

画像9

画像10

画像11

Indexクラスを経由するアクセスのサンプルコード

Indexクラスを経由して、つまり行名と列名を用いてアクセスする関数には、loc関数があります。loc関数は、行名はDataFrameオブジェクトのindexプロパティのIndexオブジェクトの値から判定され、列名はDataFrameオブジェクトのcolumnsプロパティのIndexオブジェクトの値から判定されます。

// 指定した行名のSeriesオブジェクトを取得。
df.loc[行名]

// 指定した行名のリストのDataFrameオブジェクトを取得。
df.loc[行名リスト]

// 指定した列名のSeriesオブジェクトを取得。
// :は、全ての行/列名のリストの指定を意味します。
df.loc[:, 列名]

// 指定した行名と列名のデータ値を取得。
df.loc[行名, 列名]

// 指定した行名リストと列名リストのDataFrameオブジェクトを取得。
df.loc[行名リスト, 列名リスト]

iloc関数とiat関数の関係と同様に、loc関数に対してはat関数が存在します。at関数は、必ず行名と列名を指定して、1つのデータ値を取得する関数です。

// 指定した行名と列名のデータ値を取得。
df.at[行名, 列名]

また関数を用いず、直接1次元目に列名を指定してデータを取り出す方法もあります。特定の列だけ取り出したいケースは、データ分析においては多く、よく利用するので覚えておきましょう。

Indexクラスを経由するアクセスのサンプルコード

画像12

画像13

画像14

画像15

画像16

画像17

画像18

関数による行名の変更

DataFrameオブジェクトのindexプロパティに直接Indexクラスを設定することもできますが、関数を使って変更することができます。その関数は、set_index関数reindex関数reset_index関数です。

set_index関数は、引数に指定した列名のデータ列を行名(indexプロパティ)に設定する関数です。

// 指定した列名のデータ列を行名に設定。
df.set_index(列名)

// 指定した列名リストの複数のデータ列を行名に設定。
df.set_index(列名リスト)

reindex関数は、引数に指定したデータ値を行名(indexプロパティ)に設定する関数です。同じ行名が存在しているデータ行は、元のデータ値が格納されており、存在しなかったデータ行は、空のデータ値が格納されている。axis=1に指定することで、対象を行から列に変更することができます。columns引数に値リスト指定することでも、対象を列に変更することができます。

// 指定した値リストを新たな行名/列名に設定。
df.reindex(値リスト, axis=0 or 1)

reset_index関数は、設定されている行名(indexプロパティ)をリセットして、新たな行名を設定する関数です。オプションパラメータdropTrueにすると設定されていた行名は破棄されます。dropFalseにすると設定されていた行名はデータ行として追加される。新たに設定される行名は0からの連続値が設定されています。(型は、RangeIndexが採用されています。詳しくは第2回で解説します。)

// 設定されている行名を破棄して、新たな行名を設定。
df.reset_index(drop=True or False)

関数による行名の変更のサンプルコード

画像19

画像20

画像21

まとめ

DataFrameとIndexの関係は分かりましたか?DataFrameの行名と列名を関するのがIndexクラスの大きな役割です。特に行名を扱うのは直感的でなく、違和感があるかもしれません。そのため多くの人は行名を意識しないで済むように、reset_index関数を定期的に呼び出しているのが実態なのでしょう。しかし、Pandasの処理はこの行名こそが多くの変換処理の実現を担っており、これらを理解すれば1つ上のレベルのPandas使いになれるでしょう。

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