R: применение функции над матрицей и сохранение размеров матрицы - программирование
Подтвердить что ты не робот

R: применение функции над матрицей и сохранение размеров матрицы

Итак, я хочу применить функцию по матрице в 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

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

4b9b3361

Ответ 1

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

UPDATE Я выяснил другой (более короткий) способ сохранения структуры матрицы:

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

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

Ответ 2

Один из способов - использовать 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

Ответ 3

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

> # 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

Ответ 4

Там небольшое усовершенствование решения Dason и Josh с использованием 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