pandasで要素、行、列に関数を適用するmap, applymap, apply
適用する関数、対象による違い
pandasのオブジェクト(pandas.DataFrame
, pandas.Series
)に関数を適用する場合、どんな関数を適用するか、要素・行・列のいずれに適用するかによって、使うメソッドなどが異なる。
- NumPyの関数の引数にpandasオブジェクトを指定
- 関数の引数にpandasオブジェクトを指定可能
- 関数の種類および引数の設定によって要素・行・列いずれに適用されるかが異なる
- pandasオブジェクトのメソッドとして用意されている関数もある
- pandasオブジェクトのメソッドで関数を適用
- 要素(スカラー値)に対する関数
Series
の各要素に適用:map()
,apply()
DataFrame
の各要素に適用:applymap()
- 行・列(一次元配列)に対する関数
DataFrame
の各行・各列に適用:apply()
- 要素(スカラー値)に対する関数
今回は以下のcsvファイルを読み込んで例を示す。
a,b,c,d
11,12,13,14
21,22,23,24
31,32,33,34
import pandas as pd
import numpy as np
df = pd.read_csv('data/src/sample_header.csv')
print(df)
# a b c d
# 0 11 12 13 14
# 1 21 22 23 24
# 2 31 32 33 34
NumPyの関数の引数にpandasオブジェクトを指定
NumPyの関数の引数にpandasオブジェクトを指定することができる。
要素に適用
NumPyのユニバーサル関数(ufunc: 配列の要素に適用される関数)はpandasオブジェクトの各要素に適用される。
絶対値(fabs()
)や平方根(sqrt()
)、log(log()
)など。
print(np.sqrt(df))
# a b c d
# 0 3.316625 3.464102 3.605551 3.741657
# 1 4.582576 4.690416 4.795832 4.898979
# 2 5.567764 5.656854 5.744563 5.830952
行・列に適用
NumPy配列の要素全体から値を算出する関数の引数にpandasオブジェクトを指定すると、デフォルトではpandasオブジェクトの各列に対して適用される。引数axis=1
とすると各行に対して適用される。
最大(amax()
)や最小(amin()
)、平均(mean()
)など。
print(np.amax(df))
# a 31
# b 32
# c 33
# d 34
# dtype: int64
print(np.mean(df, axis=1))
# 0 12.5
# 1 22.5
# 2 32.5
# dtype: float64
(おまけ)pandas.DataFrame、pandas.Seriesのメソッド
最大、最小、平均、分散などはpandasオブジェクトのメソッドとしても準備されているので、そちらを使ってもいい。その他のメソッドについては以下のリンク参照。
この場合も、デフォルトでは各列に対して適用され、引数axis=1
とすると各行に対して適用される。
print(df.max())
# a 31
# b 32
# c 33
# d 34
# dtype: int64
print(df.max(axis=1))
# 0 14
# 1 24
# 2 34
# dtype: int64
pandasオブジェクトのメソッドで関数を適用
pandasオブジェクトのメソッドを使って要素や行・列に関数を適用することが可能。Pythonの組み込み関数、自分で定義した関数を適用できる。NumPyの関数もOK。
Series
の各要素に適用:map()
,apply()
DataFrame
の各要素に適用:applymap()
DataFrame
の各行・各列に適用:apply()
いずれのメソッドも、処理された新たなpandasオブジェクトを返し、元のオブジェクトは変更されない。dropna()
やfillna()
にあるような引数inplace
は存在しないので、元のオブジェクト自体を変更したい場合は、
df = df.applymap(function)
のように、新たなオブジェクトを元のオブジェクトに代入して上書きする。
Seriesの各要素に関数を適用: map(), apply()
Pythonの組み込み関数、無名関数(lambda
)やdef
で定義した関数をmap()
またはapply()
の引数に渡す。
s = df['a']
print(s)
# 0 11
# 1 21
# 2 31
# Name: a, dtype: int64
f_brackets = lambda x: '[{}]'.format(x)
print(s.map(f_brackets))
# 0 [11]
# 1 [21]
# 2 [31]
# Name: a, dtype: object
def f_str(x):
return str(x).replace('1', 'One').replace('2', 'Two').replace('3', 'Three').replace('4', 'Four')
print(s.map(f_str))
# 0 OneOne
# 1 TwoOne
# 2 ThreeOne
# Name: a, dtype: object
map()
の場合、引数に辞書dict
を指定すると要素の置換となる。詳細は以下の記事を参照。
また、文字列に対する置換などの処理は文字列メソッドとして用意されている。
DataFrameの各要素に関数を適用: applymap()
Pythonの組み込み関数、無名関数(lambda
)やdef
で定義した関数をapplymap()
の引数に渡す。
f_oddeven = lambda x: 'odd' if x % 2 == 1 else 'even'
print(df.applymap(f_oddeven))
# a b c d
# 0 odd even odd even
# 1 odd even odd even
# 2 odd even odd even
DataFrameの各行・各列に適用: apply()
一次元配列に適用可能な関数をapply()
の引数に渡す。デフォルトでは各列に対して適用され、引数axis=1
とすると各行に対して適用される。
f_maxmin = lambda x: max(x) - min(x)
print(df.apply(f_maxmin))
# a 20
# b 20
# c 20
# d 20
# dtype: int64
print(df.apply(f_maxmin, axis=1))
# 0 3
# 1 3
# 2 3
# dtype: int64
DataFrameの特定の行・列の要素に適用
DataFrame
の特定の行・列の要素にのみ関数を適用するメソッドはないので、
- 行・列を選択し、
Series
としてmap()
またはapply()
で関数を適用 - 元の行・列に代入して上書き
という処理を行う。
df['b'] = df['b'].map(f_str)
print(df)
# a b c d
# 0 11 OneTwo 13 14
# 1 21 TwoTwo 23 24
# 2 31 ThreeTwo 33 34
df.iloc[2] = df.iloc[2].map(f_str)
print(df)
# a b c d
# 0 11 OneTwo 13 14
# 1 21 TwoTwo 23 24
# 2 ThreeOne ThreeTwo ThreeThree ThreeFour