note.nkmk.me

pandasで任意の位置の値を取得・変更するat, iat, loc, iloc

Date: 2017-11-15 / Modified: 2018-02-12 / tags: Python, pandas
このエントリーをはてなブックマークに追加
スポンサーリンク

pandas.DataFrameの任意の位置のデータを選択し処理

pandas.DataFrameの任意の位置のデータを取り出したり変更(代入)したりする場合、pandas.DataFrameのプロパティ、at, iat, loc, ilocを使う。at()ではなくat[]のように記述する。

以下のような違いがある。

  • 位置の指定方法
    • at, loc : 行ラベル(行名)、列ラベル(列名)
    • iat, iloc : 行番号、列番号
  • 選択し取得・変更できるデータ
    • at, iat : 単独の要素の値
    • loc, iloc : 単独および複数の要素の値
      • 行全体・列全体を選択して取得・変更可能
      • リスト、スライスで範囲を指定可能
  • その他
    • 処理速度はatiatのほうがlocilocよりも高速
    • ラベルと番号を組み合わせて位置を指定したい場合はatまたはlocindexcolumnを組み合わせる(最後に説明)

pandas.DataFrameの行全体・列全体、pandas.Seriesの要素の値を選択・取得する場合は直接インデックスdf[]も使用できる。

なお、DataFrame.get_value()DataFrame.ix[]もあるが、どちらも最新のバージョンでは非推奨(Deprecated)になっている。これから新しく書くコードにはat, iat, loc, ilocを使うほうがいいだろう。

今回のサンプルコードでは以下のcsvデータをread_csvで読み込んで使用する。

引数index_colで最初の列をindexとしている。

import pandas as pd

df = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=0)
print(df)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70
# Dave      68    TX     70
# Ellen     24    CA     88
# Frank     30    NY     57

行ラベル(index)、列ラベル(columns)の値はそれぞれ以下のようになる。

print(df.index.values)
# ['Alice' 'Bob' 'Charlie' 'Dave' 'Ellen' 'Frank']

print(df.columns.values)
# ['age' 'state' 'point']

既存のDataFrameの列をset_index()indexに指定することもできる。

at, iat : 単独の要素の値を選択、取得・変更

atは行ラベルと列ラベルで位置を指定する。

データを取得するだけでなく、その位置に新たな値を設定(代入)することもできる。

print(df.at['Bob', 'age'])
print(df.at['Dave', 'state'])
# 42
# TX

df.at['Bob', 'age'] = 60
print(df.at['Bob', 'age'])
# 60

iatは行番号と列番号で位置を指定する。行番号・列番号は0はじまり。

iatatと同じく、データを取得するだけでなく、その位置に新たな値を設定(代入)することができる。

print(df.iat[1, 0])
print(df.iat[3, 1])
# 60
# TX

df.iat[1, 0] = 42
print(df.iat[1, 0])
# 42

loc, iloc : 単独および複数の要素の値を選択、取得・変更

locilocは単独の値だけでなく、範囲を指定して複数のデータを選択することができる。

locは行ラベルと列ラベルで位置を指定、ilocは行番号と列番号で位置を指定する。

単独の要素の値を選択

単独の値にアクセスする場合はatiatと同じ。処理速度はatiatのほうが速い。

print(df.loc['Bob', 'age'])
print(df.iloc[3, 1])
# 42
# TX

データを参照するだけでなく、その位置に新たな値を設定(代入)することもできる。

df.loc['Bob', 'age'] = 60
print(df.loc['Bob', 'age'])
# 60

df.iloc[1, 0] = 42
print(df.iloc[1, 0])
# 42

複数の要素の値を選択

複数の値にアクセスする場合は、リスト[x, y]やスライスstart:stop:stepでデータの範囲・位置を指定する。参照される値はpandas.Seriesまたはpandas.DataFrameになる。

スライスは通常のスライスと同じ書き方。stepは省略可。

スライスstart:stop:stepで指定するとき、locで行ラベル・列ラベルを使う場合はstopまで含まれるが、ilocで行番号・列番号を使う場合はstopの一つ前までになるので注意。

print(df.loc['Bob':'Dave', 'age'])
print(type(df.loc['Bob':'Dave', 'age']))
# name
# Bob        42
# Charlie    18
# Dave       68
# Name: age, dtype: int64
# <class 'pandas.core.series.Series'>

print(df.loc[:'Dave', ['age', 'point']])
print(type(df.loc[:'Dave', 'age':'point']))
#          age  point
# name               
# Alice     24     64
# Bob       42     92
# Charlie   18     70
# Dave      68     70
# <class 'pandas.core.frame.DataFrame'>

print(df.iloc[:3, [0, 2]])
print(type(df.iloc[:3, [0, 2]]))
#          age  point
# name               
# Alice     24     64
# Bob       42     92
# Charlie   18     70
# <class 'pandas.core.frame.DataFrame'>

stepを指定すると、奇数行または偶数行を抽出して取得したりもできる。

print(df.iloc[::2, 0])
print(type(df.iloc[::2, 0]))
# name
# Alice      24
# Charlie    18
# Ellen      24
# Name: age, dtype: int64
# <class 'pandas.core.series.Series'>

print(df.iloc[1::2, 0])
print(type(df.iloc[1::2, 0]))
# name
# Bob      42
# Dave     68
# Frank    30
# Name: age, dtype: int64
# <class 'pandas.core.series.Series'>

複数の値を一括で変更することも可能。

