pandasで要素、行、列に関数を適用するmap, applymap, apply

Pythonの組み込み関数、自分で定義した関数を適用する場合は、以下のメソッドを使う。

  • Seriesの各要素に適用: map()
  • DataFrameの各要素に適用: applymap()
  • DataFrame, Seriesの各行・各列に適用: apply() 

    いずれのメソッドも、処理された新たなpandasオブジェクトを返し、元のオブジェクトは変更されない。dropna()やfillna()にあるような引数inplaceは存在しないので、元のオブジェクト自体を変更したい場合は、新たなオブジェクトを元のオブジェクトに代入して上書きする。
In [1]:
import pandas as pd
import numpy as np

df = pd.DataFrame({'a':[11, 21, 31],
                  'b':[12, 22, 32],
                  'c':[13, 23, 33],
                  'd':[14, 24, 34]})
print(df)
 
    a   b   c   d
0  11  12  13  14
1  21  22  23  24
2  31  32  33  34
 

Seriesの各要素に関数を適用: map()

Pythonの組み込み関数、無名関数(lambda)やdefで定義した関数をmap()の引数に渡す。

In [2]:
s = df['a']
print(s)

f_brackets = lambda x: '[{}]'.format(x)
print(s.map(f_brackets))
print(s.map(lambda x: '[{}]'.format(x)))

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    11
1    21
2    31
Name: a, dtype: int64
0    [11]
1    [21]
2    [31]
Name: a, dtype: object
0    [11]
1    [21]
2    [31]
Name: a, dtype: object
0      OneOne
1      TwoOne
2    ThreeOne
Name: a, dtype: object
In [3]:
df['col'] = ['PCB,MO(4) FH-3050の2次処理面 TO PCB,MO(1) FH-3050-1..',
             'PCB,MO(4) FH-3050の2次処理面 TO PCB,MO(1) FH-3050-1..','PCB,MO(4) FH-3050の2次処理面 TO PCB,MO(1) FH-3050-1..']
s = df['col'].map(lambda x: str(x).rpartition(' TO ')[0])
print(s)

#print(s.map(lambda x: str(x).rpartition(' TO ')[0]))
 
0    PCB,MO(4) FH-3050の2次処理面
1    PCB,MO(4) FH-3050の2次処理面
2    PCB,MO(4) FH-3050の2次処理面
Name: col, dtype: object
In [4]:
s = 'PCB,MO(4) FH-3050の1次処理面 TO PCB,MO(4) FH-3050の2次処理面'
df['col'] = [s, s, s]
print(s.find('の'))
print(s[:s.find('の')])
#def f_str(s):
#    return str(s)[:s.find('PCB,MO(4) FH-3050', s.find('TO'))] + s[s.find('PCB,MO(4) FH-3050', s.find('TO')) + len('PCB,MO(4) FH-3050')+1:]

s = df['col'].map(lambda s: str(s)[:s.find(s[:s.find('の')], s.find('TO'))] 
                  + s[s.find(s[:s.find('の')], s.find('TO')) + len(s[:s.find('の')])+1:])
print(s)
#s[:s.find('PCB,MO(4) FH-3050', s.find('TO'))] + s[s.find('PCB,MO(4) FH-3050', s.find('TO')) + len('PCB,MO(4) FH-3050')+1:]
 
17
PCB,MO(4) FH-3050
0    PCB,MO(4) FH-3050の1次処理面 TO 2次処理面
1    PCB,MO(4) FH-3050の1次処理面 TO 2次処理面
2    PCB,MO(4) FH-3050の1次処理面 TO 2次処理面
Name: col, dtype: object
In [5]:
s = 'PCB,MO(4) FH-3050の1次処理面 TO PCB,MO(1) FH-3050-1の2次処理面'
df['col'] = [s, s, s]
s = df['col'].map(lambda s: str(s).replace('次処理',''))
print(s)
 
0    PCB,MO(4) FH-3050の1面 TO PCB,MO(1) FH-3050-1の2面
1    PCB,MO(4) FH-3050の1面 TO PCB,MO(1) FH-3050-1の2面
2    PCB,MO(4) FH-3050の1面 TO PCB,MO(1) FH-3050-1の2面
Name: col, dtype: object
 

DataFrameの各要素に関数を適用: applymap()

map()と同じく、Pythonの組み込み関数、無名関数(lambda)やdefで定義した関数をapplymap()の引数に渡す。

In [6]:
df = pd.DataFrame({'a':[11, 21, 31],
                  'b':[12, 22, 32],
                  'c':[13, 23, 33],
                  'd':[14, 24, 34]})

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, Seriesの各行・各列に適用: apply()

一次元配列に適用可能な関数をapply()の引数に渡す。デフォルトでは各列に対して適用され、引数axis=1とすると各行に対して適用される。

In [7]:
f_maxmin = lambda x: max(x) - min(x)
print(df.apply(f_maxmin))

print(df.apply(f_maxmin, axis=1))
 
a    20
b    20
c    20
d    20
dtype: int64
0    3
1    3
2    3
dtype: int64
 

DataFrameの特定の行・列の要素に適用

DataFrameの特定の行・列の要素にのみ関数を適用するメソッドはないので、

  • 行・列を選択し、Seriesとしてmap()で関数を適用
  • 元の行・列に代入して上書き 

    という処理を行う。
In [8]:
df['b'] = df['b'].map(f_str)
print(df)

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  31  ThreeTwo  33  34
          a         b           c          d
0        11    OneTwo          13         14
1        21    TwoTwo          23         24
2  ThreeOne  ThreeTwo  ThreeThree  ThreeFour