applymapとかの高階関数をいろいろ試してみる

前回の記事でChatGPTにapplymapを使ってデータフレームに特定の文字列を含む列の抽出方法を教えてもらったので、もう少しいろいろ試してみようと思います。
ちなみにapplymapのように引数に関数を渡したり、関数を戻り値とする関数を高階関数というそうです。

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

このデータフレームをapplymap関数を使って触っていこうと思います。
全ての要素を対象に「バナナ」を「ばなな」に置き換えてみようと思います。

df.applymap(lambda x: 'ばなな' if str(x)=='バナナ' else x) 

	仕入先	果物	   価格
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

「バナナ」が「ばなな」に置きかわりました。
lambda式の 引数x ですが個人的には最初これがなんなのかよくわかりませんでした。勝手に名付けたものなのでxだろうがyだろうがなんでもいいのですが、これはdfの各要素にあたります。
なのでdfの全ての要素に対して、バナナという文字列であれば、ばななに置き換えるということになります。

ちなみにstr(x)としたのは、要素にいろいろな型があるとエラーを起こすことがあるようなので、全て文字列とした上での条件式としました。この場合は価格はint型だと思うのですが、if x=='バナナ' ~ としてもエラーを起こしませんでした。なのでどういうときにエラーを起こすかはよくわかりません。

次に果物のカラムを全て「メロン」に置き換えようと思います。

df['果物'].applymap(lambda x: 'メロン')

こう書きたいところですが、
AttributeError: 'Series' object has no attribute 'applymap'
こういうエラーを返します。

pandasのDataframeの特定のカラムを抽出したものはSeriesになるようです。そしてSeriesはapplymap関数を使えないようです。
では何を使うか。map関数を使います。

df['果物'].map(lambda x: 'メロン')

0    メロン
1    メロン
2    メロン
3    メロン
4    メロン
5    メロン
6    メロン
7    メロン

すべてメロンに置き換わりました。

次に価格が150より大きい列のみを抽出してみようと思います。

df['価格'].map(lambda x: x>150)

0    False
1     True
2    False
3     True
4     True
5     True
6     True
7    False

df['価格']はSeriesなので今回もmap関数を使います。
結果はbool型でかえってきます。
Trueの行のみ抽出してみます。

df[df['価格'].map(lambda x: x>150)]

	仕入先	果物	   価格
1	商店C	バナナ	200
3	商店A	いちご	600
4	商店C	ぶどう	250
5	商店A	みかん	300
6	商店A	いちご	200

df[ ]で囲ってやるとTrueの行のみ表示させることができました。


最後に「A」という文字列を含む列のみ抽出してみようと思います。
今回はデータフレーム全体が対象になるのでapplymap関数を使用します。

df.applymap(lambda x: 'A' in str(x))

	仕入先	果物	      価格
0	True	False	False
1	False	False	False
2	False	True	False
3	True	False	False
4	False	False	False
5	True	False	False
6	True	False	False
7	False	False	False

各要素にTrue、Falseが返ってきます。
ただしこれでは各行にTrueとFalseが混在しているので先ほどと同じやり方でTrueのみ抽出するということはできなさそうです。

試しにやってみます。

df[df.applymap(lambda x: 'A' in str(x))]

	仕入先	果物	価格
0	商店A	NaN	NaN
1	NaN	    NaN	NaN
2	NaN	 みかんA	NaN
3	商店A	NaN	NaN
4	NaN	    NaN	NaN
5	商店A	NaN	NaN
6	商店A	NaN	NaN
7	NaN	    NaN	NaN

Trueの要素のみ元のデータが表示されます。
今回抽出したい行は文字列「A」が含まれている行なので、それぞれの行にTrueが1つでもあるものが対象となります。
そこで登場するのがany()です。
早速使ってみます。

df.applymap(lambda x: 'A' in str(x)).any(axis=1)

0     True
1    False
2     True
3     True
4    False
5     True
6     True
7    False

各カラムに1つでもTrueがあるものがTrueとなりました。
any()関数はPythonの組み込み関数の一つで、イテラブル(リスト、タプル、セット、辞書など)の中に少なくとも1つの真(True)の要素が含まれているかどうかを判定するために使用されます。
引数のaxis=0は行方向に対して、axis=1は列方向に対してTrueが1つ以上あるかを判定します。

df[df.applymap(lambda x: 'A' in str(x)).any(axis=1)]

	仕入先	果物	価格
0	商店A	りんご	130
2	商店C	みかんA	70
3	商店A	いちご	600
5	商店A	みかん	300
6	商店A	いちご	200

これで文字列「A」が含まれる行のみ抽出できました。

今回はapplymapとmapについて試してみましたがこれとよく似た動きをするものでapplyというものがあります。
これについても次回試してみようと思います。

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