【问题标题】:Assignment to subset of a matrix with repeated indices分配给具有重复索引的矩阵子集
【发布时间】:2014-03-10 16:04:56
【问题描述】:

不确定这是否符合 R-Inferno 中的条目,但有人可以评论以下替换工作方式背后的逻辑吗?

foo<-matrix(1:6,2)
bar<-foo[2,c(1,3,1)]
bar
# [1] 2 6 2
foo[2,c(1,3,1)]<-foo[2,c(1,3,1)]+5
foo
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    7    4   11

我的问题是:在生成bar时,重复的坐标导致输出中有重复的元素,但是修改foo时,重复的坐标确实导致重复的加法操作. (相比之下,for(j in c(1,3,1) ) foo[2,j]&lt;-foo[2,j]+5 确实如此)。为什么[&lt;- 本质上忽略了重复索引?

【问题讨论】:

    标签: r subset


    【解决方案1】:

    来自help("[&lt;-")

    子赋值是按顺序完成的,所以如果指定一个索引更多 不止一次会为索引分配最新的值。

    foo<-matrix(1:6,2)
    
    foo[1,rep(1,2)] <- c(1,42)
    
    #     [,1] [,2] [,3]
    #[1,]   42    3    5
    #[2,]    2    4    6
    

    【讨论】:

    • 对——我要问的棘手部分是子赋值忽略了所有以前的子赋值(已将原始 f∞[1,1]foo[1,1] 存储在某处),而不是执行索引条目的最新值的最终子分配。或者:是否所有首先进行分配,将其保存在“安全”的某个地方,然后将分配的值依次放入foo
    • 我没有查看源代码,但我认为(子)赋值是一个简单的 C 循环。牢记这一点,应该清楚发生了什么。循环遍历提供的索引并分配提供的值。如果索引重复,则会再次将值分配给相同的位置,从而覆盖先前分配的值。
    【解决方案2】:

    尝试间接回答 cmets 中的次要问题:

    > vec <- 1:10
    > microbenchmark(
    +       rep(1, 1e4),
    +       vec[rep(1, 1e4)] <- 1:1e4,
    +       vec[1] <- 1e4
    +     )
    Unit: microseconds
                              expr     min       lq   median       uq      max neval
                     rep(1, 10000)  16.457  17.9190  18.2860  19.0170 2561.327   100
     vec[rep(1, 10000)] <- 1:10000 215.395 219.7835 227.8285 233.6795 3437.532   100
                   vec[1] <- 10000   1.463   2.1950   3.2920   3.8405   22.308   100
    

    强烈建议将相同的值一遍又一遍地分配给相同的内存位置,直到只有最后一个占上风。为什么不添加它们只是因为这里的操作是覆盖,而不是添加(尽管这可能不是您所要求的“不会导致重复的添加操作”)。

    请注意,您的循环和您的直接分配是不等价的,因为在您的循环中,您正在阅读、添加、分配、重新阅读、重新添加、重新分配等,而在您的直接分配中,您只阅读一次, 添加到单个向量一次,然后通过覆盖只保留最后一个值。

    “读取”之间的主要区别在于,预期的“输出”是索引向量的向量长度,而“写入”(不包括使用越界索引的情况)向量的长度是受您正在写入的向量的限制。

    【讨论】:

    • 谢谢——描述得很好。
    猜你喜欢
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 2017-12-01
    相关资源
    最近更新 更多