Rで複数のデータフレームを結合するJOIN関数の使い方とは。マーケターが1からRを勉強します【第6回】

Rで複数のデータフレームを結合するJOIN関数の使い方とは。マーケターが1からRを勉強します【第6回】

マーケター1年目の小幡さんがRを学んでいきます。講師は株式会社ヴァリューズのデータアナリスト、輿石さん。第6回はRを使ったデータ同士を結合させるjoin関数を習得します。Rでデータを扱えるようになりたいと考えている方、ぜひ小幡さんと一緒に勉強していきましょう。


前回までの進捗

こんにちは、小幡です。Rを学んでおります。

前回は「dplyr」パッケージを使ったデータ集計の7つの処理のうち、6つまでを勉強しました。列の追加、行のフィルター、データの要約とデータのグループ化などを組み合わせることで、1つのデータフレームなら自由に操作ができるようになった気がします。

今回は、前回と同じ「dplyr」パッケージから、Joinを行う関数について勉強します。Joinができると複数のデータを組み合わせて分析ができるようになるみたいです。また、「パイプ演算子」という、dplyrを使ったコーディングをよりシンプルに書けるやり方も教えていただけるそうです。

では輿石さん、よろしくお願いいたします!

データの結合

輿石さん:今まで1つのデータフレームに対して列や行を増やす、減らす、並び替える、要約するといった処理を勉強しました。今までやった6つの関数を組み合わせることで、1つのデータであれば小幡さんはかなり自由にデータを加工・集計できるようになっているはずです。

今回は複数のデータフレームを結合するという操作について勉強します。実際にデータ分析をしていると、まずはいくつかのデータを1つにまとめるという作業から始まることも少なくありません。このまとめる/結合する操作をjoinと言い、「データをjoinする」とか表現したりします。

小幡:具体的に、どんなときにデータの結合が必要になるんでしょうか?

輿石さん:例えばある売上データで「9月1日に商品Aが1個売れた」というレコードがあったとします。しかし売上データには商品名がIDでAとしか書いていないので、これだけではAがどんな商品なのかは分かりません。どんな商品なのかを知るためには、商品マスタのデータと照らし合わせて、2つのデータを結合しなければいけません。

他には、売上データには購入者の情報がユーザIDしかなくて、買った人の性年代や居住地などの属性情報を組み合わせて分析するために、ユーザマスタを結合したいケースも多いのではと思います。

小幡:なるほど!

輿石さん:まずはleft_join()とinner_join()の2つの関数を理解するのが良いでしょう。では、今日の内容を理解するために使うデータフレームを読み込みましょう。今まで使っていた売上データと、ユーザの属性情報が記録されたユーザマスタの2つを使います。次のコードをテキストエディタにコピペして実行してみてください。

●コード
# packageの読み込み
library(tidyverse)

# 売上データの読み込み
kenko_ec_data <- read_tsv("https://adcreative.valuesccg.net/manamina/article/manaminar/kenko_ec_sample.tsv")
# 記事中での表示を見やすくするために列を絞っておきます。
kenko_ec_data_s <- select(kenko_ec_data, userid, purchase_date, item_name)
●コンソールの出力内容
#> # A tibble: 10,361 x 3
#>    userid purchase_date item_name                                  
#>    <chr>  <date>        <chr>                                      
#>  1 K00002 2020-01-07    マルチ酵素 サプリメント お徳用 90日分      
#>  2 K00003 2020-03-24    カルシウム サプリメント プレミアム 30日分  
#>  3 K00005 2020-01-30    クレアチン サプリメント スタンダード 30日分
#>  4 K00008 2020-01-30    乳酸菌 サプリメント プレミアム 30日分      
#>  5 K00009 2020-01-15    クエン酸 サプリメント スタンダード 30日分  
#>  6 K00010 2020-03-22    ビタミンB サプリメント お徳用 90日分       
#>  7 K00019 2020-03-21    グルコサミン サプリメント お徳用 90日分    
#>  8 K00023 2020-01-05    ビタミンB サプリメント プレミアム 30日分   
#>  9 K00027 2020-03-13    スピルリナ サプリメント お徳用 90日分      
#> 10 K00031 2020-02-12    BCAA サプリメント スタンダード 30日分      
#> # ... with 10,351 more rows
●コード
# ユーザマスタデータの読み込み
user_master <- read_tsv("https://adcreative.valuesccg.net/manamina/article/manaminar/user_master.tsv")
user_master
●コンソールの出力内容
#> # A tibble: 2,000 x 4
#>    userid gender  age   pref     
#>    <chr>  <chr>   <chr> <chr>    
#>  1 K00002 02.女性 59    12.千葉県
#>  2 K00003 02.女性 53    13.東京都
#>  3 K00008 02.女性 47    13.東京都
#>  4 K00010 01.男性 35    27.大阪府
#>  5 K00023 01.男性 36    13.東京都
#>  6 K00031 01.男性 53    23.愛知県
#>  7 K00038 01.男性 47    11.埼玉県
#>  8 K00039 01.男性 55    01.北海道
#>  9 K00061 01.男性 29    13.東京都
#> 10 K00064 01.男性 71    13.東京都
#> # ... with 1,990 more rows

