我有一个大型的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中的一个项目时,重复replace
语句显然不是很漂亮而且似乎很愚蠢。
有没有更好的方法可以做到这一点,因为我有一个大约25个键/值对的字典?
答案 0 :(得分:28)
如果您打开使用套餐,plyr
是一个非常受欢迎的套餐,并且有一个方便的mapvalues()功能,可以满足您的需求:
foo <- mapvalues(foo, from=c("AA", "AC", "AG"), to=c("0101", "0102", "0103"))
请注意,它适用于所有类型的数据类型,而不仅仅是字符串。
答案 1 :(得分:26)
map = setNames(c("0101", "0102", "0103"), c("AA", "AC", "AG"))
foo[] <- map[unlist(foo)]
假设map
涵盖foo
中的所有案例。如果foo
是一个矩阵(字符()),那就不会像'黑客'那样在空间和时间上更有效率,那么
matrix(map[foo], nrow=nrow(foo), dimnames=dimnames(foo))
当存在数百万个SNP和数千个样本时,矩阵和数据框架变体都与R的2 ^ 31-1限制了矢量大小。
答案 2 :(得分:14)
这是一个快速解决方案
dict = list(AA = '0101', AC = '0102', AG = '0103')
foo2 = foo
for (i in 1:3){foo2 <- replace(foo2, foo2 == names(dict[i]), dict[i])}
答案 3 :(得分:5)
这里有一些简单的工作:
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
会输出一个我们实际上并不关心的列表。如果您愿意,可以将结果分配给某个东西,然后将其丢弃。我在这里迭代索引,但你可以轻松地将键/ val放在一个列表中并直接迭代它们。请注意使用<<-
进行全局分配。
我用mapply
修改了一个方法,但是我的第一次尝试没有用,所以我换了。我怀疑使用mapply
的解决方案是可行的。
答案 4 :(得分:5)
注意此答案的开始是为了解决How to replace all values in data frame with a vector of values?中发布的更为简单的问题。不幸的是,这个问题被视为实际问题的重复。因此,我将尝试在此处建议基于替换两种情况的因子水平的解决方案。
如果只有一个向量(或一个数据框列) 其价值需要被替换和对使用因素没有异议我们可以强制推理因子并根据需要改变因子水平:
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
包可以在一行中完成:
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
如果需要替换数据帧的多列的所有值,则可以扩展该方法。
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
应完成,即包含原始数据框的受影响列中的所有可能值。 (使用unique(sort(unlist(foo)))
进行验证)。否则,任何缺失的值都将被强制转换为<NA>
。请注意,这也是Martin Morgans's answer的要求。
因此,如果只有几个不同的值需要替换,那么您可能会更好地使用其中一个答案,例如Ramnath's。
答案 5 :(得分:4)
用stringr::str_replace_all
包中的stringr
替换字符串或字符串向量中的值是最易读的方法之一。 str_replace_all
所需的模式可以是字典,例如
# 1. Made your dictionnary
dictio_replace= c("AA"= "0101",
"AC"= "0102",
"AG"= "0103") # short example of dictionnary.
# 2. Replace all pattern, according to the dictionary-values (only a single vector of string, or a single string)
foo$snp1 <- stringr::str_replace_all(string = foo$snp1,
pattern= dictio_replace) # we only use the 'pattern' option here: 'replacement' is useless since we provide a dictionnary.
使用foo $ snp2和foo $ snp3重复步骤2。如果要转换的向量更多,则最好使用另一个func',以便替换数据帧中每个列/向量中的值而无需重复自己。
答案 6 :(得分:1)
上面使用@ 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"
答案 7 :(得分:1)
由于距离上一个答案已经过了几年,今晚就这个话题提出了一个新问题,主持人关闭了它,我将在此处添加。海报有一个包含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
答案 8 :(得分:0)
使用 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>
答案 9 :(得分:0)
我们也可以使用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)]