pandas.DataFrame
の任意の位置のデータを取り出したり変更(代入)したりするには、at
, iat
, loc
, iloc
を使う。at()
ではなくat[]
のように記述する。
- pandas.DataFrame.at — pandas 2.0.3 documentation
- pandas.DataFrame.iat — pandas 2.0.3 documentation
- pandas.DataFrame.loc — pandas 2.0.3 documentation
- pandas.DataFrame.iloc — pandas 2.0.3 documentation
位置の指定方法および選択できる範囲に違いがある。
- 位置の指定方法
at
,loc
: 行名(行ラベル)、列名(列ラベル)iat
,iloc
: 行番号、列番号
- 選択し取得・変更できるデータ
at
,iat
: 単独の要素の値loc
,iloc
: 単独および複数の要素の値- リストやスライスで範囲を指定可能
- 単独の要素にアクセスする場合は
at
とiat
のほうが高速
目次
- at, iat: 単独の要素の値を選択、取得・変更
- loc, iloc: 単独および複数の要素の値を選択、取得・変更
- 単独の要素の値を選択
- 複数の要素の値を選択(リスト・スライスで範囲指定)
- 行・列を選択
- boolのリストによるマスク(ブーリアンインデックス)
- 行名・列名が重複している場合
- 番号と名前(ラベル)で位置を指定
- 行をpandas.Seriesで選択する際の暗黙の型変換
pandas.DataFrame
の行・列、pandas.Series
の要素を選択する場合はインデックス参照df[]
も使用できる。
- 関連記事: pandasのインデックス指定で行・列を抽出
なお、以前あったget_value()
およびix[]
は、バージョン1.0
で削除された。
本記事のサンプルコードのpandasのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。以下のpandas.DataFrame
を例とする。
import pandas as pdprint(pd.__version__)# 2.0.3df = 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
source: pandas_get_set_data.py
at, iat: 単独の要素の値を選択、取得・変更
at
は行名と列名で位置を指定する。
データを取得するだけでなく、その位置に新たな値を設定(代入)することもできる。
print(df.at['row_1', 'col_2'])# 12df.at['row_1', 'col_2'] = '0'print(df.at['row_1', 'col_2'])# 0
source: pandas_get_set_data.py
iat
は行番号と列番号で位置を指定する。行番号・列番号は0
始まり。
at
と同じく、データを取得するだけでなく、その位置に新たな値を設定(代入)できる。
print(df.iat[1, 2])# 0df.iat[1, 2] = '12'print(df.iat[1, 2])# 12
source: pandas_get_set_data.py
loc, iloc: 単独および複数の要素の値を選択、取得・変更
loc
とiloc
は、単独の値だけでなく範囲を指定して複数のデータを選択できる。loc
は行名と列名、iloc
は行番号と列番号で位置を指定する。
単独の要素の値を選択
単独の値にアクセスする場合はat
, iat
と同じ。処理速度はat
, iat
のほうが速い。
print(df.loc['row_1', 'col_2'])# 12print(df.iloc[1, 2])# 12
source: pandas_get_set_data.py
データを取得するだけでなく、その位置に新たな値を設定(代入)することもできる。
df.loc['row_1', 'col_2'] = '0'print(df.loc['row_1', 'col_2'])# 0df.iloc[1, 2] = '12'print(df.iloc[1, 2])# 12
source: pandas_get_set_data.py
複数の要素の値を選択(リスト・スライスで範囲指定)
loc
, iloc
では、行名や列番号などのスカラー値のほか、リスト[a, b, c, ...]
やスライスstart:stop:step
でデータの範囲・位置を指定して複数の値にアクセスできる。
スライスの書き方は通常のスライスと同じ。step
は省略可。
- 関連記事: Pythonのスライスによるリストや文字列の部分選択・代入
スライスstart:stop:step
で指定するとき、loc
(行名・列名)ではstop
の要素も含まれるので注意。iloc
(行番号・列番号)では通常のスライスと同様にstop
の一つ前まで。
また、リストで指定すると、行や列の順番は指定したリストの順番になる。
print(df.loc['row_1':'row_3', ['col_2', 'col_0']])# col_2 col_0# row_1 12 10# row_2 22 20# row_3 32 30print(df.iloc[1:3, [2, 0]])# col_2 col_0# row_1 12 10# row_2 22 20
スライスでstep
を指定すると、奇数行・偶数行を抽出したりできる。
print(df.iloc[::2, [0, 3]])# col_0 col_3# row_0 00 03# row_2 20 23# row_4 40 43print(df.iloc[1::2, [0, 3]])# col_0 col_3# row_1 10 13# row_3 30 33
source: pandas_get_set_data.py
複数の値を一括で変更することが可能。スカラー値を代入するとすべての要素がその値になる。範囲に対して代入する場合は、二次元リスト(リストのリスト)や二次元のNumPy配列ndarray
などを使う。
df.iloc[1:3, [2, 0]] = '0'print(df)# col_0 col_1 col_2 col_3# row_0 00 01 02 03# row_1 0 11 0 13# row_2 0 21 0 23# row_3 30 31 32 33# row_4 40 41 42 43df.iloc[1:3, [2, 0]] = [['12', '10'], ['22', '20']]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
source: pandas_get_set_data.py
なお、行・列をスカラー値で指定して一行・一列を選択するとpandas.Series
が返されるが、同じ一行・一列でも、スライスやリストで指定するとpandas.DataFrame
となる。
特に、行をpandas.Series
で取得すると暗黙の型変換が行われる可能性があるので要注意。詳細は後述。
print(df.loc['row_1', ['col_0', 'col_2']])print(type(df.loc['row_1', ['col_0', 'col_2']]))# col_0 10# col_2 12# Name: row_1, dtype: object# <class 'pandas.core.series.Series'>print(df.loc['row_1':'row_1', ['col_0', 'col_2']])print(type(df.loc['row_1':'row_1', ['col_0', 'col_2']]))# col_0 col_2# row_1 10 12# <class 'pandas.core.frame.DataFrame'>print(df.loc[['row_1'], ['col_0', 'col_2']])print(type(df.loc[['row_1'], ['col_0', 'col_2']]))# col_0 col_2# row_1 10 12# <class 'pandas.core.frame.DataFrame'>
source: pandas_get_set_data.py
行・列を選択
インデックス参照df[]
で行・列を選択できるが、以下の指定方法に限られる。
- 行の選択: 行名・行番号のスライス
- 列の選択: 列名、または、列名のリスト
詳細は以下の記事を参照。
- 関連記事: pandasのインデックス指定で行・列を抽出
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 33print(df[1:3])# col_0 col_1 col_2 col_3# row_1 10 11 12 13# row_2 20 21 22 23print(df['col_1'])# row_0 01# row_1 11# row_2 21# row_3 31# row_4 41# Name: col_1, dtype: objectprint(df[['col_1', 'col_3']])# col_1 col_3# row_0 01 03# row_1 11 13# row_2 21 23# row_3 31 33# row_4 41 43
source: pandas_get_set_data.py
loc
, iloc
を使うと、より柔軟に行・列を指定できる。
loc
, iloc
で列の指定を省略すると行が選択できる。行名・行番号単独での指定やリストによる指定も可能。
print(df.loc['row_2'])# col_0 20# col_1 21# col_2 22# col_3 23# Name: row_2, dtype: objectprint(df.iloc[[1, 3]])# col_0 col_1 col_2 col_3# row_1 10 11 12 13# row_3 30 31 32 33
source: pandas_get_set_data.py
loc
, iloc
で行の指定を:
(全体のスライス)にすると列を選択できる。スライスによる指定やiloc
での列番号による指定も可能。
print(df.loc[:, 'col_1':])# 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 43print(df.iloc[:, 2])# row_0 02# row_1 12# row_2 22# row_3 32# row_4 42# Name: col_2, dtype: object
source: pandas_get_set_data.py
上述のように、行・列をスカラー値で指定して一行・一列を選択するとpandas.Series
が返されるが、同じ一行・一列でも、スライスやリストで指定するとpandas.DataFrame
となる。
特に、行をpandas.Series
で選択すると暗黙の型変換が行われる可能性があるので要注意。詳細は後述。
print(df.loc['row_2'])print(type(df.loc['row_2']))# col_0 20# col_1 21# col_2 22# col_3 23# Name: row_2, dtype: object# <class 'pandas.core.series.Series'>print(df.loc['row_2':'row_2'])print(type(df.loc['row_2':'row_2']))# col_0 col_1 col_2 col_3# row_2 20 21 22 23# <class 'pandas.core.frame.DataFrame'>print(df.loc[['row_2']])print(type(df.loc[['row_2']]))# col_0 col_1 col_2 col_3# row_2 20 21 22 23# <class 'pandas.core.frame.DataFrame'>
source: pandas_get_set_data.py
boolのリストによるマスク(ブーリアンインデックス)
loc
, iloc
では、bool
値(True
, False
)のリストやnumpy.ndarray
を指定してデータをマスクすることができる。例では行に指定しているが、列に指定することも可能。
l_bool = [True, False, False, True, False]print(df.loc[l_bool, ['col_0', 'col_2']])# col_0 col_2# row_0 00 02# row_3 30 32print(df.iloc[l_bool, [0, 2]])# col_0 col_2# row_0 00 02# row_3 30 32
source: pandas_get_set_data.py
要素数が一致していないとエラー。
l_bool_wrong = [True, False, False]# print(df.loc[l_bool_wrong, ['col_0', 'col_2']])# IndexError: Boolean index has wrong length: 3 instead of 5
source: pandas_get_set_data.py
loc
ではbool
値を要素とするpandas.Series
も指定可能。順番ではなくラベルを元にマスクされる。
s_bool = pd.Series([True, False, False, True, False], index=reversed(df.index))print(s_bool)# row_4 True# row_3 False# row_2 False# row_1 True# row_0 False# dtype: boolprint(df.loc[s_bool, ['col_0', 'col_2']])# col_0 col_2# row_1 10 12# row_4 40 42
source: pandas_get_set_data.py
iloc
ではpandas.Series
は指定不可。
# print(df.iloc[s_bool, [0, 2]])# ValueError: Location based indexing can only have [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types
source: pandas_get_set_data.py
loc
でも要素数やラベルが一致していないとエラー。
s_bool_wrong = pd.Series([True, False, False], index=['row_0', 'row_1', 'row_2'])# print(df.loc[s_bool_wrong, ['col_0', 'col_2']])# IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).s_bool_wrong = pd.Series([True, False, False, True, False], index=['row_0', 'row_1', 'row_2', 'row_3', 'XXX'])# print(df.loc[s_bool_wrong, ['col_0', 'col_2']])# IndexingError: Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).
source: pandas_get_set_data.py
行名・列名が重複している場合
行名index
、列名columns
に重複する値が含まれていてもエラーにならない。
重複する行名・列名を持つpandas.DataFrame
を例とする。
df_duplicated = df.rename(columns={'col_2': 'col_1'}, index={'row_3': 'row_2'})print(df_duplicated)# col_0 col_1 col_1 col_3# row_0 00 01 02 03# row_1 10 11 12 13# row_2 20 21 22 23# row_2 30 31 32 33# row_4 40 41 42 43
source: pandas_get_set_data.py
at
, loc
では、重複したラベルを指定すると該当の複数要素が選択される。
print(df_duplicated.at['row_2', 'col_1'])print(type(df_duplicated.at['row_2', 'col_1']))# col_1 col_1# row_2 21 22# row_2 31 32# <class 'pandas.core.frame.DataFrame'>print(df_duplicated.loc[:'row_2', ['col_1', 'col_3']])print(type(df_duplicated.loc[:'row_2', ['col_1', 'col_3']]))# col_1 col_1 col_3# row_0 01 02 03# row_1 11 12 13# row_2 21 22 23# row_2 31 32 33# <class 'pandas.core.frame.DataFrame'>
source: pandas_get_set_data.py
iat
, iloc
で行番号・列番号で指定する場合は、位置を基準とするのでラベルが重複していても特に問題ない。
print(df_duplicated.iat[2, 1])# 21print(df_duplicated.iloc[:2, [1, 3]])# col_1 col_3# row_0 01 03# row_1 11 13
source: pandas_get_set_data.py
混乱のもとになるので、強い理由がないのであれば行名・列名は一意の値にしたほうがよい。
行名・列名が一意の値になっている(重複していない)かどうかはindex.is_unique
, columns.is_unique
で確認できる。
print(df_duplicated.index.is_unique)# Falseprint(df_duplicated.columns.is_unique)# False
source: pandas_get_set_data.py
行名・列名の変更については以下の記事を参照。
- 関連記事: pandas.DataFrameの行名・列名の変更
番号と名前(ラベル)で位置を指定
行番号と列名(列ラベル)のように番号と名前(ラベル)の組み合わせで位置を指定したい場合、at
またはloc
とindex
, column
属性を使う方法がある。
index
, column
属性で行番号または列番号からその行名・列名を取得できる。
print(df.index[2])# row_2print(df.columns[2])# col_2
source: pandas_get_set_data.py
スライスやリストを指定して複数の行名・列名を取得することも可能。
print(df.index[1:4])# Index(['row_1', 'row_2', 'row_3'], dtype='object')print(df.columns[[1, 3]])# Index(['col_1', 'col_3'], dtype='object')
source: pandas_get_set_data.py
これを利用すると、at
またはloc
で番号と名前の組み合わせで位置を指定できる。
print(df.at[df.index[2], 'col_2'])# 22print(df.loc[['row_0', 'row_3'], df.columns[[1, 3]]])# col_1 col_3# row_0 01 03# row_3 31 33
source: pandas_get_set_data.py
以下のように[]
やloc
,iloc
を繰り返す書き方もできるが、これはchained indexingと呼ばれ、SettingWithCopyWarning
という警告の要因となる。
- 関連記事: pandasのSettingWithCopyWarningの対処法
データを取得・確認するだけであれば問題ないが、新たな値を代入すると想定外の結果となる場合があるので注意。
print(df['col_2'][2])# 22print(df.loc[['row_0', 'row_3']].iloc[:, [1, 3]])# col_1 col_3# row_0 01 03# row_3 31 33
source: pandas_get_set_data.py
行をpandas.Seriesで選択する際の暗黙の型変換
loc
やiloc
で一行を選択してpandas.Series
で取得する場合、元のpandas.DataFrame
の各列のデータ型dtype
が異なっていると暗黙の型変換が行われる。
- 関連記事: pandasのデータ型dtype一覧とastypeによる変換(キャスト)
整数int
の列と浮動小数点数float
の列を持つpandas.DataFrame
を例とする。
df_mix = pd.DataFrame({'col_int': [0, 1, 2], 'col_float': [0.1, 0.2, 0.3]}, index=['A', 'B', 'C'])print(df_mix)# col_int col_float# A 0 0.1# B 1 0.2# C 2 0.3print(df_mix.dtypes)# col_int int64# col_float float64# dtype: object
loc
やiloc
で一行をpandas.Series
として取得すると、そのデータ型はfloat
となる。int
の列にあった要素はfloat
に変換される。
print(df_mix.loc['B'])# col_int 1.0# col_float 0.2# Name: B, dtype: float64print(type(df_mix.loc['B']))# <class 'pandas.core.series.Series'>
以下のように[]
を続けて書くと、float
に変換されたpandas.Series
の要素が返される。元の型と異なる型として要素の値が返されてしまうので要注意。
print(df_mix.loc['B']['col_int'])# 1.0print(type(df_mix.loc['B']['col_int']))# <class 'numpy.float64'>
[]
やloc
,iloc
を繰り返す書き方は避けてat
やiat
を使えば、元の型の要素が取得できる。
print(df_mix.at['B', 'col_int'])# 1print(type(df_mix.at['B', 'col_int']))# <class 'numpy.int64'>
なお、loc
やiloc
においてリストやスライスで一行を選択した場合は、pandas.Series
ではなくpandas.DataFrame
が返される。この場合は元のデータ型dtype
が保持される。
print(df_mix.loc[['B']])# col_int col_float# B 1 0.2print(type(df_mix.loc[['B']]))# <class 'pandas.core.frame.DataFrame'>print(df_mix.loc[['B']].dtypes)# col_int int64# col_float float64# dtype: object