左のデータに右のデータをくっつける(left_join)

輿石さん:データの準備ができましたね。まずは、基本となるleft_joinを習得しましょう。今まで学習したselectやsummariseなど6つのデータフレーム操作のための関数は、必ず第一引数にデータフレームを指定していました。joinは2つのデータフレームをくっつける動きをするのでleft_join(データフレーム1, データフレーム2, by = "キーとする列")と、データフレームを2つ引数に取ります。

byという引数には、「何を基準に2つのデータを結合するのか?」を指定してあげます。今回の場合はuseridを基準にデータをくっつけたいので、引数byにはuseridを指定して実際に結合してみましょう。

●コード
left_joined_data <- left_join(kenko_ec_data_s, user_master, by = "userid")
left_joined_data
●コンソールの出力内容
#> # A tibble: 10,361 x 6
#>    userid purchase_date item_name                                   gender  age   pref     
#>    <chr>  <date>        <chr>                                       <chr>   <chr> <chr>    
#>  1 K00002 2020-01-07    マルチ酵素 サプリメント お徳用 90日分       02.女性 59    12.千葉県
#>  2 K00003 2020-03-24    カルシウム サプリメント プレミアム 30日分   02.女性 53    13.東京都
#>  3 K00005 2020-01-30    クレアチン サプリメント スタンダード 30日分 NA      NA    NA       
#>  4 K00008 2020-01-30    乳酸菌 サプリメント プレミアム 30日分       02.女性 47    13.東京都
#>  5 K00009 2020-01-15    クエン酸 サプリメント スタンダード 30日分   NA      NA    NA       
#>  6 K00010 2020-03-22    ビタミンB サプリメント お徳用 90日分        01.男性 35    27.大阪府
#>  7 K00019 2020-03-21    グルコサミン サプリメント お徳用 90日分     NA      NA    NA       
#>  8 K00023 2020-01-05    ビタミンB サプリメント プレミアム 30日分    01.男性 36    13.東京都
#>  9 K00027 2020-03-13    スピルリナ サプリメント お徳用 90日分       NA      NA    NA       
#> 10 K00031 2020-02-12    BCAA サプリメント スタンダード 30日分       01.男性 53    23.愛知県
#> # ... with 10,351 more rows

小幡:売上データに属性情報がくっついてますね!ユーザマスタを見るとK00002さんという人は、千葉県の59才の女性でした。確かに正しく紐づいていますね。

輿石さん:そうですね。left_join()はbyに指定した値が同じ行同士をくっつけてくれるんです。

小幡:3行目のK00005さんは属性が”NA”となっていますね。これはどういうことですか??

輿石さん:良いところに気が付きましたね。NAはRで欠損値と呼ばれる特殊な値で、「データがないよ」ということを表しています。

実は、売上データは3000人のデータから構成されているのですが、ユーザマスタにはその中の2000人分しかデータが含まれていなかったんです。購入時にユーザ登録してくれた人やアンケートに答えてくれた人しかユーザの属性情報がないというのはよくあるのではと思います。

