メモ:dplyr::mutate()の中でstr_split()したいと思ったとき、使うのはtidyr::separate()だ

定期的に忘れるのでメモ。たぶんまた忘れるけど。

stackoverflow.com

uri氏の素晴らしいパッケージJapan.useRにこういうデータがあります。

library(dplyr)
library(stringr)
library(Japan.useR)

slides <- 
  Japan.useR::materials() %>%
  filter(str_detect(Slide, "slideshare|rpubs")) %>%
  select(Slide)

head(slides)
#>                                                 Slide
#> 1                https://rpubs.com/kazutan/hijiyamar1
#> 2    http://www.slideshare.net/sakaue/hiroshimar-1-12
#> 3 http://www.slideshare.net/sakaue/hiroshimar-1-13-lt
#> 4  http://www.slideshare.net/KojiKosugi/psych-8342608
#> 5     http://www.slideshare.net/springking/ss-8342938
#> 6       http://www.slideshare.net/sakaue/hiroshimar-2

これが、あなたの目には、

https://サイト/ユーザ名/スライド

と見えるとします。

この各要素をうまいこと取り出したい。

思いつくシンプルな発想は、"/"str_split()し、ネギトロめいた配列に分解することです。

が、うまくいきません。

slides %>%
  mutate(negitoro = str_split(Slide, "/"),
         site     = negitoro[3])
#> Error: not compatible with STRSXP

そんなときは、tidyrにseparate()という関数があるのでこれを使えるみたいです。

library(tidyr)

slides %>%
  separate(Slide,
           into = c("protocol", "_", "site", "username", "title"),
           sep = "/",
           extra = "drop") %>%
  head
#>   protocol _               site   username              title
#> 1   https:            rpubs.com    kazutan         hijiyamar1
#> 2    http:   www.slideshare.net     sakaue    hiroshimar-1-12
#> 3    http:   www.slideshare.net     sakaue hiroshimar-1-13-lt
#> 4    http:   www.slideshare.net KojiKosugi      psych-8342608
#> 5    http:   www.slideshare.net springking         ss-8342938
#> 6    http:   www.slideshare.net     sakaue       hiroshimar-2

ちなみにextraは、intoに指定したカラム数と実際に分かれた数が違う時にどうするかの挙動を指定するオプションです。 "drop"を指定すると、実際に分かれた数が指定より多い場合ははみ出た要素を無視して、少ない場合はNAで埋めてくれます。

デフォルトだと、長さが違うとエラーになります。一番最後に/がついているものとついていないものが混じっているからです。

slides %>%
  separate(Slide,
           into = c("protocol", "_", "site", "username", "title"),
           sep = "/")
#> Error: Values not split into 5 pieces at 16, 20, 119, 357, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385


slides[16,]
#> [1] http://www.slideshare.net/tmr_kohei/kashiwa-r/
#> 465 Levels:  http://1drv.ms/1sbZsIb  http://bit.ly/eabQki ... https://www.slideshare.net/yurieoka37/ss-35866478

"merge"を指定すると、実際に分かれた数が指定より多い場合ははみ出た要素は分割せず、少ない場合はNAで埋めてくれます。

slides %>%
  filter(row_number() == 16) %>%
  separate(Slide,
           into = c("protocol", "_", "site", "username", "title"),
           sep = "/",
           extra = "merge")
#>   protocol _               site  username      title
#> 1    http:   www.slideshare.net tmr_kohei kashiwa-r/