gsubをdata.frameに使用した時に少し困ったので、備忘録を残しておきます。
~目次~
1. gsubの基本的な使い方
gsubは文字列の変換を行う関数で、基本的な使い方は以下になります。
gsub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
#シンプルに使うと以下
gsub(変更する文字列, 変換後の文字列, 対象のデータ)
試してみます。
> test <- "テストの結果は10点でした"
> test
[1] "テストの結果は10点でした"
> gsub("10", "95",test)
[1] "テストの結果は95点でした"
上記のように"10"を"95"に変えることができました。
便利ですね。
2. gsbuをdata.frameに使用した時の問題
gsub関数自体は、Rの他の関数と同様にベクトルにもそのまま使えます。
> tmp2 [1] "1,000" "2,000" "3,000" > gsub(",","",tmp2) [1] "1000" "2000" "3000"
上記では数字に入っている","を削除しました。(変換後の文字列を""にすることで、当該の文字列を削除できます)
しかし、data.frameにgsubを使用すると、以下のようにおかしな結果になります。
> tmp <- data.frame(x=c("1,000","2,000","3,000"), y=c("1,999","2,999","3,999"))
> tmp
x y
1 1,000 1,999
2 2,000 2,999
3 3,000 3,999
> gsub(",","",tmp)
[1] "1:3" "1:3"
こういう時に、lapplyやsapplyを使用することを思いつくかもしれませんが、gsubは第一変数が対象のデータではないため、使用できません。
無理やり実行すると、以下のようにエラーが出ます。
> lapply(tmp,gsub,",","")
$x
[1] ""
$y
[1] ""
警告メッセージ:
1: FUN(X[[i]], ...) で:
引数 'pattern' は 1 を超える長さなので、最初の要素だけが使われます
2: FUN(X[[i]], ...) で:
引数 'pattern' は 1 を超える長さなので、最初の要素だけが使われます
3. 解決策
data.frame型には直接持ってこれないので、matrix型にしてから適用します。
> gsub(",","",as.matrix(tmp))
x y
[1,] "1000" "1999"
[2,] "2000" "2999"
[3,] "3000" "3999"
ただし、このままではdata.frameがmatrixになってしまっているので、as.data.frameでdata.frame型に戻してあげます。
> class(gsub(",","",as.matrix(tmp)))
[1] "matrix"
>
> tmp_after <- as.data.frame(gsub(",","",as.matrix(tmp)))
> tmp_after; class(tmp_after)
x y
1 1000 1999
2 2000 2999
3 3000 3999
[1] "data.frame"
無事gsub関数で変換することができました。
4. [おまけ]listへのgsubの適用
listにgsubを適用すると、予想通りdata.frameと同様にうまくいきません。
> tmp_list <- list(x=c("1,000","2,000"), y=c("1,999","2,999"))
> gsub(",","",tmp_list)
[1] "c(\"1000\" \"2000\")" "c(\"1999\" \"2999\")"
listにはas.matrixも効かないため以下のどちらかしかないかなと思います。
unlistを使う
unlistで一時的にベクトルに→gsubを適用→list化の流れです。
> tmp_list_2 <- gsub(",","",unlist(tmp_list));tmp_list_2
x1 x2 y1 y2
"1000" "2000" "1999" "2999"
> tmp_list_after <- list(x=tmp_list_2[1:2], y=tmp_list_2[3:4]);tmp_list_after
$x
x1 x2
"1000" "2000"
$y
y1 y2
"1999" "2999"
for文を使う
諦めて素直にfor文を使います。ただし、この方法だとリストの要素名が消えてしまいますね。
> tmp_list_after_2 <- list()
> for (i in 1:length(tmp_list)) tmp_list_after_2[[i]] <- gsub(",","",tmp_list[[i]])
> tmp_list_after_2
[[1]]
[1] "1000" "2000"
[[2]]
[1] "1999" "2999"
まあ、あまりlist型に直接gsubを使うことはないかもしれませんが。。。