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を使う。

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

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

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

Rで文字列の変形ができるstringrとは?マーケターが1からRを勉強します【第7回】

https://manamina.valuesccg.com/articles/814

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

関連記事

Rとは一体何? マーケターが1からRを勉強するドキュメンタリーが始まります【第1回】

https://manamina.valuesccg.com/articles/717

マーケター1年目、小幡さんのRを学ぶ道のりが始まります。講師は株式会社ヴァリューズのデータアナリスト、輿石さん。初回はそもそもRとは何か、なぜデータ分析でRを学ぶべきなのかを学び、実際にRをインストールします。Rでデータを扱えるようになりたいと考えている方、ぜひ小幡さんと一緒に勉強していきましょう。

コードはもう書かない!?「ノーコード」のサービスやメリット・デメリットとは…検索者属性から関心層の実態も調査

https://manamina.valuesccg.com/articles/1094

エンジニアではない人にとって、これまでプログラミングによるプロダクト開発は縁遠いものでした。しかし、いまや非エンジニアも簡単にプロダクトを開発できる時代になっています。それを可能にしたのが「ノーコード」。今回はそんなノーコードについてデータ分析ツール「Dockpit(ドックピット)」のキーワード分析機能を使い、関心を持つユーザーを深堀りしていきます。

​​

メールマガジン登録

最新調査やマーケティングに役立つ
トレンド情報をお届けします

この記事のライター

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

関連する投稿


「社内ハッカソン」の事前準備と進め方実例を公開!成功のポイントとは?

「社内ハッカソン」の事前準備と進め方実例を公開!成功のポイントとは?

エンジニアが参加・実施しているイメージがある「ハッカソン」。普段の業務ルーティーンの中では生まれづらい交流やスキル取得が模索できるメリットを持ち合わせています。一方で具体的にどのようなことが必要なのか、知らない方も多いかもしれません。そこで今回、ヴァリューズ在籍の4名の社員がハッカソンの準備から実装までを行いました。実際に体験・紹介することで、新たな気づきが得られるかもしれません。


お金の悩み相談の先に専門家がいる。「マネコミ!」がオウンドメディアで目指すこと

お金の悩み相談の先に専門家がいる。「マネコミ!」がオウンドメディアで目指すこと

保険会社のオウンドメディアとしてSEOでの集客数が多い「マネコミ!」。ローンチから3年目(2022年度)の最大月間UU数は60万に達しています。そんな「マネコミ!」を展開する東京海上日動あんしん生命保険株式会社は、なぜオウンドメディアを立ち上げたのか、どのように運営されているのか、そしてオウンドメディアが同社の成長にどう影響しているのかについて、デジタル戦略部企画グループの齋藤 瞬(さいとう わたる)さんに伺いました。


サブスクや課金サービス運営はなぜ難しい?「無料」「有料」サービスの境界線を探る「有料会員向けのユーザーアンケート」の価値とは

サブスクや課金サービス運営はなぜ難しい?「無料」「有料」サービスの境界線を探る「有料会員向けのユーザーアンケート」の価値とは

サービスを無料で楽しんだり、売買ができたりするだけでなく、さらなる付加価値を手に入れられる「有料サービス」。昨今はユーザーが月1回、年1回など料金を支払って受けられるサブスクリプションなどのサービスも様々でてきています。マネタイズの観点でも、価格×会員数で収益が見込めるため、運営がしやすいようにも見られがちです。しかし実際には「制作費・人件費を含めると赤字」「廃止の判断が難しく、運営が続いている」という悩みの声が上がっているというのです。今回は有料モデルについて、リサーチャーの菅原大介さんに解説いただきました。


マーケターの仕事は、分かりやすい言葉で「伝える」こと。BtoBビジネスにおけるターゲットの理解とDockpit活用法

マーケターの仕事は、分かりやすい言葉で「伝える」こと。BtoBビジネスにおけるターゲットの理解とDockpit活用法

サイバーセキュリティ製品というと、難しいイメージがありませんか?ふるまい防御やサンドボックス機能など耳にしたことがない機能があり、海外の製品情報に翻訳をかけただけでは難解な領域において、「伝える」ことを追求しているのがソフトバンクグループ企業のSB C&S株式会社のシマンテック事業のチームです。伝わる商品訴求のためには、ターゲットの理解やペルソナの設定が必要不可欠。今回は、同社がどのようにWeb行動ログ分析ツール「Dockpit」を活用し、マーケティング施策につなげているのか、ICT事業本部でプロダクトマーケティングを担当している須賀田淳氏に伺いました。


お菓子業界5社をマーケティング視点で企業研究! 大学生のデータドリブン就活|2022年最新版

お菓子業界5社をマーケティング視点で企業研究! 大学生のデータドリブン就活|2022年最新版

お菓子業界大手の「森永製菓」「江崎グリコ」「カルビー」「ブルボン」「不二家」。各公式サイトの集客状況に注目し、強みや施策の違いを調査します。2年半前に公開した同記事の最新版として、新たな発見をお届けします。


最新の投稿


博報堂研究デザインセンター、生活者発想技研からメタバース生活者たちと共にメタバースの未来を考える 「メタバース生活者ラボ™」を設立

博報堂研究デザインセンター、生活者発想技研からメタバース生活者たちと共にメタバースの未来を考える 「メタバース生活者ラボ™」を設立

株式会社博報堂は、メタバース空間における新しい生活者価値の創出と、イノベーションを生み出すことを目指し、研究員全員がメタバース生活者当事者によって構成されたコミュニティ型プロジェクト「メタバース生活者ラボ™」を設立したことを発表しました。


【2024年12月2日週】注目のマーケティングセミナー・勉強会・イベント情報まとめ

【2024年12月2日週】注目のマーケティングセミナー・勉強会・イベント情報まとめ

編集部がピックアップしたマーケティングセミナー・勉強会・イベントを一覧化してお届けします。


SEOの失敗から学んだ教訓、「技術的な最適化の重要性」「キーワード選定の重要性」「コンテンツの質が検索順位に与える影響」が上位に【eclore調査】

SEOの失敗から学んだ教訓、「技術的な最適化の重要性」「キーワード選定の重要性」「コンテンツの質が検索順位に与える影響」が上位に【eclore調査】

株式会社ecloreは同社が運営する「ランクエスト」にて、SEO対策で実際に失敗を経験した担当者に対し、その原因や対策についてアンケートを実施し、結果を公開しました。


ゴンドラ、CXデザイン・カスタマーサクセスの最新トレンドと顧客エンゲージメントに関する調査結果を発表

ゴンドラ、CXデザイン・カスタマーサクセスの最新トレンドと顧客エンゲージメントに関する調査結果を発表

株式会社ゴンドラは、カスタマーサクセス、CRM、CXデザイン業務経験者を対象に、顧客エンゲージメントに関するアンケート調査を実施しました。


SEOにおける動画コンテンツの活用目的は検索順位・ブランド認知度向上!約8割がSEO効果を実感している結果に【eclore調査】

SEOにおける動画コンテンツの活用目的は検索順位・ブランド認知度向上!約8割がSEO効果を実感している結果に【eclore調査】

株式会社ecloreは同社が提供する「ランクエスト」にて、動画コンテンツ活用者を対象に、SEO対策としての動画の有効性について調査を実施し、結果を公開しました。


競合も、業界も、トレンドもわかる、マーケターのためのリサーチエンジン Dockpit 無料登録はこちら

アクセスランキング


>>総合人気ランキング

ページトップへ