R: применение функции к матрице и сохранение размеров матрицы - PullRequest
27 голосов
/ 20 декабря 2011

Итак, я хочу применить функцию к матрице в R. Это действительно интуитивно понятно для простых функций:

> (function(x)x*x)(matrix(1:10, nrow=2))
 [,1] [,2] [,3] [,4] [,5]
[1,]    1    9   25   49   81
[2,]    4   16   36   64  100

... но, очевидно, я не понимаю всех ее функций:

> m = (matrix(1:10, nrow=2))
> (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) })(m)
     [,1] [,2] [,3] [,4] [,5]
[1,]    2    4    6    8   10
[2,]    3    5    7    9   11
Warning message:
In if (x == 3) { :
  the condition has length > 1 and only the first element will be used

Я прочитал об этом и узнал о Vectorize и sapply, которые оба выглядели великолепно и точно так же, как я хотел, за исключением того, что они оба преобразовали мою матрицу в список:

> y = (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) })
> sapply(m, y)
 [1]  2  3 NA  5  6 NA  8  9 NA 11
> Vectorize(y)(m)
 [1]  2  3 NA  5  6 NA  8  9 NA 11

... тогда как я хотел бы сохранить его в матрице с текущими размерами.Как я могу это сделать?Спасибо!

Ответы [ 4 ]

20 голосов
/ 20 декабря 2011

@ У Джошуа Ульриха (и Дэйсона) отличный ответ. И делать это напрямую без функции y - лучшее решение. Но если вам действительно нужно для вызова функции, вы можете сделать это быстрее, используя vapply. Он создает вектор без измерений (как sapply, но быстрее), но затем вы можете добавить их обратно, используя structure:

# Your function (optimized)
y = function(x) if (x %% 3) x+1 else NA

m <- matrix(1:1e6,1e3)
system.time( r1 <- apply(m,1:2,y) ) # 4.89 secs
system.time( r2 <- structure(sapply(m, y), dim=dim(m)) ) # 2.89 secs
system.time( r3 <- structure(vapply(m, y, numeric(1)), dim=dim(m)) ) # 1.66 secs
identical(r1, r2) # TRUE
identical(r1, r3) # TRUE

... Как вы видите, подход vapply примерно в 3 раза быстрее, чем apply ... И причина vapply быстрее, чем sapply в том, что sapply должен анализировать результат, чтобы вычислить что это может быть упрощено до числового вектора. С vapply вы указали тип результата (numeric(1)), поэтому не нужно угадывать ...

ОБНОВЛЕНИЕ Я нашел другой (более короткий) способ сохранения структуры матрицы:

m <- matrix(1:10, nrow=2)
m[] <- vapply(m, y, numeric(1))

Вы просто присваиваете новые значения объекту, используя m[] <-. Затем все остальные атрибуты сохраняются (например, dim, dimnames, class и т. Д.).

13 голосов
/ 20 декабря 2011

Одним из способов является использование apply для строк и столбцов:

apply(m,1:2,y)
     [,1] [,2] [,3] [,4] [,5]
[1,]    2   NA    6    8   NA
[2,]    3    5   NA    9   11

Вы также можете сделать это с помощью подписки, поскольку == уже векторизовано:

m[m %% 3 == 0] <- NA
m <- m+1
m
     [,1] [,2] [,3] [,4] [,5]
[1,]    2   NA    6    8   NA
[2,]    3    5   NA    9   11
8 голосов
/ 20 декабря 2011

Для этого конкретного примера вы можете просто сделать что-то вроде этого

> # Create some fake data
> mat <- matrix(1:16, 4, 4)
> # Set all elements divisible by 3 to NA
> mat[mat %% 3 == 0] <- NA
> # Add 1 to all non NA elements
> mat <- mat + 1
> mat
     [,1] [,2] [,3] [,4]
[1,]    2    6   NA   14
[2,]    3   NA   11   15
[3,]   NA    8   12   NA
[4,]    5    9   NA   17
7 голосов
/ 20 декабря 2011

Есть небольшое уточнение решения Дейсона и Джоша с использованием ifelse.

mat <- matrix(1:16, 4, 4)
ifelse(mat %% 3 == 0, NA, mat + 1)
     [,1] [,2] [,3] [,4]
[1,]    2    6   NA   14
[2,]    3   NA   11   15
[3,]   NA    8   12   NA
[4,]    5    9   NA   17
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...