次のようなDataFrameがあるとします
import pandas as pd
df = pd.DataFrame([
[1, 2, 1], [1, 3, 2], [4, 6, 3], [4, 3, 4], [5, 4, 5]
], columns=['A', 'B', 'C'])
>> df
A B C
0 1 2 1
1 1 3 2
2 4 6 3
3 4 3 4
4 5 4 5
元の DataFrame は、列と行が多くなり、より複雑になっています。
いくつかの条件を満たす最初の行を取得したいです。例:
- A > 3 となる最初の行を取得します (行 2 を返します)
- A > 4 AND B > 3 となる最初の行を取得します (行 4 を返します)
- A > 3 AND (B > 3 OR C > 2) となる最初の行を取得します (行 2 を返します)
しかし、特定の基準を満たす行がない場合は、A (または他の場合は B、C など) で降順に並べ替えた後、最初の行を取得したいと思います。
- A > 6 の最初の行を取得します (A の降順で並べ替えて行 4 を返し、最初の行を取得します)
DataFrame を反復処理することで、これを実現できました (これはひどいことだとわかっています :P)。では、これを解決するためのより Python 的な方法は何でしょうか?
ベストアンサー1
このチュートリアルpandas のスライスに非常に適しています。ぜひチェックしてみてください。いくつかのスニペットを紹介します... 条件付きでデータフレームをスライスするには、次の形式を使用します。
>>> df[condition]
これにより、 を使用してインデックスを作成できるデータフレームのスライスが返されますiloc
。例を次に示します。
A > 3 となる最初の行を取得します (行 2 を返します)
>>> df[df.A > 3].iloc[0] A 4 B 6 C 3 Name: 2, dtype: int64
実際に必要なのが行番号である場合は、 を使用するのではなくiloc
、 を使用しますdf[df.A > 3].index[0]
。
A > 4 AND B > 3 となる最初の行を取得します。
>>> df[(df.A > 4) & (df.B > 3)].iloc[0] A 5 B 4 C 5 Name: 4, dtype: int64
A > 3 AND (B > 3 OR C > 2) となる最初の行を取得します (行 2 を返します)
>>> df[(df.A > 3) & ((df.B > 3) | (df.C > 2))].iloc[0] A 4 B 6 C 3 Name: 2, dtype: int64
さて、最後のケースでは、降順でソートされたフレームを返すデフォルトのケースを処理する関数を記述できます。
>>> def series_or_default(X, condition, default_col, ascending=False):
... sliced = X[condition]
... if sliced.shape[0] == 0:
... return X.sort_values(default_col, ascending=ascending).iloc[0]
... return sliced.iloc[0]
>>>
>>> series_or_default(df, df.A > 6, 'A')
A 5
B 4
C 5
Name: 4, dtype: int64
予想どおり、行 4 が返されます。