df.loc['Bob':'Dave', 'age'] = [20, 30, 40]
print(df.loc['Bob':'Dave', 'age'])
# name
# Bob        20
# Charlie    30
# Dave       40
# Name: age, dtype: int64

行・列を選択

行単位・列単位で選択する場合は直接インデックス参照df[]が使えるが、以下の指定方法に限られる。

  • 行の選択 : 行名・行番号のスライス
  • 列の選択 : 列名、または、列名のリスト
print(df['Bob':'Ellen'])
#          age state  point
# name                     
# Bob       20    CA     92
# Charlie   30    CA     70
# Dave      40    TX     70
# Ellen     24    CA     88

print(df[:3])
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       20    CA     92
# Charlie   30    CA     70

print(df['age'])
# name
# Alice      24
# Bob        20
# Charlie    30
# Dave       40
# Ellen      24
# Frank      30
# Name: age, dtype: int64

print(df[['age', 'point']])
#          age  point
# name               
# Alice     24     64
# Bob       20     92
# Charlie   30     70
# Dave      40     70
# Ellen     24     88
# Frank     30     57

詳細は以下の記事を参照。

loc, ilocで行全体・列全体を選択する場合はインデックス参照df[]よりも柔軟に指定することができる。

loc, ilocで列の指定を省略すると行全体の参照になる。インデックス参照では出来ない単独行の選択やリストでの複数行選択も可能。

print(df.loc['Bob'])
print(type(df.loc['Bob']))
# age      20
# state    CA
# point    92
# Name: Bob, dtype: object
# <class 'pandas.core.series.Series'>

print(df.iloc[[1, 4]])
print(type(df.iloc[[1, 4]]))
#        age state  point
# name                   
# Bob     20    CA     92
# Ellen   24    CA     88
# <class 'pandas.core.frame.DataFrame'>

loc, ilocで行の指定を:(全体のスライス)にすると列全体を参照できる。インデックス参照では出来ないスライスが使える。ilocで列番号を使うことも可能。

print(df.loc[:, 'age':'point'])
print(type(df.loc[:, 'age':'point']))
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       20    CA     92
# Charlie   30    CA     70
# Dave      40    TX     70
# Ellen     24    CA     88
# Frank     30    NY     57
# <class 'pandas.core.frame.DataFrame'>

print(df.iloc[:, [0, 2]])
print(type(df.iloc[:, [0, 2]]))
#          age  point
# name               
# Alice     24     64
# Bob       20     92
# Charlie   30     70
# Dave      40     70
# Ellen     24     88
# Frank     30     57
# <class 'pandas.core.frame.DataFrame'>

行名・列名が重複した値を持っている場合

重複する値を持つ行や列もindexcolumnsに指定できる。

重複した値を持つ列をindexに指定した場合を例とする。

df_state = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=2)
print(df_state)
#           name  age  point
# state                     
# NY       Alice   24     64
# CA         Bob   42     92
# CA     Charlie   18     70
# TX        Dave   68     70
# CA       Ellen   24     88
# NY       Frank   30     57

print(df_state.index.values)
# ['NY' 'CA' 'CA' 'TX' 'CA' 'NY']

atで重複した列名を指定すると、numpy.ndarrayで複数の値が返ってくる。

print(df_state.at['NY', 'age'])
print(type(df_state.at['NY', 'age']))
# [24 30]
# <class 'numpy.ndarray'>

locで重複した列名を指定すると、pandas.DataFrameまたはpandas.Seriesで返ってくる。

print(df_state.loc['NY', 'age'])
print(type(df_state.loc['NY', 'age']))
# state
# NY    24
# NY    30
# Name: age, dtype: int64
# <class 'pandas.core.series.Series'>

print(df_state.loc['NY', ['age', 'point']])
print(type(df_state.loc['NY', ['age', 'point']]))
#        age  point
# state            
# NY      24     64
# NY      30     57
# <class 'pandas.core.frame.DataFrame'>

iatilocで列番号で指定する場合は、値が重複していても特に関係ない。

print(df_state.iat[0, 1])
# 24

列ラベル・行ラベルが一意の値になっている(重複していない)かどうかはindex.is_unique, columns.is_uniqueで確認できる。

print(df_state.index.is_unique)
# False

print(df_state.columns.is_unique)
# True

番号とラベルで位置を指定する

行番号と列ラベルのように番号とラベルの組み合わせで位置を指定したい場合、atまたはlocindexcolumnを使う方法がある。

indexcolumnで行番号または列番号からその行ラベル、列ラベルを取得できる。

print(df)
#          age state  point
# name                     
# Alice     24    NY     64
# Bob       20    CA     92
# Charlie   30    CA     70
# Dave      40    TX     70
# Ellen     24    CA     88
# Frank     30    NY     57

print(df.index[2])
# Charlie

print(df.columns[1])
# state

これとatまたはlocを利用して、番号とラベルの組み合わせで位置を指定できる。

print(df.at[df.index[2], 'age'])
# 30

print(df.loc[['Alice', 'Dave'], df.columns[1]])
# name
# Alice    NY
# Dave     TX
# Name: state, dtype: object

取得したい要素の範囲にもよるが、ほかにもindexcolumnを使わない様々な書き方が可能。

pandas.DataFrameからpandas.Seriesを選択し、さらにそのpandas.Seriesから値を選択して取得する。

print(df['age'][2])
# 30

print(df.age[2])
# 30

locilocを繰り返し適用して範囲を指定する。

print(df.loc[['Alice', 'Dave']].iloc[:, 1])
# name
# Alice    NY
# Dave     TX
# Name: state, dtype: object
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事