R:在矩阵上应用函数并保持矩阵尺寸

时间:2011-12-20 17:12:56

标签: 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

...而我希望将其保留在具有当前尺寸的矩阵中。我怎么能这样做?谢谢!

4 个答案:

答案 0 :(得分:19)

@Joshua Ulrich(和Dason)有一个很好的答案。在没有函数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方法比apply方法快3倍... vapplysapply更快的原因是sapply {1}}必须分析结果,以确定它可以简化为数字向量。使用vapply,您指定了结果类型(numeric(1)),因此无需猜测...

UPDATE 我想出了另一种(更短的)保留矩阵结构的方法:

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

您只需使用m[] <-将新值分配给对象。然后保留所有其他属性(例如dimdimnamesclass等。

答案 1 :(得分:13)

一种方法是在行和列上使用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

答案 2 :(得分:8)

对于这个具体的例子,你可以做这样的事情

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

答案 3 :(得分:7)

使用ifelse对Dason和Josh的解决方案略有改进。

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