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

StackOverflow https://stackoverflow.com/questions/4236368

Вопрос

Предположим, у меня есть матрица на 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?

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

Это было полезно?

Решение

Вы просто используете 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().

Другие советы

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

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

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

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)

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

Подать заявку хорошо, но довольно медленно. Использование Sapply и Vapply может быть полезным. Rowwise Dlyr Bally также может быть полезным, давайте увидим пример того, как сделать подряд мудрый продукт любого кадра данных.

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, ...). Отказ Использование вектора ширины позволяет вам применить функцию в различной окне набора данных. Я использовал это, чтобы построить адаптивную фильтрацию рутины, хотя она не очень эффективна.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top