El estilo del diccionario reemplaza varios elementos

Tengo un gran data.frame of character data que quiero convertir basado en lo que comúnmente se llama un diccionario en otros idiomas.

Actualmente lo estoy haciendo así:

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") 

Esto funciona bien, pero obviamente no es bonito y parece una tontería repetir la statement de replace cada vez que quiero reemplazar un elemento en el dataframe.

¿Hay alguna forma mejor de hacerlo ya que tengo un diccionario de aproximadamente 25 pares de clave / valor?

 map = setNames(c("0101", "0102", "0103"), c("AA", "AC", "AG")) foo[] <- map[unlist(foo)] 

suponiendo que el map cubra todos los casos en foo . Esto se sentiría menos como un 'hack' y sería más eficiente tanto en el espacio como en el tiempo si foo fuera una matriz (de carácter ()), luego

 matrix(map[foo], nrow=nrow(foo), dimnames=dimnames(foo)) 

Tanto la matriz como las variantes del dataframe están en conflicto con el límite de R ^ 2 ^ 31-1 en el tamaño del vector cuando hay millones de SNP y miles de muestras.

Si está abierto a usar paquetes, plyr es muy popular y tiene esta útil función mapvalues ​​() que hará justo lo que está buscando:

 foo <- mapvalues(foo, from=c("AA", "AC", "AG"), to=c("0101", "0102", "0103")) 

Tenga en cuenta que funciona para tipos de datos de todo tipo, no solo cadenas.

Aquí hay una solución rápida

 dict = list(AA = '0101', AC = '0102', AG = '0103') foo2 = foo for (i in 1:3){foo2 <- replace(foo2, foo2 == names(dict[i]), dict[i])} 

Aquí hay algo simple que hará el trabajo:

 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  2 0103 AT GG 3 0101 0103 GG 4 0101 0101 GC 

lapply generará una lista en este caso que en realidad no nos importa. Podría asignar el resultado a algo si lo desea y luego simplemente descartarlo. Estoy iterando sobre los índices aquí, pero también podría colocar fácilmente la clave / val en una lista e iterar sobre ellos directamente. Tenga en cuenta el uso de la asignación global con <<- .

Hice algunos ajustes para hacer esto con mapply pero mi primer bash no funcionó, así que cambié. Sospecho que una solución con mapply es posible, sin embargo.

Tenga en cuenta que esta respuesta comenzó como un bash de resolver el problema mucho más simple publicado en ¿Cómo reemplazar todos los valores en el dataframe con un vector de valores? . Lamentablemente, esta pregunta se cerró como duplicado de la pregunta real. Entonces, intentaré sugerir una solución basada en reemplazar los niveles de factor para ambos casos, aquí.


En caso de que solo haya un vector (o una columna de dataframe) cuyos valores necesiten ser reemplazados y no haya objeciones al factor de uso, podemos forzar al vector a factorizar y cambiar los niveles de los factores según sea necesario:

 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] AACCGGAAT #Levels: ATCG 

Usando el paquete de forcats , esto se puede hacer de una sola línea:

 x <- c(1, 1, 4, 4, 5, 5, 1, 1, 2) forcats::lvls_revalue(factor(x), replacement_vec) #[1] AACCGGAAT #Levels: ATCG 

En caso de que todos los valores de múltiples columnas de un dataframe deban ser reemplazados, el enfoque puede extenderse.

 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  #2 0103 0104 0303 #3 0101 0103 0303 #4 0101 0101 0302 

Tenga en cuenta que level_vec y replacement_vec deben tener longitudes iguales.

Más importante aún, level_vec debe estar completo , es decir, incluir todos los valores posibles en las columnas afectadas del dataframe original. (Use unique(sort(unlist(foo))) para verificar). De lo contrario, cualquier valor faltante será forzado a . Tenga en cuenta que esto también es un requisito para la respuesta de Martin Morgans .

Entonces, si solo hay unos pocos valores diferentes que reemplazar, probablemente estará mejor con una de las otras respuestas, por ejemplo, Ramnath's .

Usó la respuesta de @Ramnath anterior, pero lo hizo leer (qué reemplazar y qué reemplazar) de un archivo y usar gsub en lugar de reemplazar.

 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 contiene la siguiente pestaña separada

 "from" "to" "AA" "0101" "AC" "0102" "AG" "0103" 

Dado que han pasado algunos años desde la última respuesta, y una nueva pregunta surgió esta noche sobre este tema y un moderador la cerró, la agregaré aquí. El póster tiene un gran dataframe que contiene 0, 1 y 2, y desea cambiarlos a AA, AB y BB, respectivamente.

Utilice 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  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  0 1  4 1 2  2 2 2 1 1 0 1 ... to 10th row > df[] <- lapply(df, as.character) 

Cree una función sobre el dataframe utilizando revalue para reemplazar varios términos:

 > 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 
Intereting Posts