pandasのDataFrameのデータ選択方法について解説します。
Contents
DataFrameのデータ選択方法
pandasを利用する際にとても重要になってくるのがDataFrameの扱いです。本記事ではDataFrameから必要なデータを選択する方法の基本について説明します。
DataFrameのデータ選択方法として是非覚えておいて欲しいのは後述するloc
, iloc
, at
, iat
といったデータ選択方法です。しかし、それらメソッドを使用しないデータアクセス方法も色々とあります。
本記事では、まずはDataFrameとしてのデータ選択方法を概観します。その後にloc
, iloc
, at
, iat
といった重要なメソッドを使ったDataFrameのデータ選択方法を紹介していきます。loc
, iloc
, at
, iat
の使い方を確認したい場合は、その他の方法は読み飛ばしていただいても構いません。
列名を指定して特定の列を取得する方法
基本的な使用方法
DataFrameで、列名を指定して特定の列を取得する場合には以下のように使用します。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # 列名を指定して特定の列情報を取得する(辞書のようにアクセス) print(df["attr1"], "\n") # 列名を変数のようにして読み込むことも可能 print(df.attr1)
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 A 10 B 20 C 30 D 40 E 50 Name: attr1, dtype: int64 A 10 B 20 C 30 D 40 E 50 Name: attr1, dtype: int64
使い方は、Python辞書のキーを指定してアクセスする方法と同様でdf['列名']
とすることで特定列を取得できます。また、列名を変数名のように「df.列名
」としてアクセスすることも可能です。
注意事項:列名とメソッド名が同じ場合に注意
列名を変数名のように「df.列名
」としてアクセスする場合には注意事項があります。DataFrameのメソッド名と同じ列名を使ってしまうと取得できるデータは想定のものになりません。メソッド名と列名が同じになっているような列がないか注意しましょう。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "pop": attr2}) print(df, "\n") # メソッド名と重なる場合、辞書形式の取得と属性名での取得は一致しない print(f"df.pop: \n{df.pop}\n") print(f"df['pop']: \n{df['pop']}\n") print(df.pop is df["pop"])
【実行結果】 attr1 pop A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 df.pop: <bound method DataFrame.pop of attr1 pop A 10 60 B 20 70 C 30 80 D 40 90 E 50 100> df['pop']: A 60 B 70 C 80 D 90 E 100 Name: pop, dtype: int64 False
上記例では、データが「pop
」という列を持っています。しかし、DataFrameのメソッドにpop
メソッドがあるため、df.pop
として取得できるものはdf['pop']
として取得できるものとは異なります。is
を使って確認を取っていますがFalse
で一致しません。
このように、DataFrameのメソッドと列名が同じ場合だと想定外の結果となることもあるので注意して使用するようにしてください。
特定の列情報を任意順序に並べたデータを取得する方法
DataFrameの列の順序を任意に並べ替えたい場合には、以下のように列名を並べて取得します。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # 特定の列名を指定し、任意順序で並べ替えてデータを取得する(同じ列の複製も可能) print(df[["attr2", "attr1", "attr1", "attr2"]])
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 attr2 attr1 attr1 attr2 A 60 10 10 60 B 70 20 20 70 C 80 30 30 80 D 90 40 40 90 E 100 50 50 100
上記例では、列の順序を表すようなリストを[]
の中に渡すことで、指定した列順序で並び替えています。また、attr1
, attr2
を複数回指定していますが、列が複製されていることが分かるかと思います。このように、同一の列名を複数回リストに指定すれば、列データを複製するようなことが可能になります。
既存の列を用いて計算した結果列を作成する方法
DataFrameの既存の列を用いて計算した結果で新しい列を作成したくなる場合がよくあります。以下例のように、既存の列を用いて計算したうえで新しく結果列を作ることができます。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # 既存の列から計算して新しい列を作成する df["sum"] = df["attr1"] + df["attr2"] print(df)
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 attr1 attr2 sum A 10 60 70 B 20 70 90 C 30 80 110 D 40 90 130 E 50 100 150
df['sum']
は元々のデータには存在していないですが、上記例のように足し算の計算式を指定することで新しい'sum'
という列を作成することができます。上記例は、足し算「+
」ですが、その他の演算や関数等を使って新しい列を作ることももちろん可能です。
スライスで特定のキーを持つ行を選択する方法
DataFrameの特定のキーを持つ行を選択する場合にはスライスが使用できます。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # ===== スライスで特定のキーを持つ行を選択する # 明示的なインデックスを使用する場合 print(df["B":"D"], "\n") # 暗黙的なインデックスを使用する場合 print(df[1:3])
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 attr1 attr2 B 20 70 C 30 80 D 40 90 attr1 attr2 B 20 70 C 30 80
[]
の中にキーとなるインデックスをスライスで指定すると該当する行を選択できます。pandasのDataFrameやSeriesでは、インデックスには明示的なインデックスと暗黙的なインデックスがあります。
明示的なインデックスは「index=
」で指定しているインデックスです。一方、暗黙的なインデックスは表面上は見えていませんが0~
の数値で振られているインデックスです。例えば上記の例でいえば、明示的なインデックス「'A'
」に相当する暗黙的なインデックスは「0
」となります。
注意が必要なのは、明示的なインデックスのスライスでは終わりを含みますが、暗黙的なインデックスのスライスでは終わりを含まないことです。上記例でいうと、['B':'D']
という指定であれば'D'
に該当する行を含みますが、[1:3]
とすると3
に該当する行は含まれません。
特定条件に一致する行を選択する方法
マスキングによるデータ選択
DataFrameの中から特定条件に一致する行を選択するには、以下の例のようにマスキングすることができます。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # 特定の条件に一致する行を選択する print(df[(df["attr1"] > 10) & (df["attr2"] < 100)])
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 attr1 attr2 B 20 70 C 30 80 D 40 90
上記例では「attr1
列の値が10
より大きい」かつ「attr2
列の値が100
より小さい」に該当する行が選択されます。df['attr1'] > 10
といった部分は該当する行がTrue
となるようなbool
型になります。df['attr2'] < 100
についても同様の考え方です。
選択対象とする行がTrue
となるbool
値をDataFrameの[]
内に指定することで該当する行だけマスキングすることができます。
queryを用いた条件指定によるデータ選択
特定条件に一致する行を選択する方法として、query
メソッドを使用した方法もあります。query
は、以下の例のように使用します。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2}) print(df, "\n") # queryを用いて条件に一致する行を選択する # ※ 内部的に文字列評価を行うためパフォーマンスに影響ある場合があることに注意 print(df.query("attr1 > 10 and attr2 < 100"), "\n") # 変数を使ったクエリの記載も可能 threshold1 = 20 threshold2 = 90 print(df.query("attr1 >= @threshold1 and attr2 < @threshold2"))
【実行結果】 attr1 attr2 A 10 60 B 20 70 C 30 80 D 40 90 E 50 100 attr1 attr2 B 20 70 C 30 80 D 40 90 attr1 attr2 B 20 70 C 30 80
query
を使用する場合には、上記例のようにデータを取得するための条件となるクエリ文字列で指定します。また、threshold1
やthreshold2
のようにプログラム中で作成した変数をクエリに含めたい場合には、@
を文字列内で使用することで該当箇所に埋め込んでデータ選択をすることも可能です。
query
は、条件式を文字列で直接記載するので複雑な条件を直感的に読みやすいというメリットがあります。ただし、query
では内部的に文字列を評価して処理を実行するため、巨大なデータフレームを扱う場合などではパフォーマンス上で影響があるかもしれないので注意が必要です。
また、すべての状況でquery
が使用できるとは限りませんので実行したいクエリを実行できるかはよく確認してもらえればと思います。
任意の行、列の値を選択する方法 ~loc, iloc, at, iat~
DataFrameで任意の行や列の値を選択する方法は、loc
, iloc
, at
, iat
を使用することができます。これらのメソッドの使い方は是非覚えてください。
pandasのDataFrameやSeriesでは、インデックスには明示的なインデックスと暗黙的なインデックスがあります。明示的なインデックスは「index=
」等で指定しているインデックスで、一方の暗黙的なインデックスは表面上は見えていませんが0~
の数値で振られているインデックスです。
以降で説明するloc
, iloc
, at
, iat
に関して「i
」がついているものは暗黙的なインデックスを対象に、「i
」がついていないものは明示的なインデックスを対象にしてデータ選択するメソッドです。また、iloc
は「integer-location」、iat
は「integer-position」を意味します。
特定位置の情報を選択する方法
DataFrameにおける特定位置の値(例えば「2行1列の値」等)を選択する場合は、loc
, iloc
, at
, iat
を使用して以下の例のようにデータを選択ができます。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) attr3 = pd.Series([110, 120, 130, 140, 150], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2, "attr3": attr3}) print(df, "\n") # 特定の位置を選択する # 明示的なインデックスを使用する場合 print(df.loc["C", "attr2"], "\n") # atを使っても同様のことができる print(df.at["C", "attr2"], "\n") # 暗黙的なインデックスを使用する場合 print(df.iloc[2, 1], "\n") # iatを使っても同様のことができる print(df.iat[2, 1])
【実行結果】 attr1 attr2 attr3 A 10 60 110 B 20 70 120 C 30 80 130 D 40 90 140 E 50 100 150 80 80 80 80
上記例のように[]
内に、[行のインデックス, 列のインデックス]
という形で指定することで該当する特定位置の値を取得することができます。
loc
やat
は明示的なインデックスを対象にし、iloc
やiat
は暗黙的なインデックスを対象にします。特定位置の値を選択する場合には、loc
とat
、iloc
とiat
については結果は同じです。loc
やiloc
は以降で説明するようなスライスでのデータ選択にも対応しているという点でat
やiat
とは異なります。
スライスで任意の行、列を選択する方法
DataFrameにおける任意の行、列をスライスで選択する場合は、loc
, iloc
を使用して以下例のようにデータ選択ができます。
import pandas as pd attr1 = pd.Series([10, 20, 30, 40, 50], index=["A", "B", "C", "D", "E"]) attr2 = pd.Series([60, 70, 80, 90, 100], index=["A", "B", "C", "D", "E"]) attr3 = pd.Series([110, 120, 130, 140, 150], index=["A", "B", "C", "D", "E"]) df = pd.DataFrame({"attr1": attr1, "attr2": attr2, "attr3": attr3}) print(df, "\n") # 任意の行、列を選択する(スライスを使用する例) # 明示的なインデックスを使用する場合 print(df.loc["B":"D", "attr2":"attr3"], "\n") # 暗黙的なインデックスを使用する場合 print(df.iloc[1:3, 1:2])
【実行結果】 attr1 attr2 attr3 A 10 60 110 B 20 70 120 C 30 80 130 D 40 90 140 E 50 100 150 attr2 attr3 B 70 120 C 80 130 D 90 140 attr2 B 70 C 80
上記例のように[]
内に、[行のスライス, 列のスライス]
という形で指定することで、指定した行の範囲、列の範囲に該当するデータを選択することができます。
ここで注意が必要なのは、明示的なインデックスでは終わりを含みますが、暗黙的なインデックスでは終わりを含まないことです。上記例の行スライスでいうと、例えば「'B':'D'
」という指定であれば「'D'
」は含みますが、「1:3
」とすると3
は含まれません。列スライスについても同様です。
データ集約やピボットテーブル
上記までは、対象DataFrameから対象の行を抽出する例を中心に様々な方法を紹介してきました。データ分析を行う際には、データをグループ化して集約処理したり、ピボットテーブルを作成したくなることがよくあります。
集約処理は、あるグループに対して合計や平均などを計算する処理で、単純にDataFrame全体を集約をすればよいわけではなく、ある区分ごとのグループ単位で集約処理を実施することでデータ分析に非常に有益な情報が得られます。pandasではgroupby
メソッドが用意されていて簡単に処理が可能です。groupby
については「DataFrameをgroupbyでグループ化して集約する方法」でまとめていますので参考にしてください。
また、ピボットテーブルもグループごとの情報を確認するためによく使われるものです。ピボットテーブルはgroupby
を用いても実現できますが、pandasではpivot_table
メソッドが用意されていて簡単に対処できます。pivot_table
については「DataFrameのpivot_tableでピボットテーブルを扱う」でまとめていますので参考にしてください。
まずは本記事で紹介したような基本的なデータ選択方法を理解してもらい、groupby
やpivot_table
といった少し高度なデータ処理ができるようになると良いかと思います。
まとめ
pandasのDataFrameのデータ選択方法について解説しました。
DataFrameのデータ選択方法として是非覚えておいて欲しいのはloc
, iloc
, at
, iat
といったデータ選択方法です。しかし、それらメソッドを使用しないデータアクセス方法も色々とあります。列名を指定しての取得やスライス、マスキング等の方法を紹介しています。
pandasを利用する際にとても重要になってくるのがDataFrameの扱いになってきます。是非、各種方法について扱えるようにしてほしいと思います。
上記で紹介しているソースコードについてはgithubにて公開しています。参考にしていただければと思います。