Pynote

Python、機械学習、画像処理について

pandas - apply、applymap、map, pipe の使い方

DataFrame.apply

DataFrame.apply は DataFrame の各行または各列に対して指定した関数を適用して、その結果を返す。

DataFrame.apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)

行ごとに関数を適用する。

axis=0 または axis="index" を指定すると、行ごとに指定した関数を適用する。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

print(df.apply(np.sum, axis=0))  # 列ごと
# 0    12
# 1    15
# 2    18
# dtype: int64

print(df.apply(np.sum, axis="index"))  # 列ごと
# 0    12
# 1    15
# 2    18
# dtype: int64

列ごとに関数を適用する。

axis=1 または axis="columns" を指定すると、行ごとに指定した関数を適用する。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

print(df.apply(np.sum, axis=1))  # 行ごと
# 0     6
# 1    15
# 2    24
# dtype: int64

print(df.apply(np.sum, axis="columns"))  # 行ごと
# 0     6
# 1    15
# 2    24
# dtype: int64

raw: 関数に pandas.Series として渡すか、numpy 配列として渡すか

raw=True の場合、numpy 配列として関数に渡される。
numpy の関数を適用する場合はこのほうが高速に処理できる。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])


def func(s):
    print(type(s))  # 渡ってきた型を print する。
    return 0


df.apply(func, raw=False)
# <class 'pandas.core.series.Series'>
# <class 'pandas.core.series.Series'>
# <class 'pandas.core.series.Series'>

df.apply(func, raw=True)
# <class 'numpy.ndarray'>
# <class 'numpy.ndarray'>
# <class 'numpy.ndarray'>

関数に追加の引数を渡す。

apply に指定した関数には、第1引数に行または列が渡されるが、他に引数がある場合は、次のように指定する。
位置引数の場合は args にタプルで指定する。
キーワード引数の場合は、apply にキーワード引数として指定する。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])


def func(a, b, c):
    print(f"b: {b}, c: {c}")  # # b: 2, c: test
    return a ** b


# apply() に与えた args とキーワード引数に基づき、
# func(series, 2, c='test') として呼び出される。
print(df.apply(func, args=(2,), c="test"))
#     0   1   2
# 0   1   4   9
# 1  16  25  36
# 2  49  64  81

返り値の形状

指定する関数の返り値による。
例えば、numpy.sum のように1次元配列を渡すと、スカラーを返す関数の場合、apply の返り値は Series になる。
numpy.sqrt のように1次元配列を渡すと、要素ごとに処理して1次元配列を返す関数の場合、apply の返り値は DataFrame になる。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

print(df.apply(np.sum))
# 0     6
# 1    15
# 2    24
# dtype: int64

print(df.apply(np.sqrt))
#           0         1         2
# 0  1.000000  1.414214  1.732051
# 1  2.000000  2.236068  2.449490
# 2  2.645751  2.828427  3.000000

DataFrame.pipe

複数の関数を連続して適用する場合に使用できる。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

df2 = df.pipe(np.ceil).pipe(np.mod, 2)
print(df2)
#      0    1    2
# 0  1.0  0.0  1.0
# 1  0.0  1.0  0.0
# 2  1.0  0.0  1.0

DataFrame.applymap

DataFrame.apply は DataFrame の各セルに対して、指定した関数を適用して、その結果を返す。

import numpy as np
import pandas as pd

df = pd.DataFrame([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

print(df.applymap(np.sqrt))
#           0         1         2
# 0  1.000000  1.414214  1.732051
# 1  2.000000  2.236068  2.449490
# 2  2.645751  2.828427  3.000000

Series.apply

Series.apply は Series の各セルに対して指定した関数を適用して、その結果を返す。

import numpy as np
import pandas as pd

s = pd.Series([1, 2, 3, 4, 5])

print(s.apply(np.sqrt))
# 0    1.000000
# 1    1.414214
# 2    1.732051
# 3    2.000000
# 4    2.236068
# dtype: float64

convert_dtype: 型を最適化するかどうか

convert_dtype=True の場合、より適した型があれば、返り値の型が変更される。

以下の霊では、元の Series は文字列型であるが、len 関数を適用すると、数値の Series になる。
convert_dtype=False の場合、型は変更しないので、元の Series と同じ文字列型である。
他方、convert_dtype=True の場合、整数型に変換される。

import numpy as np
import pandas as pd

s = pd.Series(["Apple", "Banana", "Orange"])

print(s.apply(len, convert_dtype=False))
# 0    5
# 1    6
# 2    6
# dtype: object

print(s.apply(len, convert_dtype=True))
# 0    5
# 1    6
# 2    6
# dtype: int64

関数に追加の引数を渡す。

apply に指定した関数には、第1引数に Series の各要素が渡されるが、他に引数がある場合は、次のように指定する。
位置引数の場合は args にタプルで指定する。
キーワード引数の場合は、apply にキーワード引数として指定する。

import numpy as np
import pandas as pd

s = pd.Series([1, 2, 3, 4, 5])


def func(a, b, c):
    print(f"b: {b}, c: {c}")  # # b: 2, c: test
    return a ** b


# apply() に与えた args とキーワード引数に基づき、
# func(series, 2, c='test') として呼び出される。
print(s.apply(func, args=(2,), c="test"))
# 0     1
# 1     4
# 2     9
# 3    16
# 4    25
# dtype: int64

Series.map

Series.map は Series の各値を指定した辞書に基づて置換を行い、結果を返す。
辞書は {変換前の値: 変換後の値, ...} とする。

import numpy as np
import pandas as pd

s = pd.Series(["a", "b", "a", "c", "b"])

# "a" は10、"b" は20、"c" は30に置換する。
print(s.map({"a": 10, "b": 20, "c": 30}))
# 0    10
# 1    20
# 2    10
# 3    30
# 4    20

Series.pipe

複数の関数を連続して適用する場合に使用できる。

import pandas as pd

s = pd.Series([1.2, 2.4, 3.6])
print(s)
# 0    1.2
# 1    2.4
# 2    3.6
# dtype: float64

s2 = s.pipe(np.ceil).pipe(np.mod, 2)
print(s2)
# 0    0.0
# 1    1.0
# 2    0.0
# dtype: float64