Вопрос по r, dataframe – использовать несколько столбцов в качестве переменных с sapply

27

у меня естьdataframe и я хотел бы применить функцию, которая принимает значения трех столбцов и вычисляет минимальную разницу между тремя значениями.

<code>#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))
}
</code>

Я ищу что-то вроде:

<code>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
</code>

Пока я могу использовать ddply:

<code>df2 <- ddply(df,.(a),function(r) {data.frame(min_distance=minimum_distance(r$a,r$b, r$c))}, .drop=FALSE)
</code>

Это не сохраняет все столбцы. Какие-либо предложения?

Изменить: я в конечном итоге с помощью:

<code>df$distance <- mapply(minimum_distance, df$a, df$b, df$c)
</code>

Ваш Ответ

4   ответа
6

do.call("mapply", c(list(minimum_distance), df))

но вы можете написать векторизованную версию:

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)
это умно, но немного менее просто, спасибо mapply. zach
5

что на этот вопрос дан ответ, но на самом деле я выбрал другой подход, который использует любое количество столбцов и является более обобщенным с использованием внешнего подхода:

vdiff <- function(x){
    y <- outer(x, x, "-")
    min(abs(y[lower.tri(y)]))
}

apply(df, 1, vdiff)

Я думаю, что это немного чище и гибче.

РЕДАКТИРОВАТЬ: В комментариях zach я предлагаю эту более формализованную функцию, которая также работает с фреймами данных с нечисловыми столбцами, удаляя их и воздействуя только на числовые столбцы.

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)
хорошая идея. Мой реальный фрейм данных не является матрицей - может ли это быть изменено для использования в фрейме данных с текстовыми столбцами? что-то вроде external (x, x, & quot; - & quot ;, drop_string = T)? zach
в этом случае скорость не проблема, но я буду иметь это в виду. спасибо Тайлер zach
очень хорошо. Я согласен, что external достаточно мощный и что для более крупной матрицы это был бы путь, а не указание каждого столбца или значения. zach
Примечание. Поскольку этот ответ является более обобщенным, вполне вероятно, что он также медленнее, и мы не уверены, насколько высока скорость проблемы (т. Е. Насколько велик ваш набор данных).
Функцияouter не обязательно означает, что вы работаете над матрицей. Он просто берет два вектора и функцию и создает матрицу всех возможных комбинаций для этих двух векторов. Здесь я просто поставляю один и тот же вектор (строку) для внешнего дважды и вычитание функции- оператор. Я добавил немного в свое решение, чтобы создать автономную функцию, которая действует на фреймы данных и исключает все, что не является числовым.outer может быть очень мощным, я просто хотел бы помнить, чтобы использовать его больше. Насколько drop_string = T? Нет такой удачи, ноsapply сis.numeric запрос работает хорошо.
1

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

qq <- mapply(minimum_distance, df$a, df$b, df$c)
Какой из них самый быстрый? или более эффективный?
просто и элегантно Спасибо zach

Похожие вопросы