Pandas の obj[i] と obj.loc[i] などの違いについて

Pandas の Series オブジェクトの話になります。 Series オブジェクトを obj とした時、 obj[i] と obj.loc[i] と obj.iloc[i] の違い、さらに obj[s:e] のようにスライスした時の動作の違いを理解するために、コードを書き実行して動作を確かめました。確認のためのコードは以下になります。Series オブジェクトの index が整数のみからなるか否かで、 obj[i] の振る舞いが変わるのには注意が必要だと思いました。コードの説明はコメントとして記載しました。

############################################################################
# index が整数型 Seires の場合(index の値が整数のみからなる Series の場合)
############################################################################
import pandas as pd

s1 = pd.Series([15,20,25,30,40], index=[3,4,5,6,7])
s2 = pd.Series([15,20,25,30,40])

# (1) s1[-1] を取得する
s1[-1]
# KeyError: -1

# (2) s2[-1] を取得する
s2[-1]
# KeyError: -1

# 上記よりindex が整数のみからなる場合は、obj[i] の i はラベルのように認
# 識されることがわかる。
# ただし、スライスの場合は obj[s:e] の s, e はインデックスとして扱われる

# (3) s1[3:5] を取得する
s1[3:5]
# 6    30
# 7    40
# dtype: int64

# (4) s1.loc[-1] を取得する
s1.loc[-1]
# KeyError: 'the label [-1] is not in the [index]'

# (5) s1.loc[3:5] で loc にスライスを使用して取得する
s1.loc[3:5]
# 3    15
# 4    20
# 5    25
# dtype: int64

# (6) s1.iloc[-1] を使った場合
s1.iloc[-1]
# 40

# (7) s1.iloc[3:5] で iloc にスライスを使用して取得する
s1.iloc[3:5]
# 6    30
# 7    40
# dtype: int64

################################################################
# index がオブジェクト型の  Series の場合
################################################################

s3 = pd.Series([15,20,25,30,40], index=[3,4,5,6,'X'])

# (8) s3[-1] を取得する
s3[-1]
# 40

# (9) s3[3] を取得する
s3[3]
# 15

# index がオブジェクト型の場合は、 obj[i] はインデックスとして扱われる
# loc, iloc, スライス を使用した際の挙動は (3)(4)(5)(6)(7) と同様になると思われる(未確認)

################################################################
# index が重複している時の Series の場合
################################################################

# インデックスが重複しているとき
s4 = pd.Series([10, 100, 1000, 10000], index=['a', 'a', 'b', 'b'])
s5 = pd.Series([200, 2000], index=['a', 'b'])
s6 = pd.Series([200, 200], index=['a', 'a'])

# (10) 値を取得する
s4['a']
# a     10
# a    100
# dtype: int64

# (11) 値を取得する
s4[['a','b']]
# a       10
# a      100
# b     1000
# b    10000
# dtype: int64

# (12) 重複していないインデックスを重複するように reindex する
s5.reindex(s4.index)
# a     200
# a     200
# b    2000
# b    2000
# dtype: int64

# (13) インデックスが重複しているとき reindex する
s6.reindex(['x', 'y'])
# ValueError: cannot reindex from a duplicate axis

以上です。