HOWTO · Pandas

Pandas の特定の値に一致する列の行のインデックスを取得する

この記事では、Pandas でカラムが特定の値に一致する行のインデックスを取得する方法を紹介します。

このページの内容

条件に一致する行を取得するには、ブールマスクを作成してDataFrame.locに渡します。対応するラベルだけを取得するには、同じマスクをDataFrame.indexに適用します。通常のPythonリストが必要な場合は、tolist()を呼び出します。インデックスラベルは行を識別するもので、連続した整数の位置とは限りません。同じマスクを使えば、DataFrameに独自のラベルが付いている場合でも、行の選択とラベルの選択を対応させられます。取得したレコードをさらに処理する場合はDataFrame.locを使い、ラベル自体が必要な場合はインデックスを使う式を選びます。

Pandasで数値条件に一致する行を取得する

この例では、列Bが19と等しい行を選択し、さらに列Cの条件をORで組み合わせます。DataFrame.locは一致した行を返し、DataFrame.indexはそれらのラベルを返します。各比較式を括弧で囲むことで、組み合わせたブール条件が明確になります。実際のDataFrameでは、サンプルの列名と値をデータに合わせて置き換えてください。マスクを|または&で組み合わせるときは各比較式を括弧で囲み、Pythonがそれぞれのブール値のSeriesに意図した演算を適用するようにします。

import numpy as np
import pandas as pd

np.random.seed(0)
df = pd.DataFrame(np.random.randint(1, 20, size=(20, 4)), columns=list("ABCD"))

matches_b = df["B"] == 19
print(df.loc[matches_b])
print(df.index[matches_b].tolist())

matches_b_or_c = (df["B"] == 19) | (df["C"] == 19)
print(df.loc[matches_b_or_c])
print(df.index[matches_b_or_c].tolist())
    A   B  C   D
6   1  19  4  18
9  12  19  3   1
[6, 9]
     A   B   C   D
6    1  19   4  18
9   12  19   3   1
14  12  15  19   1
[6, 9, 14]

最初のマスクは、Bの値が19である行を選択し、そのラベルは[6, 9]です。2つ目のマスクはOR(|)を使うため、BまたはCのどちらかが19であれば行が選択され、ラベルは[6, 9, 14]になります。両方の条件を満たす必要がある場合は、括弧で囲んだ条件の間に&を使います。これらは行の位置ではなくインデックスラベルなので、DataFrameをフィルタリングした後や独自のインデックスを付けて読み込んだ場合でも、ラベルは意味を保ちます。DataFrame.indexはメソッドではなく属性です。また、tolist()を使うと、特定のpandasインデックスクラスに依存せず、選択したラベルをPythonリストに変換できます。元のラベルが一意でない場合、一致した行ごとにそのインデックスラベルが追加されるため、結果に同じラベルが複数含まれることがあります。

Pandasで文字列条件に一致する行のインデックスを取得する

文字列のフィルタリングも同じ方法で行えます。列を値全体と比較して完全一致を調べるか、str.containsを使って部分文字列を検索します。セル全体の値が一致する必要がある場合は完全一致が便利で、値にほかの文字列が含まれる可能性がある場合は部分一致が便利です。以下の例では、一致した行とそのラベルの両方を取得します。部分一致の条件に使う小文字のrexは、Tyrannosaurus rexにも同じ大文字小文字で含まれています。コードと出力のブロックはそのまま保持されるため、サンプルの文字列や表示ラベルは英語のままです。

import pandas as pd

df = pd.DataFrame(
    {
        "Name": ["blue", "delta", "echo", "charlie", "alpha"],
        "Type": ["Raptors", "Raptors", "Raptors", "Raptors", "Tyrannosaurus rex"],
    }
)

exact_name = df["Name"] == "blue"
print(df.index[exact_name].tolist())
print(df.loc[exact_name])

name_contains_ha = df["Name"].str.contains("ha")
print(df.index[name_contains_ha].tolist())
print(df.loc[name_contains_ha])

name_contains_ha_and_type_contains_rex = name_contains_ha & df["Type"].str.contains("rex")
print(df.loc[name_contains_ha_and_type_contains_rex])
[0]
   Name     Type
0  blue  Raptors
[3, 4]
      Name               Type
3  charlie            Raptors
4    alpha  Tyrannosaurus rex
    Name               Type
4  alpha  Tyrannosaurus rex

完全一致ではblueが見つかり、そのラベルが返されます。部分文字列haはcharlieとalphaに一致します。これにType列のrex条件を組み合わせると、alphaの行が選択され、そのラベルは[4]です。str.containsは既定で大文字と小文字を区別するため、データ内の表記に合わせるか、caseオプションを明示的に設定してください。両方の条件を満たす場合は&、どちらか一方を満たせばよい場合は|で条件を組み合わせ、各比較式を括弧で囲みます。数値のフィルタリングと同様に、行を取得するにはマスクをDataFrame.locに渡し、ラベルを取得するにはDataFrame.indexに適用します。完全一致の式は列名と比較値を変えれば別の列にも使えます。部分一致の式も、検索文字列を変えるだけで同じ形のまま使えます。