見出し画像

高階関数reduceに行き着きました

データフレーム同士を結合させようとしたところ、reduceに行き着きました。

やりたかったことをざっくりいうと、日付ごとに特定の文字列を含む要素数を一覧表示させること。

まずは元となるデータフレームをChatGptに作ってもらいました。

import pandas as pd
import random
from datetime import date, timedelta
from functools import reduce

# 日付をランダムに10日間選択
start_date = date(2023, 9, 1)
end_date = date(2023, 9, 10)
date_list = [start_date + timedelta(days=random.randint(0, 9)) for _ in range(30)]  # 30個の日付をランダムに選択

# 曜日を生成
day_of_week_list = [d.strftime('%A') for d in date_list]

# 商品名を生成
fruits = ['りんご', 'バナナ', 'みかん', 'いちご']
product_list = [random.choice(fruits) for _ in range(30)]

# データフレームを作成
data = {'日付': date_list, '曜日': day_of_week_list, '商品名': product_list}
df = pd.DataFrame(data).sort_values('日付')

ランダムに選んでいうので毎回違うデータフレームになりますが、
こんな感じです。

print(df)
#
	日付	                曜日	               商品名
1	2023-09-02	Saturday	バナナ
2	2023-09-02	Saturday	いちご
11	2023-09-02	Saturday	バナナ
0	2023-09-03	Sunday	りんご
23	2023-09-03	Sunday	りんご
29	2023-09-03	Sunday	みかん
22	2023-09-04	Monday	みかん
12	2023-09-04	Monday	みかん
18	2023-09-04	Monday	バナナ
27	2023-09-05	Tuesday	バナナ
9	2023-09-05	Tuesday	みかん
28	2023-09-05	Tuesday	バナナ
15	2023-09-05	Tuesday	いちご
6	2023-09-06	Wednesday	りんご
10	2023-09-06	Wednesday	りんご
20	2023-09-06	Wednesday	いちご
5	2023-09-06	Wednesday	りんご
21	2023-09-07	Thursday	みかん
14	2023-09-07	Thursday	いちご
7	2023-09-07	Thursday	バナナ
19	2023-09-08	Friday	みかん
13	2023-09-08	Friday	みかん
8	2023-09-08	Friday	バナナ
24	2023-09-08	Friday	みかん
25	2023-09-08	Friday	バナナ
17	2023-09-09	Saturday	りんご
4	2023-09-10	Sunday	みかん
3	2023-09-10	Sunday	みかん
26	2023-09-10	Sunday	いちご
16	2023-09-10	Sunday	バナナ

次に商品名に特定の文字列を含む日付ごとの要素数を変数にします。

df_ringo = df[df['商品名'].str.contains('りんご')].groupby(['日付','曜日']).size().reset_index(name='りんご')
df_banana = df[df['商品名'].str.contains('バナナ')].groupby(['日付','曜日']).size().reset_index(name='バナナ')
df_mikan = df[df['商品名'].str.contains('みかん')].groupby(['日付','曜日']).size().reset_index(name='みかん')
df_ichigo = df[df['商品名'].str.contains('いちご')].groupby(['日付','曜日']).size().reset_index(name='いちご')

ちなみにこんな感じです。

print(df_ringo)
#
	日付	                曜日	               りんご
0	2023-09-03	Sunday	        2
1	2023-09-06	Wednesday	3
2	2023-09-09	Saturday	1

print(df_banana)
#
        日付     	       曜日	               バナナ
0	2023-09-02	Saturday	2
1	2023-09-04	Monday	        1
2	2023-09-05	Tuesday   	2
3	2023-09-07	Thursday	1
4	2023-09-08	Friday	        2
5	2023-09-10	Sunday	        1

これらを日付、曜日ごとに結合させれば欲しいデータが得られます。
Pandasのmergeを使えば連結できそうです。
ですが問題がひとつ。
mergeは2つのデータフレームしか結合できないようです。

もちろん、df_ringoとdf_bananaを結合して、結合したものにdf_mikanを結合して…とやっていけばできることはできますが、かなり面倒です。
ここで便利なのがreduce関数。
あれとこれをこうして、できたものとそれをさらにこうするみたいなことが一気にできます。
うまく説明できないので、まずはコードを書きます。

dfs = [df_ringo, df_banana,df_mikan, df_ichigo]
df = reduce(lambda x, y: pd.merge(x,y, on=['日付', '曜日'], how='outer'), dfs).fillna(0)

まずは結合したいものをリストにします。
そしてついにreduceの出番。
reduceについてはこのYouTubeの解説がとてもわかりやすいです。

mergeについてはあまり使ったことがなかったので次回に取り上げてみようと思います。
結合した時に、データがない場合ももちろんあるので、fillna(0)でデータがない部分は0を表示させておきました。

結果、こういうデータフレームができ目的のものを完成させることができました。

print(df.sort_values('日付'))
#
	日付	        曜日      	りんご  バナナ	みかん いちご
3	2023-09-02	Saturday	0.0	  2.0	0.0	  1.0
0	2023-09-03	Sunday	    2.0	  0.0	1.0	  0.0
4	2023-09-04	Monday	    0.0	  1.0	2.0	  0.0
5	2023-09-05	Tuesday	    0.0	  2.0	1.0	  1.0
1	2023-09-06	Wednesday	3.0	  0.0	0.0	  1.0
6	2023-09-07	Thursday	0.0	  1.0	1.0	  1.0
7	2023-09-08	Friday	    0.0	  2.0	3.0	  0.0
2	2023-09-09	Saturday	1.0	  0.0	0.0	  0.0
8	2023-09-10	Sunday	    0.0	  1.0	2.0	  1.0


いいなと思ったら応援しよう!