left_joinは、「左のデータを基準に右のデータをくっつける」ので、左のデータはすべて残るんです。何も紐づかなかった箇所にはNAという欠損を表す値が入っています。

小幡:NAはデータがない=欠損していることを表す値だったんですね。ちなみに「左のデータ」というのは第一引数に指定したデータで、「右のデータ」というのは第二引数に指定したデータ、ということであってますか?

輿石さん:その通りです!

共通する行だけを残すinner_join

輿石さん:次にinner_join()を説明します。関数の引数はleft_join()と一緒です。

小幡inner_join(データフレーム1, データフレーム2, by = "キーとする列")ですね。left_join()とinner_join()で何が違うんでしょう?

輿石さん:そこですよね。left_joinは"left"と名前にあるように、「左のデータを基準に右のデータを結合する」という働きをしました。左が基準なので左のデータはすべて残って、右側のデータが紐づかない箇所には欠損を表すNAが入っていましたね。

inner_join()は「2つのデータ両方に含まれる値だけ残して結合する」という働きをします。下記はinner_joinの動きを表す図です。x1という列に着目してください。aとb両方のデータに含まれるのはAとBです。CとDはどちらか片方にしか存在しません。なので、inner_join()の結果はAとBだけのレコードに絞られていますね。

輿石さん:ではサンプルデータで実行してみましょう。

●コード
inner_joined_data <- inner_join(kenko_ec_data, user_master, by = "userid")
inner_joined_data
●コンソールの出力内容
#> # A tibble: 6,960 x 6
#>    userid purchase_date item_name                                 gender  age   pref     
#>    <chr>  <date>        <chr>                                     <chr>   <chr> <chr>    
#>  1 K00002 2020-01-07    マルチ酵素 サプリメント お徳用 90日分     02.女性 59    12.千葉県
#>  2 K00003 2020-03-24    カルシウム サプリメント プレミアム 30日分 02.女性 53    13.東京都
#>  3 K00008 2020-01-30    乳酸菌 サプリメント プレミアム 30日分     02.女性 47    13.東京都
#>  4 K00010 2020-03-22    ビタミンB サプリメント お徳用 90日分      01.男性 35    27.大阪府
#>  5 K00023 2020-01-05    ビタミンB サプリメント プレミアム 30日分  01.男性 36    13.東京都
#>  6 K00031 2020-02-12    BCAA サプリメント スタンダード 30日分     01.男性 53    23.愛知県
#>  7 K00038 2020-03-18    カルシウム サプリメント プレミアム 30日分 01.男性 47    11.埼玉県
#>  8 K00039 2020-01-09    ビタミンB サプリメント プレミアム 30日分  01.男性 55    01.北海道
#>  9 K00061 2020-02-05    EPA サプリメント スタンダード 30日分      01.男性 29    13.東京都
#> 10 K00064 2020-01-30    オルニチン サプリメント お徳用 90日分     01.男性 71    13.東京都
#> # ... with 6,950 more rows

小幡:left_join()の結果は10,361行でしたが、inner_joinでは6,960行と少なくなっています。そしてNAという値もないですし、K00005さんなどユーザマスタにいない人のデータが消えてますね。2つのデータ両方にいる人に絞られているので行数が減っているんですね。

輿石さん:何か実行した後に行数を確認するのは良い習慣ですね!その通りです!

ヴァリューズオフィスの11F「Peak Bar」にて(2020年2月に撮影)

何を基に結合するか?キーの指定の仕方

輿石さん:2つのデータを結合する際に、どの列をキーにするかは時によって違いますよね。また、キーが複数あるケースや、データによって列名が違う場合があったりします。その指定の仕方を簡単に紹介します。

小幡:キーが複数でもできるんですね。列名が違うっていうのはどういうことでしょう?

輿石さん:例えば、売上データはuseridという小文字の列名で、ユーザマスタはUSERIDと大文字だったり、user_idとアンダースコアが入っている列名になっていたりと、名前が違っているケースが結構あるんです。こういう場合でも「useridとuser_idがキーですよ」というのを機械に教えてあげる必要があります。

