Применение функции к каждой строке матрицы или фрейма данных



предположим, что у меня есть матрица n на 2 и функция, которая принимает 2-вектор в качестве одного из своих аргументов. Я хотел бы применить функцию к каждой строке матрицы и получить n-вектор. Как это сделать в R?

например, я хотел бы вычислить плотность 2D стандартного нормального распределения по трем точкам:

bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
    exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}

out <- rbind(c(1, 2), c(3, 4), c(5, 6))

Как применить функцию к каждой строке out?

Как передать значения для других аргументов, кроме точек функция в том, как вы укажете?

132   6  

6 ответов:

вы просто использовать apply() функция:

R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1]  4 10 16
R> 

Это берет матрицу и применяет (глупую) функцию к каждой строке. Вы передаете дополнительные аргументы функции как четвертый, пятый, ... аргументы для apply().

если вы хотите применить общие функции, такие как sum или mean, вы должны использовать rowSums или rowMeans так как они быстрее, чем apply(data, 1, sum) подход. В противном случае, придерживайтесь apply(data, 1, fun). Вы можете передать дополнительные аргументы после забавного аргумента (как уже предложил Дирк):

set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
     [,1] [,2] [,3] [,4]
[1,]   NA    5    2    3
[2,]    2   NA    2    4
[3,]    3    4   NA    5
[4,]    5    4    3   NA
[5,]    2    1    4    4

затем вы можете сделать что-то вроде этого:

apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
    [,1] [,2] [,3] [,4] [,5]
25%  2.5    2  3.5  3.5 1.75
50%  3.0    2  4.0  4.0 3.00
75%  4.0    3  4.5  4.5 4.00

вот краткий пример применения функции к каждой строке матрицы. (Здесь применяемая функция нормализует каждую строку на 1.)

Примечание: результат apply() должен быть транспонировать используя t() чтобы получить тот же макет, что и входная матрица A.

A <- matrix(c(
  0, 1, 1, 2,
  0, 0, 1, 3,
  0, 0, 1, 3
), nrow = 3, byrow = TRUE)

t(apply(A, 1, function(x) x / sum(x) ))

результат:

     [,1] [,2] [,3] [,4]
[1,]    0 0.25 0.25 0.50
[2,]    0 0.00 0.25 0.75
[3,]    0 0.00 0.25 0.75

первым шагом будет создание объекта функции, а затем его применение. Если вы хотите матричный объект, который имеет такое же количество строк, вы можете предварительно определить его и использовать форму object [], как показано на рисунке (в противном случае возвращаемое значение будет упрощено до вектора):

bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
     exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
                           x[2]^2/sigma[2]^2-
                           2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 
     1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
     }
 out=rbind(c(1,2),c(3,4),c(5,6));

 bvout<-matrix(NA, ncol=1, nrow=3)
 bvout[] <-apply(out, 1, bvnormdens)
 bvout
             [,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15

Если вы хотите использовать другие параметры, кроме параметров по умолчанию, то вызов должен включать именованные аргументы после функции:

bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)

применить() также можно использовать на массивах более высоких размеров и аргумент MARGIN может быть вектором, а также одним целым числом.

применить делает работу хорошо, но довольно медленно. Использование sapply и vapply может быть полезно. dplyr rowwise также может быть полезен Давайте рассмотрим пример того, как сделать row wise продуктом любого фрейма данных.

a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)

обратите внимание, что назначение переменной перед использованием vapply/sapply/ apply является хорошей практикой, поскольку это значительно сокращает время. Давайте посмотрим результаты microbenchmark

a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
    apply(b, 1 , prod),
    vapply(a, prod, 0),
    sapply(a, prod) , 
    apply(iris[1:10,1:3], 1 , prod),
    vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
    sapply(data.frame(t(iris[1:10,1:3])), prod) ,
    b %>%  rowwise() %>%
        summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)

внимательно посмотрите, как используется t ()

другой подход, если вы хотите использовать различную часть набора данных вместо одного значения-использовать rollapply(data, width, FUN, ...). Использование вектора ширины позволяет применить функцию к изменяющемуся окну набора данных. Я использовал это, чтобы построить адаптивную процедуру фильтрации, хотя это не очень эффективно.

    Ничего не найдено.

Добавить ответ:
Отменить.