【问题标题】:Applying a function to multiple arrays/matrices in R将函数应用于 R 中的多个数组/矩阵
【发布时间】:2013-09-10 19:21:59
【问题描述】:

给定两个数组:

a = array(1:3)
b = array(3:1)

我想应用一个函数,依次将A的每个元素的值与B的每个元素的值进行比较,并返回结果。

类似:

compare = function(xa, xb) { if (xa < xb) { 1 } else { 0 } }

...其中 xa 是 a 数组中的一个元素,xb 是 b 数组中的一个元素。

是否有 apply 的派生可以用来完成此操作?

【问题讨论】:

  • 在查看了发布 CV 要求的问题后,可能应该将其移至 Stack Overflow。如果那里更合适,任何有声誉的人都可以随意。

标签: r matrix function


【解决方案1】:

我偶然发现了“mapply”,这似乎可以解决问题:

> gg = function(x,y){ if(x < y) { 1 } else { 0 }}
> gg(1,2)
[1] 1
> gg(2,1)
[1] 0
> mapply(gg, 1:4, 4:1)
[1] 1 1 0 0

【讨论】:

  • 我无意粗鲁,但这是非常低效的 R 代码。无论是性能还是可读性。
  • 关于为什么这是低效和不可读的任何建议?我是 R 的新手,如果这很明显,我将不胜感激。
  • 函数&lt; 可以在一次调用中比较任何给定大小的向量 xy。使用mapply,您可以让 R 重新解释每对元素的表达式。因此,使用 as.integer(x&lt;y) 甚至 ifelse(x&lt;y, 1, 0) 之类的代码,您不仅可以获得更快的代码,还可以获得更紧凑的表达式。
  • 好的,有道理。谢谢
【解决方案2】:

而不是mapply,我会使用 R 内部循环规则来处理矢量化函数。如果ab 的长度相同,您只需这样做:

as.integer( a < b )
#[1] 1 0 0

as.integer 只是用来强制转换为10,实际上TRUEFALSE 在任何后续的乘法运算中将表现为10

示例

set.seed(1); a <- sample(10)
#[1]  3  4  5  7  2  8  9  6 10  1

set.seed(2); b <- sample(10)
#[1]  2  7  5 10  6  8  1  3  4  9

a < b
#[1] FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE

a * ( a < b )
#[1] 0 4 0 7 2 0 0 0 0 1

a[ a < b ]
#[1] 4 7 2 1

有些人可能会感到惊讶,但&lt; 是一个函数。它在文件/src/main/relop.c 中调用一个名为do_relop 的底层C 函数(所有逻辑比较器都这样做——它们只是使用不同的开关进行比较类型)来处理向量回收。你可以这样写&lt;

`<`( a , b )
#[1] FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE

基准测试

使用基本的 &lt; 运算符(在一对 1e6 长度的向量上)比使用 ifelse(也是一个向量化函数)快 100 倍以上:

set.seed(1); a <- sample(10,1e6,repl=T)
set.seed(2); b <- sample(10,1e6,repl=T)
require( microbenchmark)
bm <- microbenchmark( comparealt(a,b) , `<`(a,b) , times = 25L )
print( bm , digits = 3 , unit = "relative" , order = "median" )
#Unit: relative
#             expr min  lq median  uq  max neval
#            a < b   1   1      1   1  1.0    25
# comparealt(a, b) 131 126    122 105 48.3    25

【讨论】:

  • 如果您比较“A 的每个元素与 B 的每个元素的值”,您不会期望 100 个 TRUE 或 FALSE 结果吗?
  • @Henry 我认为您误解了这个问题。查看 OP 提供的答案中的输出。我相信他们指的是元素方面的比较,而不是外部产品。我认为x 在他们的伪函数中是一个索引向量。
  • 我在原始问题中没有看到示例,但现在我看到 juwiley 也给出了答案,所以您可能是正确的。
  • @Henry 其中 xa 是 a 数组中的一个元素,xb 是 b 数组中的一个元素。 我认为 x 是同一个元素来自两个数组,因此是元素方面的。
  • 很好的答案,不幸的是我的用例可能不清楚。我需要将变量传递给函数,并用于比较,所以简单的 a
【解决方案3】:

我最初阅读“A的每个元素到B的每个元素的值”意思是外连接并建议:

compare <- function(x, y){ outer(x, y, FUN="<")+0 }

例如给出

> compare(array(1:6), array(5:3))
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    1    1    1
[3,]    1    1    0
[4,]    1    0    0
[5,]    0    0    0
[6,]    0    0    0

为了比较相同维度的矩阵元素,你可以使用类似

comparemat <- function(mat1, mat2){ (mat1 < mat2)+0 }

comparealt <- function(mat1, mat2){ ifelse(mat1 < mat2, 1, 0) }

其中任何一个

comparemat(matrix(1:12,nrow=4), matrix(12:1,nrow=4)) 
comparealt(matrix(1:12,nrow=4), matrix(12:1,nrow=4)) 

     [,1] [,2] [,3]
[1,]    1    1    0
[2,]    1    1    0
[3,]    1    0    0
[4,]    1    0    0

【讨论】:

  • 你为什么要定义 comparealt &lt;- function(mat1, mat2){ ifelse(mat1 &lt; mat2, 1, 0) } 来使用 ifelse 而你可以只做 matrix(1:12,nrow=4) &lt; matrix(12:1,nrow=4)?!
  • 这是一个函数,因为这是问题所要求的。 comparemat 给出了您要求的简单比较,而 comparealt 使用 ìfelse 来说明向量化的 if,对于大型案例,这似乎比在 juwiley 的 gganswer 中映射 ìf 快 8 倍以上(尽管比 comparemat 慢 8 倍)
  • &lt; 一个函数。请参阅我的问题中的编辑,以了解表达此功能的稍微令人惊讶的方式。 a &lt; b 是方便表示法,但 &lt; 使用 LTOP 开关调用名为 do_relopC 函数以对 &lt; 进行逻辑比较。不要重新发明轮子以使情况变得更糟!我只是想帮你。如果你真的想要,你可以做flt &lt;- function( a , b ) a &lt; b,但这同样愚蠢! &lt; 也适用于矩阵元素。
  • @SimonO101 &lt; 给出布尔结果,但问题要求输入数字,因此您需要进行转换。一种方法是添加 0,它保留任何矩阵结构,这就是 comparemat 所做的。
  • 好吧,我放弃了。最后一次尝试:TRUE == 1 ; FALSE == 0 我建议尝试一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 2015-05-08
  • 1970-01-01
  • 2015-04-23
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多