apply map applymapの使い分けがよくわからぬ

前回はmapとapplymapを試してみましたが、applyというのもどうも同じような動きをするらしい。

試しに前回試したmapやapplymapをapplyに置き換えたところほとんど同じ動きをしました。
使い分けがまったくわかりません。
ということでこの辺りを探っていくことにします。

ChatGPTに聞いてみました。

applymapapplymap は、PandasのDataFrameやSeriesオブジェクトに対して使用されるメソッドであり、データの変換や操作を行う際に使われます。それぞれの違いを以下に解説します。
apply:
apply メソッドはDataFrameやSeriesの各要素に対して関数を適用します。
DataFrameの場合、axis パラメータを使って行方向(axis=0)または列方向(axis=1)に関数を適用できます。
Seriesの場合、要素に対して関数を適用します。
関数は単純な値の変換だけでなく、複雑な操作も行うことができます。
map:
map メソッドはSeriesオブジェクトに対して使われます。
1つの値から別の値への変換を行うために使用します。
辞書や関数を使って、要素の値を別の値に対応付けることができます。
DataFrameにはmapメソッドがありませんが、列に対してmapを使用したい場合は、applyを使用して各列に対してmapを適用することができます。
applymap:
applymap メソッドはDataFrameオブジェクトに対して使われます。
DataFrameの各要素に対して関数を適用します。
つまり、DataFrame全体の要素に対して要素ごとの変換を行いたい場合に使用します。
Seriesには applymap メソッドはありませんが、Seriesの各要素に対して変換を行いたい場合は、代わりに apply メソッドを使用します。


簡単に言うと、apply はDataFrameやSeriesの要素に対して関数を適用する際に使用します。
map はSeriesの要素を別の値に対応付ける際に使用します。
applymap はDataFrameの全ての要素に対して要素ごとの変換を行う際に使用します。

ChatGPT

わかったようなわからないような。
ググってみました。
このサイトがわかりやすい。

1)mapはSeriesのみに対応、applyはSeriesでなくても良い。例えば、カラム1つに適用するならmap、applyのどちらもよいが、カラム2つ以上に一括適用するならapplyのみ。
2)mapは辞書で変換できる。applyではできない。
3)リストに対してはmapしか使えない。

基本的には特別な場合を除いてはどちらも同じように使えるようです。
試しにここの1)2)3)のパターンをmapとapplyで確認してみようと思います。

import pandas as pd

data = {
    '仕入先': ['商店A', '商店C', '商店C', '商店A', '商店C', '商店A', '商店A', '商店B'],
    '果物': ['りんご', 'バナナ', 'みかんA', 'いちご', 'ぶどう', 'みかん', 'いちご', 'すいか'],
    '価格': [130, 200, 70, 600, 250, 300, 200, 150]
}

# データフレームを作成
df = pd.DataFrame(data)

# データフレームを表示して確認
print(df)

   仕入先  果物   価格
0  商店A   りんご  130
1  商店C   バナナ  200
2  商店C   みかんA  70
3  商店A   いちご  600
4  商店C   ぶどう  250
5  商店A   みかん  300
6  商店A   いちご  200
7  商店B   すいか  150

前回と同じくこちらのデータを使います。

まずは1)から。
mapはSeriesのみに対応、applyはSeriesでなくても良い。

type(df['価格'])

#
pandas.core.series.Series

まずはdf['価格']がSeriesであることを確認。
mapを試してみます。

df['価格'].map(lambda x: x * 1.1)
#
0    143.0
1    220.0
2     77.0
3    660.0
4    275.0
5    330.0
6    220.0
7    165.0

問題なく動きます。
次にapply。

df['価格'].apply(lambda x: x * 1.1)
#
0    143.0
1    220.0
2     77.0
3    660.0
4    275.0
5    330.0
6    220.0
7    165.0

こちらも問題なし。

カラム2つに対してはどうか。

type(df[['仕入先','果物']])
#
pandas.core.frame.DataFrame

df[['仕入先','果物']].apply(lambda x: True if 'A' in str(x) else False, axis=1)
#
0     True
1    False
2     True
3     True
4    False
5     True
6     True
7    False

applyは問題なし。
ではmapはどうか。

df[['仕入先','果物']].map(lambda x: True if 'A' in str(x) else False, axis=1)
#
AttributeError: 'DataFrame' object has no attribute 'map'

カラム2つに対してはmapは使えないようです。
ちなみにapplymapならどうなるか。

df[['仕入先','果物']].applymap(lambda x: True if 'A' in str(x) else False)
#
	仕入先	果物
0	True	False
1	False	False
2	False	True
3	True	False
4	False	False
5	True	False
6	True	False
7	False	False

個別の要素に対して判定がなされます。
applyの場合は仕入先と果物の文字列を結合させた上で判定を行っているらしく、結合させた文字列に'A'があるかないかを判定しています。
でも要素がintの場合はそれぞれの要素に対して処理を行うようです。

import pandas as pd

data = {
    '仕入先': ['商店A', '商店C', '商店C', '商店A', '商店C', '商店A', '商店A', '商店B'],
    '価格A': [13430, 2544, 7430, 43434600, 4343250, 34400, 4343200, 443150],
    '価格B': [130, 200, 70, 600, 250, 300, 200, 150]
}

# データフレームを作成
df = pd.DataFrame(data)

df[['価格A','価格B']].apply(lambda x: x*2)
#
	価格A	価格B
0	26860	260
1	5088	400
2	14860	140
3	86869200	1200
4	8686500	500
5	68800	600
6	8686400	400
7	886300	300

このあたりはなぜなのかよくわからないのでそういうものだということにしておきます。

2)mapは辞書で変換できる。applyではできない。

import pandas as pd

data = {
    '仕入先': ['商店A', '商店C', '商店C', '商店A', '商店C', '商店A', '商店A', '商店B'],
    '果物': ['りんご', 'バナナ', 'みかん', 'いちご', 'ぶどう', 'みかん', 'いちご', 'すいか'],
}

df = pd.DataFrame(data)

price ={'りんご': '100円', 'バナナ': '150円', 'みかん': '200円', 'いちご': '250円', 'ぶどう': '300円', 'すいか': '400円'}

df['価格'] = df['果物'].map(price)

print(df)
#
   仕入先   果物    価格
0  商店A  りんご  1001  商店C  バナナ  1502  商店C  みかん  2003  商店A  いちご  2504  商店C  ぶどう  3005  商店A  みかん  2006  商店A  いちご  2507  商店B  すいか  400

辞書で変換されたカラムが追加されました。
applyならどうでしょう。
なにかよくわからないエラーが出ました。
もちろんapplymapもだめでした。


3)リストに対してはmapしか使えない。

numbers = [1, 3, 5, 7,9]
list(map(lambda x: x**2, numbers))

mapは問題なく使えます。
applyはどうでしょう。

list(apply(lambda x: x**2, numbers))
#
NameError: name 'apply' is not defined

エラーが出ます。

ここまでいろいろ試してみて、完全に理解したというところまでは到底至っていませんが、こういう場面ではこっちを使うということは多少わかった気がします。

それとは別に、lambda式の使い方がわかったことが1番の収穫だったかも。







この記事が気に入ったらサポートをしてみませんか?