¿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