pandasのインデックス指定で行・列を抽出
pandas.DataFrame
, pandas.Series
の[]
によるインデックス指定で、行・列および要素を選択し抽出・取得できる。[]
に指定する値のタイプによって取得できるデータが異なる。
at
, iat
, loc
, iloc
を使うと、より明確に範囲の選択が可能。列をスライス、行を行名・行番号やそのリストで選択することもできる。
列をindex
に割り当てるにはset_index()
を使う。
本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。以下のpandas.DataFrame
を例とする。
import pandas as pd
print(pd.__version__)
# 2.0.3
df = pd.DataFrame({'col_0': ['00', '10', '20', '30', '40'],
'col_1': ['01', '11', '21', '31', '41'],
'col_2': ['02', '12', '22', '32', '42'],
'col_3': ['03', '13', '23', '33', '43']},
index=['row_0', 'row_1', 'row_2', 'row_3', 'row_4'])
print(df)
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# row_1 10 11 12 13
# row_2 20 21 22 23
# row_3 30 31 32 33
# row_4 40 41 42 43
pandas.DataFrameの列を抽出
[列名]
: 単独の列をpandas.Seriesとして取得
[]
に列名(列ラベル)を指定すると、選択した列をpandas.Series
として取得できる。
print(df['col_2'])
print(type(df['col_2']))
# row_0 02
# row_1 12
# row_2 22
# row_3 32
# row_4 42
# Name: col_2, dtype: object
# <class 'pandas.core.series.Series'>
属性のように.
に続けて列名を指定することもできる。ただし、列名が既存のメソッド名や属性名などと重複しているとそちらが優先されるので注意。
print(df.col_2)
# row_0 02
# row_1 12
# row_2 22
# row_3 32
# row_4 42
# Name: col_2, dtype: object
[列名のリスト]
: 単独・複数列をpandas.DataFrameとして取得
列名のリストを指定すると、選択した複数列をpandas.DataFrame
として取得できる。列の順番は指定したリストの順番になる。
print(df[['col_2', 'col_0']])
print(type(df[['col_2', 'col_0']]))
# col_2 col_0
# row_0 02 00
# row_1 12 10
# row_2 22 20
# row_3 32 30
# row_4 42 40
# <class 'pandas.core.frame.DataFrame'>
要素数1のリストも一列のpandas.DataFrame
となる。pandas.Series
ではない。
print(df[['col_2']])
print(type(df[['col_2']]))
# col_2
# row_0 02
# row_1 12
# row_2 22
# row_3 32
# row_4 42
# <class 'pandas.core.frame.DataFrame'>
loc, ilocの例
loc
を用いると列名のスライスも指定可能。またiloc
を用いると列番号で指定することもできる。詳細は以下の記事を参照。
print(df.loc[:, 'col_1':'col_3'])
# col_1 col_2 col_3
# row_0 01 02 03
# row_1 11 12 13
# row_2 21 22 23
# row_3 31 32 33
# row_4 41 42 43
print(df.iloc[:, 2])
# row_0 02
# row_1 12
# row_2 22
# row_3 32
# row_4 42
# Name: col_2, dtype: object
pandas.DataFrameの行を抽出
[行名・行番号のスライス]
: 単独・複数行をpandas.DataFrameとして取得
[]
にスライスを指定すると、該当範囲の行をpandas.DataFrame
として取得できる。
print(df[1:4])
print(type(df[1:4]))
# col_0 col_1 col_2 col_3
# row_1 10 11 12 13
# row_2 20 21 22 23
# row_3 30 31 32 33
# <class 'pandas.core.frame.DataFrame'>
通常のスライスと同様に、マイナスの値で末尾からの位置を指定したり、start:stop:step
のようにstep
を指定したりすることも可能。奇数行または偶数行を抽出して取得できる。
print(df[:-3])
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# row_1 10 11 12 13
print(df[::2])
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# row_2 20 21 22 23
# row_4 40 41 42 43
print(df[1::2])
# col_0 col_1 col_2 col_3
# row_1 10 11 12 13
# row_3 30 31 32 33
あくまでもスライスでないとダメで、行番号を単独で指定するとエラーとなる。
# print(df[1])
# KeyError: 1
一行だけ選択される場合も、取得できるのはpandas.DataFrame
。pandas.Series
にはならない。
print(df[1:2])
print(type(df[1:2]))
# col_0 col_1 col_2 col_3
# row_1 10 11 12 13
# <class 'pandas.core.frame.DataFrame'>
行番号ではなく行名(行ラベル)でスライスを指定することもできる。行名(行ラベル)のスライスの場合はstart:stop
のstop
の行も含まれる。
print(df['row_1':'row_3'])
# col_0 col_1 col_2 col_3
# row_1 10 11 12 13
# row_2 20 21 22 23
# row_3 30 31 32 33
loc, ilocの例
loc
やiloc
を用いると、行名・行番号を単独で指定してpandas.Series
として取得したり、リストで複数行を選択したりできる。詳細は以下の記事を参照。
print(df.loc[['row_1', 'row_3']])
# col_0 col_1 col_2 col_3
# row_1 10 11 12 13
# row_3 30 31 32 33
print(df.iloc[1])
# col_0 10
# col_1 11
# col_2 12
# col_3 13
# Name: row_1, dtype: object
[boolのリスト・Series]
: Trueの行をpandas.DataFrameとして取得
bool
値(True
, False
)を要素とするリストやnumpy.ndarray
を指定すると、True
の行が抽出されpandas.DataFrame
として取得できる。
l_bool = [True, False, False, True, True]
print(df[l_bool])
print(type(df[l_bool]))
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# row_3 30 31 32 33
# row_4 40 41 42 43
# <class 'pandas.core.frame.DataFrame'>
True
の要素が1つだけでも、一行のpandas.DataFrame
。pandas.Series
にはならない。
l_bool = [True, False, False, False, False]
print(df[l_bool])
print(type(df[l_bool]))
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# <class 'pandas.core.frame.DataFrame'>
要素数と行数が一致していないとエラー。
# print(df[[True, False, False]])
# ValueError: Item wrong length 3 instead of 5.
bool
値を要素とするpandas.Series
も指定可能。順番ではなくラベルに従ってマスクされる。
s_bool = pd.Series([True, False, False, True, True], index=reversed(df.index))
print(s_bool)
# row_4 True
# row_3 False
# row_2 False
# row_1 True
# row_0 True
# dtype: bool
print(df[s_bool])
# col_0 col_1 col_2 col_3
# row_0 00 01 02 03
# row_1 10 11 12 13
# row_4 40 41 42 43
要素数およびラベルが一致していないとエラー。
s_bool_wrong = pd.Series([True, False, False, True, True],
index=['A', 'B', 'C', 'D', 'E'])
# print(df[s_bool_wrong])
# IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).
bool
値を要素とするpandas.Series
による行の抽出を利用して、条件を満たす行を抽出できる。
pandas.Seriesの要素の値を取得
以下のpandas.Series
を例とする。
s = df['col_0']
print(s)
# row_0 00
# row_1 10
# row_2 20
# row_3 30
# row_4 40
# Name: col_0, dtype: object
[ラベル名・番号]
: 単独の要素の値をそれぞれの型で取得
ラベル名・番号を単独で指定すると、その値がそのまま取得できる。
print(s[3])
print(type(s[3]))
# 30
# <class 'str'>
番号の場合、負の値で末尾からの位置を指定可能。-1
が末尾(一番最後)。
また、pandas.DataFrame
の列名指定のように、.
に続けてラベル名を指定することもできる。既存のメソッド名や属性名などと重複しているとそちらが優先されるので注意。
print(s[-1])
# 40
print(s['row_0'])
# 00
print(s.row_0)
# 00
[ラベル名・番号のリスト]
: 単独・複数の要素の値をpandas.Seriesとして取得
リストの場合は選択した複数の値をpandas.Series
として取得できる。順番は指定したリストの順番になる。要素数1のリストの場合も、要素自体ではなく要素数1のpandas.Series
。
print(s[[3, 1]])
print(type(s[[3, 1]]))
# row_3 30
# row_1 10
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
print(s[[1]])
print(type(s[[1]]))
# row_1 10
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
ラベル名のリストも指定可能。
print(s[['row_3', 'row_1']])
# row_3 30
# row_1 10
# Name: col_0, dtype: object
print(s[['row_1']])
# row_1 10
# Name: col_0, dtype: object
[ラベル名・番号のスライス]
: 単独・複数の要素の値をpandas.Seriesとして取得
スライスの場合も選択した複数の値をpandas.Series
として取得できる。要素1個が選択された場合、要素数1のpandas.Series
となる。
print(s[1:3])
print(type(s[1:3]))
# row_1 10
# row_2 20
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
print(s[1:2])
print(type(s[1:2]))
# row_1 10
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
ラベル名のスライスの場合はstart:stop
のstop
の要素も含まれる。
print(s['row_1':'row_3'])
# row_1 10
# row_2 20
# row_3 30
# Name: col_0, dtype: object
print(s['row_1':'row_1'])
# row_1 10
# Name: col_0, dtype: object
[boolのリスト・Series]
: Trueの要素をpandas.Seriesとして取得
bool
値(True
, False
)のリストやnumpy.ndarray
を指定すると、True
の要素が抽出されpandas.Series
として取得できる。
l_bool = [True, False, False, True, True]
print(s[l_bool])
print(type(s[l_bool]))
# row_0 00
# row_3 30
# row_4 40
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
True
の要素が1つだけでも、要素数1のpandas.Series
。
l_bool = [True, False, False, False, False]
print(s[l_bool])
print(type(s[l_bool]))
# row_0 00
# Name: col_0, dtype: object
# <class 'pandas.core.series.Series'>
要素数が一致していないとエラー。
# print(s[[True, False, False]])
# IndexError: Boolean index has wrong length: 3 instead of 5
bool
値を要素とするpandas.Series
も指定可能。順番ではなくラベルを元にマスクされる。
s_bool = pd.Series(l_bool, index=reversed(df.index))
print(s_bool)
# row_4 True
# row_3 False
# row_2 False
# row_1 False
# row_0 False
# dtype: bool
print(s[s_bool])
# row_4 40
# Name: col_0, dtype: object
要素数およびラベルが一致していないとエラー。
s_bool_wrong = pd.Series([True, False, False, True, True],
index=['A', 'B', 'C', 'D', 'E'])
# print(s[s_bool_wrong])
# IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).
pandas.DataFrameの要素の値を取得
pandas.DataFrame
からpandas.Series
を抽出し、さらにそのpandas.Series
から値を選択して取得することで、pandas.DataFrame
から要素の値を取得できる。
print(df['col_1']['row_2'])
# 21
スライスやリストを組み合わせて任意の範囲を抽出することもできる。
print(df['row_1':'row_3'][['col_1', 'col_3']])
# col_1 col_3
# row_1 11 13
# row_2 21 23
# row_3 31 33
このようにインデックス指定を繰り返す([...][...]
)方法はchained indexingと呼ばれ、選択範囲に値を代入する際にSettingWithCopyWarning
が発生する場合がある。
詳細は以下の記事を参照。
at
, iat
, loc
, iloc
を使うと行・列を一度に指定して選択可能。こちらのほうが望ましい。
print(df.at['row_2', 'col_1'])
# 21
print(df.loc['row_1':'row_3', ['col_1', 'col_3']])
# col_1 col_3
# row_1 11 13
# row_2 21 23
# row_3 31 33
行名・列名が整数値の場合の注意点
これまでの例は行名・列名が文字列だったが、行名・列名が整数値の場合は注意が必要。
以下のpandas.DataFrame
を例とする。
df = pd.DataFrame([[0, 10, 20], [30, 40, 50], [60, 70, 80]],
index=[2, 0, 1], columns=[1, 2, 0])
print(df)
# 1 2 0
# 2 0 10 20
# 0 30 40 50
# 1 60 70 80
[スカラー値]
, [リスト]
の場合、指定した値は列名とみなされる。
print(df[0])
# 2 20
# 0 50
# 1 80
# Name: 0, dtype: int64
print(df[[0, 2]])
# 0 2
# 2 20 10
# 0 50 40
# 1 80 70
[スライス]
の場合、指定した値は行名ではなく行番号とみなされる。負の値も使える。
print(df[:2])
# 1 2 0
# 2 0 10 20
# 0 30 40 50
print(df[-2:])
# 1 2 0
# 0 30 40 50
# 1 60 70 80
行名か行番号かを明確に指定するにはloc
(行名)またはiloc
(行番号)を使う。loc
の場合、start:stop
のstop
の行も含まれる。
print(df.loc[:2])
# 1 2 0
# 2 0 10 20
print(df.iloc[:2])
# 1 2 0
# 2 0 10 20
# 0 30 40 50
pandas.Series
の場合。以下を例とする。
s = df[2]
print(s)
# 2 10
# 0 40
# 1 70
# Name: 2, dtype: int64
pandas.Series
では指定した値が番号ではなくラベル名だとみなされる。
print(s[0])
# 40
ラベル名か番号かを明確に指定するにはat
, iat
を使う。loc
, iloc
でもよいが、at
, iat
のほうが高速。
print(s.at[0])
# 40
print(s.iat[0])
# 10
特に、末尾の値を取得しようとして[-1]
とすると-1
という名前のラベルの値の選択とみなされてしまうので注意。iat
を使えば問題ない。
# print(s[-1])
# KeyError: -1
print(s.iat[-1])
# 70
このように、行名・列名などが整数値の場合は混乱を避けるために、at
, iat
, loc
, iloc
を使ったほうがよい。