Posted at

R初心者はこれを見ろ!便利なパッケージまとめ!入門編②


R初心者におすすめのパッケージ

R初心者はこれを見ろ!便利なパッケージまとめ!入門編の続きです。

ちなみに、前回はdata.tabledplyr(select filter mutate summarise group_by)、重複削除のdistinctについて書かせていただきました。


今回の内容

今回もdplyrについて説明していきます。

inner_join (%in%も触れます)

anti_join

あたりを説明します。

変数加工に便利なので、「知らない!」という方は、お読みいただければと存じます。


dplyr

まず、inner_joinanti_joinから。

tableは、顧客ID別の購入レコードとご理解ください。

ターゲットにしているブランドがABCであり、ABCの購入週にpurchase_flg : 1が立っているデータです。

このようなデータから、2回以上「ABC」を購入した顧客のデータだけ抽出したいとします。

このような時にinner_joinは便利です。

> table

ID Weeks Brand
1 A 1 ABC
2 A 2 ABC
3 A 3 DEF
4 A 4 ABC
5 B 1 DEF
6 B 2 DEF
7 B 3 DEF
8 B 4 ABC
9 C 1 ABC
10 C 2 GHI
11 C 3 ABC
12 C 4 GHI
13 D 1 GHI
14 D 2 GHI
15 D 3 ABC
16 D 4 DEF

手順としては、2回以上購入のIDを始めに抽出します。

#2回以上購入の顧客IDをまず抜き出します

> over2 <- table %>%         #%>%はパイプ処理と呼ばれ、このように連続で変数加工ができます
dplyr::filter(Brand == "ABC") %>%    #ABC購入レコードだけにします
dplyr::group_by(ID) %>%          #以下をID別に処理します   
dplyr::summarise(freq = n()) %>%     #freqという列名で、ID別にレコード数を数えます。n()で行数をカウントできます
dplyr::filter(freq >= 2)         #上で作った、freq列の値が2以上のレコードのみにします。

> over2                   #このように、A(3回)、C(2回)のデータができます。
# A tibble: 2 x 2
ID freq
<chr> <int>
1 A 3
2 C 2

ちなみに、summariseまでですと、以下のようなデータになります。

このデータに、freq列でフィルターを掛けていたわけです。

> over2 <- table %>%         

dplyr::filter(Brand == "ABC") %>%
dplyr::group_by(ID) %>%
dplyr::summarise(freq = n())

> over2
# A tibble: 4 x 2
ID freq
<chr> <int>
1 A 3
2 B 1
3 C 2
4 D 1

続いて、over2に二回以上の購入IDが格納されましたので、これとtableを紐づけます。

というか、tableのID列が、over2のID列と一致するレコードを抽出します

> pick_up <- table %>% 

dplyr::inner_join(over2, by = "ID")  #tableとover2にて、ID列が共通するレコードのみにします。

> pick_up
ID Weeks Brand purchase_flg freq
1 A 1 ABC 1 3
2 A 2 ABC 1 3
3 A 3 DEF 0 3
4 A 4 ABC 1 3
5 C 1 ABC 1 2
6 C 2 GHI 0 2
7 C 3 ABC 1 2
8 C 4 GHI 0 2

見ての通り、inner_joinを使えば一瞬です。

by = 列名にて、列名を指定し、指定した列名に共通する値を持つレコードが残ります。

もし、列名が異なる場合は、以下のようにします。

> colnames(over2)[1] <- c("MonitorCD")  #over2の1列目の列名を MonitorCDに変えています。

> over2                  #無事、列名が変わっています
# A tibble: 2 x 2
MonitorCD freq
<chr> <int>
1 A 3
2 C 2

> pick_up <- table %>%
+ dplyr::inner_join(over2, by = c("ID" = "MonitorCD"))
> pick_up
ID Weeks Brand purchase_flg freq
1 A 1 ABC 1 3
2 A 2 ABC 1 3
3 A 3 DEF 0 3
4 A 4 ABC 1 3
5 C 1 ABC 1 2
6 C 2 GHI 0 2
7 C 3 ABC 1 2
8 C 4 GHI 0 2

上記のように、by = c("A" = "B")のようにしてあげると、異なる列名でも指定できます。

また、複数の列名で共通するレコードにしたい場合は、

> pick_up <- table %>% 

dplyr::inner_join(over2, by = c("ID" = "MonitorCD", "Weeks" = "freq"))

> pick_up
ID Weeks Brand purchase_flg
1 A 3 DEF 0
2 C 2 GHI 0

上記のように、by = c("A", "B")と列名を複数指定します。

ちなみに、%in%という、技もあります。

> target <- c("A", "C")  

> target
[1] "A" "C"

> pick_up2 <- table[table$ID %in% target,]
> pick_up2
ID Weeks Brand purchase_flg
1 A 1 ABC 1
2 A 2 ABC 1
3 A 3 DEF 0
4 A 4 ABC 1
9 C 1 ABC 1
10 C 2 GHI 0
11 C 3 ABC 1
12 C 4 GHI 0

inner_joindata frameでないと使えませんが、%in%は上記のようにdata frameじゃなくても使えます。

もちろん、下記のようにdata frameでも使えます。

> pick_up2 <- table[table$ID %in% over2$MonitorCD,]

> pick_up2
ID Weeks Brand purchase_flg
1 A 1 ABC 1
2 A 2 ABC 1
3 A 3 DEF 0
4 A 4 ABC 1
9 C 1 ABC 1
10 C 2 GHI 0
11 C 3 ABC 1
12 C 4 GHI 0

このように、inner_joinとは異なり、[freq]の列は引き継がれません。

inner_joinは名前の通り、データの「統合」なのです。


anti_join

anti_joininner_joinの逆で合致しないものを残してくっつけます、

#まずはデータの確認から、(上と同じものです)

> table
ID Weeks Brand purchase_flg
1 A 1 ABC 1
2 A 2 ABC 1
3 A 3 DEF 0
4 A 4 ABC 1
5 B 1 DEF 0
6 B 2 DEF 0
7 B 3 DEF 0
8 B 4 ABC 1
9 C 1 ABC 1
10 C 2 GHI 0
11 C 3 ABC 1
12 C 4 GHI 0
13 D 1 GHI 0
14 D 2 GHI 0
15 D 3 ABC 1
16 D 4 DEF 0

> over2
# A tibble: 2 x 2
MonitorCD freq
<chr> <int>
1 A 3
2 C 2

> pick_up <- table %>%
dplyr::anti_join(over2, by = c("ID" = "MonitorCD"))
> pick_up
ID Weeks Brand purchase_flg
1 B 1 DEF 0
2 B 2 DEF 0
3 B 3 DEF 0
4 B 4 ABC 1
5 D 1 GHI 0
6 D 2 GHI 0
7 D 3 ABC 1
8 D 4 DEF 0

この通り、AでもCでもない列が残りました。

これも%in%を使って代替できます。

#!で否定することで「合致しないもの」になります

> pick_up2 <- table[!table$ID %in% over2$MonitorCD,]
> pick_up2
ID Weeks Brand purchase_flg
5 B 1 DEF 0
6 B 2 DEF 0
7 B 3 DEF 0
8 B 4 ABC 1
13 D 1 GHI 0
14 D 2 GHI 0
15 D 3 ABC 1
16 D 4 DEF 0

本日はここまでです。

次回はtidyrspread, gatherあたりをまとめようかと思います。

もし、「こんな事できないの?」とか「こういうことが知りたい」等ありましたら、コメントいただければと思います。