pandas

【pandas】DataFrameのデータ選択方法 ~loc, iloc, at, iat 等~

【pandas】DataFrameのデータ選択方法 loc iloc at iat

pandasのDataFrameのデータ選択方法について解説します。

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を使用する場合には、上記例のようにデータを取得するための条件となるクエリ文字列で指定します。また、threshold1threshold2のようにプログラム中で作成した変数をクエリに含めたい場合には、@を文字列内で使用することで該当箇所に埋め込んでデータ選択をすることも可能です。

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

上記例のように[]内に、[行のインデックス, 列のインデックス]という形で指定することで該当する特定位置の値を取得することができます。

locatは明示的なインデックスを対象にし、ilociatは暗黙的なインデックスを対象にします。特定位置の値を選択する場合には、locatilociatについては結果は同じです。locilocは以降で説明するようなスライスでのデータ選択にも対応しているという点でatiatとは異なります。

スライスで任意の行、列を選択する方法

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でピボットテーブルを扱う」でまとめていますので参考にしてください。

まずは本記事で紹介したような基本的なデータ選択方法を理解してもらい、groupbypivot_tableといった少し高度なデータ処理ができるようになると良いかと思います。

まとめ

pandasのDataFrameのデータ選択方法について解説しました。

DataFrameのデータ選択方法として是非覚えておいて欲しいのはloc, iloc, at, iatといったデータ選択方法です。しかし、それらメソッドを使用しないデータアクセス方法も色々とあります。列名を指定しての取得やスライス、マスキング等の方法を紹介しています。

pandasを利用する際にとても重要になってくるのがDataFrameの扱いになってきます。是非、各種方法について扱えるようにしてほしいと思います。