R初心者におすすめのパッケージ
R初心者はこれを見ろ!便利なパッケージまとめ!入門編の続きです。
ちなみに、前回はdata.table
やdplyr
(select
filter
mutate
summarise
group_by
)、重複削除のdistinct
について書かせていただきました。
今回の内容
今回もdplyr
について説明していきます。
・inner_join
(%in%
も触れます)
・anti_join
あたりを説明します。
変数加工に便利なので、「知らない!」という方は、お読みいただければと存じます。
dplyr
まず、inner_join
とanti_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_join
はdata 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_join
はinner_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
本日はここまでです。
次回はtidyr
のspread
, gather
あたりをまとめようかと思います。
もし、「こんな事できないの?」とか「こういうことが知りたい」等ありましたら、コメントいただければと思います。