【Python入門】pandasでlocとilocを使って値を取得する

loc pandas

pandas.DataFrameの任意の行・列を指定してデータを取得・変更します。

機械学習の前処理では、条件に合う特定の行・列を抽出する場合や、条件分岐でデータをふるい分ける場合などに使用します。

行・列を指定する方法

pandas.DataFrameで作成したデータの一部を取得して確認したり、データを変更したい場合は、データが格納されている位置を特定して抽出します。

・行ラベル(行名)、列ラベル(列名)で指定: loc、at
・行番号、列番号で指定: iloc、iat

行ラベルと行番号は混乱しやすいので、違いを確認します。

行番号と行ラベルが同じ

pandas.DataFrameを作成するとき、行ラベル(行名)を指定しないと0からの連番が割り振られます。
この場合は、以下のように行番号と行ラベルが同じになっています。

import pandas as pd

data_abc = ['a', 'b', 'c', 'd', 'e']
data_123 = [1, 2, 3, 4, 5]
sample = pd.DataFrame({'abc': data_abc, '123':data_123})
sample
        abc	123
0	a	1
1	b	2
2	c	3
3	d	4
4	e	5

左端の列がインデックス(行ラベル・行名)です。
インデックスは、縦方向のラベルで、列名ではないです。
カラムが、横方向のラベル。

ilocで行番号を指定して取得:iloc[行番号, 列番号(省略可)]

行番号は0から始まる整数です。
2行目(行番号「1」)を取得してみます。

sample.iloc[1]
abc    b
123    2
Name: 1, dtype: object


0列と1列を、列番号で指定します。
リスト形式で取得したい列番号を指定します。

sample.iloc[1, [0, 1]]
abc    b
123    2
Name: 1, dtype: object


列番号は、get_locメソッドで取得できます。

col_abc = sample.columns.get_loc('abc')
col_abc
0


get_locメソッド を使用すると、列の追加や削除があっても正確な列番号を指定できます。

# 列番号を取得
col_abc = sample.columns.get_loc('abc')
col_123 = sample.columns.get_loc('123')

sample.iloc[1, [col_abc, col_123]]
abc    b
123    2
Name: 1, dtype: object


列番号を:(コロン)にすると、すべて取得できます。

sample.iloc[1, :]
abc    b
123    2
Name: 1, dtype: object

locで行ラベルを指定して取得:loc[行ラベル, 列ラベル(省略可)]

行ラベルで行、列ラベルで列を指定します。
この例のデータは、行番号と行ラベルは同じ値であることに注意してください。
第1引数の「1」は、行ラベルを指定しています。

sample.loc[1, ['abc', '123']]
abc    b
123    2
Name: 1, dtype: object

ilocと同様に、第2引数を省略したり、第2引数を:(コロン)にすると、すべての列を取得できます。

行番号と行ラベルが異なる

データsampleの奇数行を抽出して、データkisuuを作成します。
列ラベル「123」が1からの連番なので、2で割った余りが1となる行が奇数行です。

kisuu = sample[sample['123']%2 == 1].copy()
kisuu
        abc	123
0	a	1
2	c	3
4	e	5

ilocで行番号を指定して取得:iloc[行番号, 列番号(省略可)]

行番号は0から始まる整数です。
2行目 (行番号「1」) を取得してみます。

kisuu.iloc[1]
abc    c
123    3
Name: 2, dtype: object

行番号「1」を指定して、行ラベル「2」の行が取得できました。
ilocで指定するのは行番号なので、単純に縦方向の連番となります。

locで行ラベルを指定して取得:loc[行ラベル, 列ラベル(省略可)]

行ラベル「2」を指定して行を取得してみます。

kisuu.loc[2]
abc    c
123    3
Name: 2, dtype: object

行ラベル「2」を指定して、行番号「1」の行が取得できました。
locで指定するのは行ラベルなので、インデックスで表示される値となります。

取得・変更するデータ

pandas.DataFrameのデータを取得するとき、要素の数によってプロパティが異なります。

