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
を指定することで大文字小文字区別なく置換される。
ここで、gsub
とstr_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