以下の表にまとめました。複数キーがある場合はc()という複数の要素をまとめる関数で囲ってあげます。名前が違う場合はイコールでつないであげましょう。

----
名前が同じ一つの列でjoin
by = "id"
名前が同じ複数の列でjoin
by = c("id1","id2")
名前が違う一つの列でjoin
by = c("id1" = "ID1")
名前が違う複数の列でjoin
by = c("id1" = "ID1", "id2" = "ID2" )


小幡:いろいろ方法があるんですね…!名前も違って複数のキーを使うケースは結構ややこしいですね...。

輿石さん:そうですね(笑) 書き方そのものを覚えなくてもいいので、こういった指定で解決できることを知っておいてください。最初は必要になったらこの表を参照するでOKですよ。徐々に覚えましょう!

パイプ演算子を使った書き方

輿石さん:これでdplyrのデータフレームを操作する関数7つすべてを学びました!お疲れ様です。

小幡:ありがとうございました!

輿石さん:dplyrの学習の最後に、「パイプ演算子」を使ってコードを書くことで、これら7つを組み合わせたコードが格段に書きやすく、そして読みやすくなることを紹介します。

輿石さん:パイプ演算子を学ぶ前に、今まで通りのやり方で男性に絞った商品カテゴリごとの売上ランキングを集計してみましょう。

●コード
# 性別の集計のためにユーザマスタを結合する。
kenko_ec_data_joined <- left_join(kenko_ec_data, user_master, by = "userid")

# filter関数で男性のデータに絞る
kenko_ec_data_joined_f <- filter(kenko_ec_data_joined, gender == "01.男性")

# mutate関数で、購入個数と値段を掛け合わせた支払い金額列を追加する。
kenko_ec_data_joined_f_m <- mutate(kenko_ec_data_joined_f, payment = price * purchase_amount)

# 商品カテゴリでデータフレームをグループ化する。
kenko_ec_data_joined_f_m_grouped <- group_by(kenko_ec_data_joined_f_m, item_category)

# summarise関数で商品カテゴリごとの売り上げ金額を集計する。
kenko_ec_data_joined_sum <- summarise(kenko_ec_data_joined_f_m_grouped, payment = sum(payment))

# arrange関数で売り上げ金額の降順で並び替える。
kenko_ec_data_joined_sum_sort <- arrange(kenko_ec_data_joined_sum, desc(payment))

kenko_ec_data_joined_sum_sort
●コンソールの出力内容
#> # A tibble: 54 x 2
#>    item_category           payment
#>    <chr>                     <dbl>
#>  1 ホエイプロテイン        5576655
#>  2 BCAA                    2134305
#>  3 マルチビタミン&ミネラル 1166752
#>  4 乳酸菌                  1008216
#>  5 コラーゲン               775000
#>  6 ルテイン                 665987
#>  7 食物繊維                 638780
#>  8 クエン酸                 571428
#>  9 L-シトルリン             569294
#> 10 コエンザイムQ10          543062
#> # ... with 44 more rows

輿石さん:以下の図のように、「処理を加えたデータフレームを次のデータフレームの第一引数に渡す」ということを繰り返していますね。

※DFは「データフレーム」の略

輿石さん:パイプ演算子は「%>%」と書いて、「左側のオブジェクトを右側の関数の第一引数に渡す」という働きをするんです。上の処理をパイプ演算子「%>%」を使って書き直してみましょう。

●コード
kenko_ec_data %>%
  left_join(user_master, by = "userid") %>%
  filter(gender == "01.男性") %>%
  mutate(payment = price * purchase_amount) %>%
  group_by(item_category) %>%
  summarise(payment = sum(payment)) %>%
  arrange(desc(payment)) -> output

output

小幡: だいぶシンプルになりましたね!

輿石さん:パイプ演算子を使うメリットは2つです。1つはそれぞれのデータフレームの名前を考えなくてよいこと。kenko_ec_data_joinedなど、一つの処理をする度に名前を決めていましたが、パイプ演算子を使えばその必要はなくなります。2つ目は、左から右に、上から下にコードを読んでいくと処理の流れが理解できるので、書きやすく理解もしやすい点です。

