web-dev-qa-db-ja.com

.locがスライスに対して包括的動作をするのはなぜですか?

何らかの理由で、次の2つのiloc/locの呼び出しは、異なる動作を生成します。

>>> import pandas as pd
>>> df = pd.DataFrame(dict(A=range(3), B=range(3)))
>>> df.iloc[:1]
   A  B
0  0  0
>>> df.loc[:1]
   A  B
0  0  0
1  1  1

locは行ラベルを考慮し、ilocは行の整数ベースのインデックスを考慮することを理解しています。しかし、locの上限が包括的であると見なされ、ilocの上限が排他的であると見なされるのはなぜですか?

14
James Ko

クイックアンサー:

ラベルを使用する場合は、DataFrameの他の行に関する知識が少なくて済むため、エンドインクルーシブスライスを実行する方が理にかなっていることがよくあります。

位置ではなくラベルを気にするときはいつでも、エンドエクスクルーシブなラベルスライスは不便な方法で位置依存性をもたらします。


長い答え:

関数の動作はトレードオフです。あるユースケースを他のユースケースよりも優先します。最終的に、_.iloc_の操作は、Pandas開発者による主観的な設計上の決定です(@ALlollzによるコメントが示すように、この動作 意図的 )。彼らがなぜそれをそのように設計したのかを理解するために、ラベルスライスが位置スライスと異なる理由を考えてください。

2つのDataFrame _df1_と_df2_があると想像してください。

_df1 = pd.DataFrame(dict(X=range(4)), index=['a','b','c','d'])
df1 = pd.DataFrame(dict(X=range(4)), index=['b','c','z'])
_

_df1_に含まれるもの:

_   X
Y
a  0
b  1
c  2
d  3
_

_df2_に含まれるもの:

_   X
Y
b  0
c  1
z  2
_

実行するラベルベースのタスクがあるとします。_df1_と_df2_の両方からbcの間の行を取得し、実行したいとします。両方のDataFrameに同じコードを使用します。 bcは両方のDataFrameで同じ位置にないため、単純な位置スライスではうまくいきません。そこで、ラベルベースのスライスに目を向けます。

_.loc_がend-exclusiveの場合、bcの間の行を取得するには目的の終了行のラベルだけでなく、その次の行のラベルも知っています。構築されると、この次のラベルは各DataFrameで異なります。

この場合、2つのオプションがあります。

  • DataFrameごとに個別のコードを使用します:_df1.loc['b':'d']_および_df2.loc['b':'z']_。これは、必要な行だけでなく追加情報を知る必要があることを意味するため、不便です。
  • 最初に位置インデックスを取得し、1を追加してから、位置スライスを使用します:df.loc[df.index.get_loc('b'):df.index.get_loc('c')+1]。これはただの言葉です。

しかし、_.loc_はエンドインクルーシブなので、_.loc['b':'c']_とだけ言うことができます。はるかに簡単です!

位置ではなくラベルを気にし、位置に依存しないコードを書き込もうとしているときはいつでも、end-inclusive label slicingは、不便な方法で位置依存性を再導入します

そうは言っても、エンドエクスクルーシブなラベルベースのスライスが本当に必要なユースケースがあるかもしれません。もしそうなら、あなたは使用することができます この質問の@Willzの答え

_df.loc[start:end].iloc[:-1]
_
11
ASGM