他の言語で一般に辞書と呼ばれているものに基づいて変換したい文字データの大きなdata.frameがあります。
現在、私はそれについて次のようにしています:
foo <- data.frame(snp1 = c("AA", "AG", "AA", "AA"), snp2 = c("AA", "AT", "AG", "AA"), snp3 = c(NA, "GG", "GG", "GC"), stringsAsFactors=FALSE)
foo <- replace(foo, foo == "AA", "0101")
foo <- replace(foo, foo == "AC", "0102")
foo <- replace(foo, foo == "AG", "0103")
これは問題なく機能しますが、data.frame内の1つのアイテムを置き換えるたびにreplace
ステートメントを繰り返すのは明らかに美しくなく、ばかげているようです。
約25のキーと値のペアの辞書があるので、これを行うためのより良い方法はありますか?
map = setNames(c("0101", "0102", "0103"), c("AA", "AC", "AG"))
foo[] <- map[unlist(foo)]
map
がfoo
のすべてのケースをカバーすると仮定します。 foo
が(character()の)行列である場合、これは「ハック」のような感じが少なく、空間と時間の両方でより効率的です。
matrix(map[foo], nrow=nrow(foo), dimnames=dimnames(foo))
数百万のSNPと数千のサンプルがある場合、マトリックスとデータフレームの両方のバリアントは、ベクトルサイズのRの2 ^ 31-1制限に違反します。
パッケージを使用することにオープンである場合、plyr
は非常に人気のあるものであり、この便利な mapvalues() 関数を使用すると、目的の機能を実行できます。
foo <- mapvalues(foo, from=c("AA", "AC", "AG"), to=c("0101", "0102", "0103"))
文字列だけでなく、あらゆる種類のデータ型で機能することに注意してください。
ここに簡単な解決策があります
dict = list(AA = '0101', AC = '0102', AG = '0103')
foo2 = foo
for (i in 1:3){foo2 <- replace(foo2, foo2 == names(dict[i]), dict[i])}
注この回答は、 データフレーム内のすべての値を値のベクトルで置き換える方法? 。残念ながら、この質問は実際の質問の重複としてクローズされました。だから、私はここで、両方のケースの因子レベルを置き換えることに基づいた解決策を提案しようとします。
値を置き換える必要があるベクトル(または1つのデータフレーム列)だけがある場合および係数を使用することに異議がない場合は、ベクトルを強制して係数を変更し、必要に応じて因子レベル:
_x <- c(1, 1, 4, 4, 5, 5, 1, 1, 2)
x <- factor(x)
x
#[1] 1 1 4 4 5 5 1 1 2
#Levels: 1 2 4 5
replacement_vec <- c("A", "T", "C", "G")
levels(x) <- replacement_vec
x
#[1] A A C C G G A A T
#Levels: A T C G
_
forcats
packageを使用すると、これをワンライナーで実行できます。
_x <- c(1, 1, 4, 4, 5, 5, 1, 1, 2)
forcats::lvls_revalue(factor(x), replacement_vec)
#[1] A A C C G G A A T
#Levels: A T C G
_
データフレームの複数の列のall値を置き換える必要がある場合、アプローチを拡張できます。
_foo <- data.frame(snp1 = c("AA", "AG", "AA", "AA"),
snp2 = c("AA", "AT", "AG", "AA"),
snp3 = c(NA, "GG", "GG", "GC"),
stringsAsFactors=FALSE)
level_vec <- c("AA", "AC", "AG", "AT", "GC", "GG")
replacement_vec <- c("0101", "0102", "0103", "0104", "0302", "0303")
foo[] <- lapply(foo, function(x) forcats::lvls_revalue(factor(x, levels = level_vec),
replacement_vec))
foo
# snp1 snp2 snp3
#1 0101 0101 <NA>
#2 0103 0104 0303
#3 0101 0103 0303
#4 0101 0101 0302
_
_level_vec
_と_replacement_vec
_の長さは同じでなければならないことに注意してください。
さらに重要なことに、_level_vec
_はcompleteである必要があります。つまり、元のデータフレームの影響を受ける列にすべての可能な値を含めます。 (確認するにはunique(sort(unlist(foo)))
を使用してください)。それ以外の場合、欠損値は_<NA>
_に強制変換されます。これは Martin Morgansの回答 の要件でもあることに注意してください。
したがって、置き換えられる異なる値が数個しかない場合は、おそらく Ramnath's のように、他の答えの1つを使用したほうがよいでしょう。
これは仕事をする簡単なものです:
key <- c('AA','AC','AG')
val <- c('0101','0102','0103')
lapply(1:3,FUN = function(i){foo[foo == key[i]] <<- val[i]})
foo
snp1 snp2 snp3
1 0101 0101 <NA>
2 0103 AT GG
3 0101 0103 GG
4 0101 0101 GC
lapply
は、この場合、実際には気にしないリストを出力します。必要に応じて結果を何かに割り当て、それを単に破棄することができます。ここではインデックスを反復処理していますが、キー/値をリストに簡単に配置して、直接それらを反復処理することもできます。 <<-
でのグローバル割り当ての使用に注意してください。
私はmapply
でこれを行う方法をいじりましたが、私の最初の試みはうまくいかなかったので、切り替えました。しかし、mapply
を使用した解決策は可能だと思います。
上記の@Ramnathの回答を使用しましたが、ファイルから(置換対象および置換対象)を読み取り、置換ではなくgsubを使用しました。
hrw <- read.csv("hgWords.txt", header=T, stringsAsFactor=FALSE, encoding="UTF-8", sep="\t")
for (i in nrow(hrw))
{
document <- gsub(hrw$from[i], hrw$to[i], document, ignore.case=TRUE)
}
hgword.txtには次のタブで区切られています
"from" "to"
"AA" "0101"
"AC" "0102"
"AG" "0103"
dplyr::case_when
も使用できます
library(dplyr)
foo %>%
mutate_all(~case_when(. == "AA" ~ "0101",
. == "AC" ~ "0102",
. == "AG" ~ "0103",
TRUE ~ .))
# snp1 snp2 snp3
#1 0101 0101 <NA>
#2 0103 AT GG
#3 0101 0103 GG
#4 0101 0101 GC
条件をチェックし、条件がTRUE
の場合、対応する値に置き換えます。必要に応じてさらに条件を追加できます。TRUE ~ .
を使用すると、一致する条件がない場合は値をそのまま保持します。それらをNA
に変更したい場合は、最後の行を削除できます。
foo %>%
mutate_all(~case_when(. == "AA" ~ "0101",
. == "AC" ~ "0102",
. == "AG" ~ "0103"))
# snp1 snp2 snp3
#1 0101 0101 <NA>
#2 0103 <NA> <NA>
#3 0101 0103 <NA>
#4 0101 0101 <NA>
これにより、上記の条件がいずれも満たされない場合、値がNA
に変更されます。
ベースRのみを使用する別のオプションは、古い値と新しい値でlookup
データフレームを作成し、unlist
データフレームを古い値でmatch
作成し、対応する新しい値を取得して置き換えることです。
lookup <- data.frame(old_val = c("AA", "AC", "AG"),
new_val = c("0101", "0102", "0103"))
foo[] <- lookup$new_val[match(unlist(foo), lookup$old_val)]
前回の回答から数年が経ち、今夜、このトピックに関する新しい質問が出て、モデレーターがそれを閉じたので、ここに追加します。ポスターには、0、1、2を含む大きなデータフレームがあり、それらをそれぞれAA、AB、BBに変更しようとしています。
plyr
を使用:
> df <- data.frame(matrix(sample(c(NA, c("0","1","2")), 100, replace = TRUE), 10))
> df
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1 1 2 <NA> 2 1 2 0 2 0 2
2 0 2 1 1 2 1 1 0 0 1
3 1 0 2 2 1 0 <NA> 0 1 <NA>
4 1 2 <NA> 2 2 2 1 1 0 1
... to 10th row
> df[] <- lapply(df, as.character)
revalue
を使用してデータフレームに関数を作成し、複数の用語を置き換えます。
> library(plyr)
> apply(df, 2, function(x) {x <- revalue(x, c("0"="AA","1"="AB","2"="BB")); x})
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
[1,] "AB" "BB" NA "BB" "AB" "BB" "AA" "BB" "AA" "BB"
[2,] "AA" "BB" "AB" "AB" "BB" "AB" "AB" "AA" "AA" "AB"
[3,] "AB" "AA" "BB" "BB" "AB" "AA" NA "AA" "AB" NA
[4,] "AB" "BB" NA "BB" "BB" "BB" "AB" "AB" "AA" "AB"
... and so on
dplyr :: recodeの使用:
library(dplyr)
mutate_all(foo, funs(recode(., "AA" = "0101", "AC" = "0102", "AG" = "0103",
.default = NA_character_)))
# snp1 snp2 snp3
# 1 0101 0101 <NA>
# 2 0103 <NA> <NA>
# 3 0101 0103 <NA>
# 4 0101 0101 <NA>