上のコードだったら、kenko_ec_dataをuser_masterと結合して、性別でフィルターして、支払金額列を追加して、商品カテゴリごとに売り上げ金額を集計して、、、と順に読めませんか??

小幡: 読める気がします!

輿石さん:dplyrを使って処理を書く際は、ぜひパイプ演算子「%>%」を使ってくださいね。さて、今回はここまでです! 長かったdplyrに関する説明は今回で終了です。処理の1つ1つはすごく単純なことをやっています。しかし、組み合わせて使うことで複雑な処理もできるようになる。それを実感できるとRに取り組みやすくなると思いますよ。

まとめ

今回は、複数のデータを結合するjoinを行う関数と、コードをシンプルに書けるようになる%>%(パイプ演算子)について勉強しました。

・2つのデータフレームのうち、共通する行だけを結合したいときはinner_joinを使う。

・どちらかは全て残して結合したいときは、left_joinを使う。

・結合の際、キーにする列は複数列・もしくは列名が異なっていても結合ができる。

・%>%(パイプ演算子)を使ってコードを書くと、データフレームを操作する関数同士をつなげて処理を記述できて便利。

次回からは、関数の内部で使うのバリエーションを増やしていきます。今は足し算・引き算などシンプルな処理しかできないですが、ここの知識が豊富だと、より難しい計算もできるようになるので、やっていきましょう!

この記事のライター

大学でマーケティングを勉強しながら、ヴァリューズでインターンとして働いていました。2020年の春からは新卒としてヴァリューズに入社しました。

関連する投稿


謎の実力派データ分析集団・ホクソエムに「データが扱えるマーケター」になるためのキャリア論を聞く

謎の実力派データ分析集団・ホクソエムに「データが扱えるマーケター」になるためのキャリア論を聞く

データ分析者とマーケターは、ますます切っても切れない関係になっています。ビジネスやプロダクトを成功させる上で、データ分析とマーケティングの考え方はどちらも重要。では、「データ×マーケター」のキャリアにはどんなスキルや経験が必要なのか?株式会社ホクソエムのお二人とヴァリューズの輿石に、マナミナ編集部がお話を聞きました。


Rでデータを加工・集計する3つの操作を解説。 マーケターが1からRを勉強します【第5回】

Rでデータを加工・集計する3つの操作を解説。 マーケターが1からRを勉強します【第5回】

マーケター1年目の小幡さんがRを学んでいきます。講師は株式会社ヴァリューズのデータアナリスト、輿石さん。第5回はRを使ったデータの要約、列の追加、データのグループ化の3操作を習得します。Rでデータを扱えるようになりたいと考えている方、ぜひ小幡さんと一緒に勉強していきましょう。


いま化粧品市場では何が起きている?新型コロナの影響を検索データからマーケコンサルが読み解く

いま化粧品市場では何が起きている?新型コロナの影響を検索データからマーケコンサルが読み解く

化粧品のトレンドについて調査する新企画。ヴァリューズのマーケティングコンサルタントである私、伊東茉冬が気になる話題について調査していきます。今回の調査は新型コロナウイルスの影響について。感染拡大により百貨店などが営業自粛となっている中、化粧品業界へはどのような影響が及んでいるのか。消費者の化粧品への関心度合の変化や、化粧品の中でもアイテムによって違いがあるのか、Web行動データを基に分析します。


Rでデータを加工・集計する方法とは?マーケターが1からRを勉強します【第4回】

Rでデータを加工・集計する方法とは?マーケターが1からRを勉強します【第4回】

マーケター1年目の小幡さんがRを学んでいきます。講師は株式会社ヴァリューズのデータアナリスト、輿石さん。第4回はパッケージ「dplyr」を使ったデータの加工・集計の方法を習得します。Rでデータを扱えるようになりたいと考えている方、ぜひ小幡さんと一緒に勉強していきましょう。


マーケティングの基本3要素、フレームワーク・コピー・プロダクトを分かりやすく学べる本を紹介します

