r

¿Cómo reemplazar cierto valor del marco de datos con su nombre de columna desconocido?



(6)

Tengo un marco de datos grande con nombres de columna desconocidos y valores numéricos 1, 2, 3 o 4. Ahora quiero reemplazar los 4 valores con su nombre de columna y todos los 1, 2 y 3 con un valor vacío.

Por supuesto, puedo hacer un bucle de algún tipo, como este:

df <- data.frame(id=1:8,unknownvarname1=c(1:4,1:4),unknownvarname2=c(4:1,4:1)) for (i in 2:length(df)){ df[,i] <- as.character(df[,i]) df[,i] <- mgsub::mgsub(df[,i],c(1,2,3,4),c("","","",names(df)[i])) }

Este sería el resultado:

id unknownvarname1 unknownvarname2 1 1 unknownvarname2 2 2 3 3 4 4 unknownvarname1 5 5 unknownvarname2 6 6 7 7 8 8 unknownvarname1 unknownvarname2

Para un marco de datos de este tamaño no hay ningún problema. Pero cuando pruebo este ciclo en grandes marcos de datos con hasta 30k y hasta 40 variables desconocidas, el ciclo tarda años en completarse.

¿Alguien sabe de una manera más rápida de hacer esto? Intenté funciones como dplyr package mutate() del dplyr package pero no pude lograr que funcionara.

¡Muchas gracias de antemano!


Otra opción más de base R, usando ifelse dentro de lapply (todavía girando en las columnas, pero enfoque vectorizado por columna):

df <- data.frame(id=1:8,unknownvarname1=c(1:4,1:4),unknownvarname2=c(4:1,4:1)) df[,2:3] <- lapply(2:3, function(x) { ifelse(df[,x] < 4, "", colnames(df)[x]) })

da

id unknownvarname1 unknownvarname2 1 1 unknownvarname2 2 2 3 3 4 4 unknownvarname1 5 5 unknownvarname2 6 6 7 7 8 8 unknownvarname1


Otra opción más que usa col para alinear los nombres y valores:

sel <- df[-1]==4 df[-1] <- "" df[-1][sel] <- names(df[-1])[col(df[-1])[sel]] # id unknownvarname1 unknownvarname2 #1 1 unknownvarname2 #2 2 #3 3 #4 4 unknownvarname1 #5 5 unknownvarname2 #6 6 #7 7 #8 8 unknownvarname1


Otra posibilidad de base R usando sweep :

idx <- df[, -1] == 4 sw <- sweep(idx, 2, 1:2, FUN = ''*'') + 1 df[, -1] <- c("", colnames(df[, -1]))[sw]

lo que da:

> df id unknownvarname1 unknownvarname2 1 1 unknownvarname2 2 2 3 3 4 4 unknownvarname1 5 5 unknownvarname2 6 6 7 7 8 8 unknownvarname1

Esto podría acortarse a:

sw <- sweep(df[, -1] == 4, 2, 1:2, FUN = ''*'') + 1 df[, -1] <- c("", colnames(df[, -1]))[sw]


Solo para dar otra opción con el switch (aunque, como esta función no está vectorizada, necesita una aplicación anidada dentro de una lapply que no la hace tan "bonita" y eficiente ...):

Básicamente, el switch funciona con switch(myNumberToTest, caseIfOne, caseIfTwo, ...) como switch(myNumberToTest, caseIfOne, caseIfTwo, ...) .

Entonces, lo que necesitas es:

df[, 2:3] <- lapply(2:3, function(x) sapply(df[, x], switch, "", "", "", names(df)[x])) df # id unknownvarname1 unknownvarname2 #1 1 unknownvarname2 #2 2 #3 3 #4 4 unknownvarname1 #5 5 unknownvarname2 #6 6 #7 7 #8 8 unknownvarname1


Una opción tidyverse algo ineficiente. Esto es ineficiente porque necesitamos seleccionar manualmente las columnas más adelante:

to_use <- names(df)[-1] df %>% mutate_at(vars(contains("unknown")),list(~ifelse(.==4, NA, ""))) -> new_df new_df[-1] <-map2(new_df[-1], to_use,function(x,y) replace(x,is.na(x),y))

Un enfoque menos manual que también tiene la desventaja de no ser específico:

df %>% map2(.,names(.), function(x, y) ifelse( x==4, y,"")) %>% as.data.frame() %>% mutate(id=row.names(.)) # might be a way around with `.id` id unknownvarname1 unknownvarname2 1 1 unknownvarname2 2 2 3 3 4 4 unknownvarname1 5 5 unknownvarname2 6 6 7 7 8 8 unknownvarname1

Resultado para el enfoque 1:

new_df id unknownvarname1 unknownvarname2 1 1 unknownvarname2 2 2 3 3 4 4 unknownvarname1 5 5 unknownvarname2 6 6 7 7 8 8 unknownvarname1


Unidireccional usando la base R

#Replace all the values with 1:3 with blank df[-1][sapply(df[-1], `%in%`, 1:3)] <- "" #Get the row/column indices where value is 4 mat <- which(df == 4, arr.ind = TRUE) #Exclude values from first column mat <- mat[mat[, 2] != 1, ] #Replace remaining entries with it''s corresponding column names df[mat] <- names(df)[mat[, 2]] df # id unknownvarname1 unknownvarname2 #1 1 unknownvarname2 #2 2 #3 3 #4 4 unknownvarname1 #5 5 unknownvarname2 #6 6 #7 7 #8 8 unknownvarname1