・要素の数が1つ: at[行ラベル, 列ラベル(省略不可)]、iat[行番号, 列番号(省略不可)]
・要素の数が複数: loc [行ラベル, 列ラベル (省略可) ] 、iloc [行番号, 列番号(省略可)]

loc、ilocで1列のみを指定すると、at、iatと同様に要素の数が1つのデータを取得できます。
要素の数が1つの場合は、 at、iat の方が高速。

行ラベルが重複する場合

pandas.DataFrameを作成するときに、インデックスを指定していなければ、0からの連番になりますが、カラムと同じく行ごとにラベルを付けることができます。
また、複数の行に同じラベルを使用することもできます。

data_abc = ['a', 'b', 'c', 'd', 'e']
data_123 = [1, 2, 3, 4, 5]
data_index = [1, 2, 3, 1, 2]
sample_dup = pd.DataFrame({'abc': data_abc, '123':data_123}, index=data_index)
sample_dup
	abc	123
1	a	1
2	b	2
3	c	3
1	d	4
2	e	5

行番号「0, 4」は、同じ行ラベル「1」になっています。
locで行ラベル「1」を取得してみます。

sample_dup.loc[1]
        abc	123
1	a	1
1	d	4

locで、重複した行ラベルを指定すると、複数の値が取得されます。

pandas.DataFrameから、for文で1行ずつ取り出す処理などではエラーとなりますので、行ラベルでの指定は注意が必要です。

行・列を指定して取得・変更するコード例

使用するデータを作成します。
行ラベルを意識するため、行ラベルは「row+行番号」とします。

data_abc = ['a', 'b', 'c', 'd', 'e']
data_123 = [1, 2, 3, 4, 5]
data_index = ['row0', 'row1', 'row2', 'row3', 'row4']
sample = pd.DataFrame({'abc': data_abc, '123':data_123}, index=data_index)
sample
	abc	123
row0	a	1
row1	b	2
row2	c	3
row3	d	4
row4	e	5

for文で、ilocを使用して値を変更

行番号を指定して取得した行の、列番号「1」の値を10倍します。

len(sample)で、データの行数を取得。>> 5
range(行数)で、行番号のリストを取得。 >> [0, 1, 2, 3, 4]

for i in range(len(sample)):
    sample.iloc[i,1] = sample.iloc[i, 1] * 10
    print(i, sample.iloc[i,1])
0 10
1 20
2 30
3 40
4 50

for文で、locを使用して値を変更

データsampleを更に加工します。
行ラベルを指定して取得した行の、列ラベル「123」の値を10倍します。

sample.indexで、行ラベルのリストを取得。 >> [row0, row1, row2, row3, row4]

for i in sample.index:
    sample.loc[i, '123'] = sample.loc[i, '123'] * 10
    print(i, sample.loc[i, '123'])
row0 100
row1 200
row2 300
row3 400
row4 500

行ラベルに重複がなかったので、エラーは発生しませんでした。
行ラベルが重複していないかは、sample.index.is_uniqueで確認できます。
重複していない場合は、True。
重複している場合は、False。

余談

pandas.DataFrameのデータ処理をfor文を使って行いました。
for文は、各行・各列に対する処理が直感的に理解しやすいですが、処理速度が遅いです。
少ないデータ数なら問題はありませんし、気長に処理を待つことも1つの選択肢です。

処理時間が待てなくなってきたときは、
・pandas.DataFrameのスライシングを使用する
・pandas.DataFrameのapplyメソッドを使用する
など、処理速度の速い方法を選択してみるとよいです。

参考までに、applyメソッドの例です。
for文の処理をぐるぐる回す感じをイメージして、各行の値を無名関数に入れてください。

f_X10 = lambda x: x*10     # 値を10倍にする無名関数。
sample['123'] = sample['123'].apply(f_X10)     # 無名関数を列ラベル「123」に適用
sample


おすすめは、スライシングです。

sample.iloc[:, 1] = sample.iloc[:, 1] * 10
sample

まとめ

  • 行ラベル(行名)・列ラベル(列名)と、行番号・列番号の違いを理解できた
  • pandas.DataFrameのデータを、任意の位置で取得・変更することができた

関連情報

タイトルとURLをコピーしました