マーケティングの基本3要素、フレームワーク・コピー・プロダクトを分かりやすく学べる本を紹介します

マーケティングについてイチから学びたいと考えている人に向けた本3冊+αを紹介する企画。マナミナを運営する株式会社ヴァリューズのマーケティング・コンサルタント、秤谷大河さんに挙げてもらいました。長期休暇の間などに、時間を取ってじっくりと読んでみてはどうでしょうか。


最新の投稿


クロス集計や回帰分析など、データ分析でよく使われる手法の基礎知識

クロス集計や回帰分析など、データ分析でよく使われる手法の基礎知識

企業がデータを活用するにあたっては、現場でデータ分析できる人材が増えることが重要です。分析したいときに他部署や外部に依頼せず、自分でデータ分析できれば、より素早く結果を得られます。また、外部に依頼した場合でも、分析に用いられている手法を理解し、分析の目的と合っているか判断する必要があります。そのためには「クロス集計」「ロジスティック回帰分析」「アソシエーション分析」「決定木分析」「クラスター分析」など、主要なデータ分析手法の基礎知識を身につけておきましょう。


大手企業Webサイトの訪問者数が急上昇、デジタル広告への投資増の結果か?富士フイルムやNEC、ソニー、コカ・コーラなど【20年8月急上昇サイト】

大手企業Webサイトの訪問者数が急上昇、デジタル広告への投資増の結果か?富士フイルムやNEC、ソニー、コカ・コーラなど【20年8月急上昇サイト】

2020年8月にユーザー数を伸ばしたWebサイトは? SaaS型の市場分析ツール「<a href="https://www.valuesccg.com/service/emarkplus/" target="_blank">eMark+(イーマークプラス)</a>」を使うと、どんな人がどんなWebサイトを見ているのか、いろいろな切り口で簡単に調べることができます。今回はeMark+を使って訪問ユーザー数の前月比が急上昇したWebサイトを調査しました。


NASA公開のビッグデータを活用したハッカソン&テックカンファレンスが今年はオンラインで開催決定!【無料申込み受付中】

NASA公開のビッグデータを活用したハッカソン&テックカンファレンスが今年はオンラインで開催決定!【無料申込み受付中】

『NASA SPACE APPS CHALLENGE KL 2020』は、NASA(アメリカ航空宇宙局)と人材の育成・教育サービスを提供する株式会社アンロックデザインが共同開催する、ASEAN最大規模のテックイベント。2020年10月2日(金)~4日(日)にマレーシアのクアラルンプールで開催される本イベントに、今年はオンラインで日本国内から参加することができます。最先端のグローバルなテックイベントで、視野を広げてみませんか。


東京コピーライターズクラブ創始者が立ち上げたクリエイティブハウスは、なぜ提案にデータを活用するのか?その理由を聞く

東京コピーライターズクラブ創始者が立ち上げたクリエイティブハウスは、なぜ提案にデータを活用するのか?その理由を聞く

東京コピーライターズクラブ(TCC)の初代会長、上野壮夫(うえのそうふ)氏が1966年に創立したクリエイティブハウス、ユー・ピイ・アール。心を動かすクリエイティブが伝統でもある同社では、競合分析ツール「eMark+」を使い、データによる提案も行なっているといいます。それはなぜなのか?また、その実態はどんなものなのでしょうか。マナミナ編集部がユー・ピイ・アールの田地さんにお聞きしました。


クラスタ分析事例「不動産投資をしたいのはどんな人?」レポート

クラスタ分析事例「不動産投資をしたいのはどんな人?」レポート

「不動産投資」「マンション投資」検索者をVALUESのユーザーの購買プロセス可視化ツール『story bank』を使って抽出し、6つにクラスタリング。中でも特徴的な3つのクラスタを詳しく分析し、不動産投資をしたい人の特徴を調査しました。(ページ数|11p)


自社と競合サイトのユーザー層の違いや急上昇サイトがすぐにわかる!他社サイトのユーザーが見える市場調査ツール eMark+無料登録はこちら

アクセスランキング


>>総合人気ランキング