graficos - usar columnas mĂșltiples como variables con sapply
mapply in r (4)
Tengo un dataframe
y me gustaría aplicar una función que tome los valores de tres columnas y calcule la diferencia mínima entre los tres valores.
#dataset
df <- data.frame(a= sample(1:100, 10),b = sample(1:100, 10),c= sample(1:100, 10))
#function
minimum_distance <- function(a,b,c)
{
dist1 <- abs(a-b)
dist2 <- abs(a-c)
dist3 <- abs(b-c)
return(min(dist1,dist2,dist3))
}
Estoy buscando algo como:
df$distance <- sapply(df, function(x) minimum_distance(x$a,x$b,x$c) )
## errormessage
Error in x$a : $ operator is invalid for atomic vectors
Si bien puedo usar ddply:
df2 <- ddply(df,.(a),function(r) {data.frame(min_distance=minimum_distance(r$a,r$b, r$c))}, .drop=FALSE)
Esto no mantiene todas las columnas. ¿Alguna sugerencia?
Editar: terminé usando:
df$distance <- mapply(minimum_distance, df$a, df$b, df$c)
Es mejor escribir una función y luego usar mapply en los vectores:
f1 <- function(a,b,c){
d =abs(a-b)
e =abs(b-c)
f= abs(c-a)
return(pmin(d,e,f))
}
qq <- mapply(f1, df$a, df$b, df$c)
Pruebe mapply ():
qq <- mapply(minimum_distance, df$a, df$b, df$c)
Sé que esto ha sido respondido, pero en realidad tomaría un enfoque diferente que toma cualquier cantidad de columnas y es más generalizable usando un enfoque externo:
vdiff <- function(x){
y <- outer(x, x, "-")
min(abs(y[lower.tri(y)]))
}
apply(df, 1, vdiff)
Creo que esto es un poco más limpio y flexible.
EDITAR: Según los comentarios de zach, propongo esta función más formalizada que también funciona en marcos de datos con columnas no numéricas, eliminándolos y actuando solo en las columnas numéricas.
cdif <- function(dataframe){
df <- dataframe[, sapply(dataframe, is.numeric)]
vdiff <- function(x){
y <- outer(x, x, "-")
min(abs(y[lower.tri(y)]))
}
return(apply(df, 1, vdiff))
}
#TEST it out
set.seed(10)
(df <- data.frame(a = sample(1:100, 10), b = sample(1:100, 10),
c = sample(1:100, 10), d = LETTERS[1:10]))
cdif(df)
prueba esto:
do.call("mapply", c(list(minimum_distance), df))
pero puedes escribir una versión vectorizada:
pminimum_distance <- function(a,b,c)
{
dist1 <- abs(a-b)
dist2 <- abs(a-c)
dist3 <- abs(b-c)
return(pmin(dist1,dist2,dist3))
}
pminimum_distance(df$a, df$b, df$c)
# or
do.call("pminimum_distance", df)