Rのデータフレームで検索と置換をする方法

(2019年12月26日追記) 普段からエクセルを使い慣れている人にとっては、「検索と置換」はよく使う機能だと思う。 Rのデータフレームで同様の処理をする機会があり、素人なりに方法を調べたのでまとめてみた。

データフレームの準備

適当なデータでデータフレームを作成。ベクトルを合成してデータフレームを作ると、デフォルトでは文字列がfactor型になってしまうので、引数でstringsAsFactors = FALSEを指定する。

x <- c("abc","cde","efg","ghi","ijk","klm")
x2 <- c("Alice","Bob","Charles","Deven","Eve","Feldman")
y <- c(TRUE,FALSE,TRUE,TRUE,TRUE,FALSE)
z <- c(1,3,5,2,4,7)
df<- data.frame(X=x, X2=x2, Y=y, Z=z, stringsAsFactors = FALSE)
df

    X      X2     Y Z
1 abc   Alice  TRUE 1
2 cde     Bob FALSE 3
3 efg Charles  TRUE 5
4 ghi   Deven  TRUE 2
5 ijk     Eve  TRUE 4
6 klm Feldman FALSE 7

列を指定して検索&置換

まずは、データフレーム中の特定の列だけ検索対象にしたいときの方法。試しにX2列を対象に、「e」を「***」に置換してみる。

#Rの基本パッケージを使う方法
df1 <- df
df1["X2"] <- lapply(df1["X2"], gsub, pattern="e", replacement = "_")
df1

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cde     Bob FALSE 3
3 efg Charl_s  TRUE 5
4 ghi   D_v_n  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7

#dplyrを使う方法
library(dplyr)
library(stringr)
df2 <- dplyr::mutate(df,X2=gsub(X2,pattern="e",replacement = "_", ignore.case = TRUE))
df2
 
    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cde     Bob FALSE 3
3 efg Charl_s  TRUE 5
4 ghi   D_v_n  TRUE 2
5 ijk     _v_  TRUE 4
6 klm F_ldman FALSE 7


df3 <- dplyr::mutate(df,X2=gsub(X2,pattern="e",replacement = "_", ignore.case = FALSE))
df3

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cde     Bob FALSE 3
3 efg Charl_s  TRUE 5
4 ghi   D_v_n  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7


df4 <- dplyr::mutate(df,X2=str_replace(X2,pattern="e",replacement = "_"))
df4

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cde     Bob FALSE 3
3 efg Charl_s  TRUE 5
4 ghi   D_ven  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7

gsubでは、ignore.case = TRUEを指定することで大文字小文字区別なく置換される。 ここで、gsubstr_replaceでは置換のされ方が違うことに注意(df3とdf4)。前者では要素内でヒットするすべての文字列が置換されるが、後者では最初のヒットのみ置換される。str_replace_allを使うとgsubと同様に全てのヒットが置換される。

また、名前付きベクトルをpatternに指定すれば複数の変換を一度にできる

df4.5 <- dplyr::mutate(df, X2 = str_replace_all(X2, pattern = c("e" = "_", "a" = "_2")))
df4.5

    X       X2     Y Z
1 abc    Alic_  TRUE 1
2 cde      Bob FALSE 3
3 efg Ch_2rl_s  TRUE 5
4 ghi    D_v_n  TRUE 2
5 ijk      Ev_  TRUE 4
6 klm F_ldm_2n FALSE 7

データフレーム全体を検索&置換

次に、データフレーム全体を検索対象にしたいときの方法。

#Rの基本パッケージを使う方法
df5 <- data.frame(lapply(df, function(x){
gsub(pattern="e", replacement = "_", x)
}),stringsAsFactors = FALSE)
df5

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cd_     Bob FALSE 3
3 _fg Charl_s  TRUE 5
4 ghi   D_v_n  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7


#dplyrを使う方法
df6 <- dplyr::mutate_all(df, ~gsub(.,pattern="e",replacement = "_"))
df6

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cd_     Bob FALSE 3
3 _fg Charl_s  TRUE 5
4 ghi   D_v_n  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7

df7 <- dplyr::mutate_all(df, ~str_replace(.,pattern="e",replacement = "_"))
df7

    X      X2     Y Z
1 abc   Alic_  TRUE 1
2 cd_     Bob FALSE 3
3 _fg Charl_s  TRUE 5
4 ghi   D_ven  TRUE 2
5 ijk     Ev_  TRUE 4
6 klm F_ldman FALSE 7

Rの基本パッケージを使う方法でdata.frameをかぶせているのは、lapplyで返されるのがリスト型なので、データフレームに直している。

注意点

データフレーム全体を検索対象にすると、factor型やdouble型の列もすべてcharacter型にされてしまう。

> mode(df$Y)
[1] "logical"
> mode(df$Z)
[1] "numeric"
> mode(df5$Y)
[1] "character"
> mode(df6$Z)
[1] "character"
> mode(df5$Y)
[1] "character"
> mode(df6$Z)
[1] "character"

よって必要に応じて型の変換を行う。

df3$Y = as.logical(df6$Y)
df3$Z = as.numeric(df6$Z)

参考サイト様

r - Replace all occurrences of a string in a data frame - Stack Overflow

dplyrのmutate_if()とかについて - Technically, technophobic.

{dplyr}のパイプの中でNAを0に置換する - Note of Pediatric Surgery

stringr: Rの文字列をまともな方法で処理する - Heavy Watal

https://stringr.tidyverse.org/reference/str_replace.html