求教社区里的各位大神一个在向量切片(subsetting)中使用通道运算符(pipe)的实际操作问题。
有以下代码段落:

k=array(0,c(10,20))
for (i in 1:5)
{
  for (j in 1:5)
  {
    k[2*i, c(2*j+1, 2*j+3, 2*j+4)]=rnorm(1)
  }
}

这个代码段是没有问题的,其目的是对矩阵中某些有规律的位置上的元素进行改变(跟我实际需求相比做了简化,但不影响问题本质)。得到结果如下:

> print(k, digits=2)
      [,1] [,2]  [,3] [,4]  [,5]  [,6]  [,7]  [,8]   [,9] [,10] [,11]  [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20]
 [1,]    0    0  0.00    0  0.00  0.00  0.00  0.00  0.000  0.00  0.00  0.000  0.00  0.00     0     0     0     0     0     0
 [2,]    0    0  0.63    0  0.97  0.63 -0.68  0.97  0.059 -0.68 -1.13  0.059 -1.13 -1.13     0     0     0     0     0     0
 [3,]    0    0  0.00    0  0.00  0.00  0.00  0.00  0.000  0.00  0.00  0.000  0.00  0.00     0     0     0     0     0     0
 [4,]    0    0 -1.27    0  1.05 -1.27  0.29  1.05  1.230  0.29  0.47  1.230  0.47  0.47     0     0     0     0     0     0
 [5,]    0    0  0.00    0  0.00  0.00  0.00  0.00  0.000  0.00  0.00  0.000  0.00  0.00     0     0     0     0     0     0
 [6,]    0    0 -0.84    0 -0.82 -0.84 -0.24 -0.82 -0.713 -0.24  0.11 -0.713  0.11  0.11     0     0     0     0     0     0
 [7,]    0    0  0.00    0  0.00  0.00  0.00  0.00  0.000  0.00  0.00  0.000  0.00  0.00     0     0     0     0     0     0
 [8,]    0    0 -0.40    0  0.59 -0.40 -0.26  0.59  1.151 -0.26 -0.95  1.151 -0.95 -0.95     0     0     0     0     0     0
 [9,]    0    0  0.00    0  0.00  0.00  0.00  0.00  0.000  0.00  0.00  0.000  0.00  0.00     0     0     0     0     0     0
[10,]    0    0  0.18    0 -0.45  0.18 -0.87 -0.45  1.820 -0.87 -2.01  1.820 -2.01 -2.01     0     0     0     0     0     0

我遇到的问题是当使用通道运算符进行简化的时候,矩阵并不会被修改:

library(magrittr)
k=array(0,c(10,20))
for (i in 1:5)
{
  for (j in 1:5)
  {
    (2*j) %>% {k[2*i, c(.+1, .+3, .+4)]=rnorm(1)}
  }
}

执行以上代码会得到以下结果:

> k
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20]
 [1,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [2,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [3,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [4,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [5,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [6,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [7,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [8,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
 [9,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0
[10,]    0    0    0    0    0    0    0    0    0     0     0     0     0     0     0     0     0     0     0     0

附系统环境信息:

> sessionInfo()
R version 3.3.2 (2016-10-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

locale:
[1] LC_COLLATE=Chinese (Simplified)_China.936  LC_CTYPE=Chinese (Simplified)_China.936    LC_MONETARY=Chinese (Simplified)_China.936
[4] LC_NUMERIC=C                               LC_TIME=Chinese (Simplified)_China.936    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] magrittr_1.5

loaded via a namespace (and not attached):
[1] tools_3.3.2

谢谢!

    Heterogeneity

    有关全局赋值符,可以参见
    https://stat.ethz.ch/pipermail/r-help/2011-April/275905.html
    https://stat.ethz.ch/R-manual/R-devel/library/base/html/assignOps.html

    =作为赋值号,只能在顶层表达式中使用。
    (不过循环体内有时候也可以用啊?)

    2019-02-26 注:我所谓的“全局赋值符”应该是上层赋值符。

    yihui 人们对 <<- 最常见的误解就是以为它是全局赋值符,但它并不是,它只是上层赋值符。如果一个对象在上层环境中不存在,那么接着到上上层中找,一直找到全局环境。如果全局环境中也不存在,R 会在全局环境中创建这个对象。

    看了有关于上层赋值符的一些材料,有如下猜测:并不是循环体的问题,而是函数的问题。通道运算符是以运算符的形式提供了一个函数,而本贴中的例子就是在函数中赋值的:

    Heterogeneity (2*j) %>% {k[2*i, c(.+1, .+3, .+4)]=rnorm(1)}

    所以在这里,赋值在函数中进行,一旦退出函数,所有的操作结果都会丢失。不论=还是<-都只能在当前层次的环境中进行赋值,所以解决不了这个问题。而上层赋值符<<-可以跳到顶层环境中进行赋值,从而实现目的。

      Heterogeneity 人们对 <<- 最常见的误解就是以为它是全局赋值符,但它并不是,它只是上层赋值符。如果一个对象在上层环境中不存在,那么接着到上上层中找,一直找到全局环境。如果全局环境中也不存在,R 会在全局环境中创建这个对象。

      说实在的,我觉得你有点管道中毒的感觉,这里用管道实在是毫无价值,反增疑惑。本来是个非常简单的赋值操作:

      k[2*i, 2*j + c(1, 3, 4)] = rnorm(1)

      却被写得如此诘屈聱牙:

      (2*j) %>% {k[2*i, c(.+1, .+3, .+4)] <<- rnorm(1)}

      就像好好的一句主动语态的句子,硬用被动语态表达出来一样:

      我今天中午吃了一碗饭。

      一碗饭今天中午被我吃了。

      这碗饭实在让人噎得慌。一个普通 R 用户看见你的一行代码至少得问四个问题:

      1. %>% 是什么?
      2. . 是什么意思?
      3. <<- 是什么操作?
      4. 为什么要用花括号?

      每个问题都不容易回答,涉及到深层技术细节。

      另:你加入论坛晚,不知道大名鼎鼎的颜大站长 @yanlinlin82 很正常,早年间很活跃,是 COS 的大功臣,可惜现在跟众人一样误入微信歧途了,只在微信上回答问题。

        yihui
        (1) 谢谢你告诉我<<-的正确名称,我把这篇帖子相关的地方都改一下吧。

        (2)看了《管道中毒》,五味杂陈……可能是因为R语言的开放吧,所以想把一件事情弄明白反而无比繁琐,成本极高……你指出的四个问题,除了第一个,都是我各处搜或者找人问得到的答案,限于场合或者面子学到的也是一知半解。这么学来的东西不可能以最简洁优雅的方式呈现,只能是补丁摞补丁。

        (3)所以在这里冒天下之大不韪,我在很长一段时间内都是喜欢Matlab完胜过R的,至少人家的帮助文档风格整齐划一,文风清晰好懂。反观R的帮助文档,都是捏着鼻子看。

        (4)大神你给出的方案确实漂亮。服。

        (5)谢谢提点,我觉得还是要感谢一下颜大站长。

          Heterogeneity 更改标题为「【已解决】通道运算符与向量切片

          yihui dapengde 我歪个楼,看到这样的发帖是赏心悦目的,对于经常逛论坛的人来说,自然优先回复,因此,我想怎么标记这种正确的发帖姿势,因为下次遇到很不规范的发帖,就可以从这些规范的发帖中随手选一则过去,可能比起让他去看左上角新手须知好很多,感觉总有人没有耐心规范发帖,比如这贴

          可能立马有人要跳出来反驳我了,你不回就是了,我就这么发帖,毕竟怎么发帖和回帖都没有强制性的规则,比如这贴

          5 天 后

          管道操作必须与纯函数,向量式编程三者联合起来实现数据流编程,才是正确的使用姿势,只需很简单的几个基本组件就可以了,很简单,

          另外,管道是正向前进的顺序结构.

          可以参考一下我的博客PurefunctionPipelineDataflow

            Heterogeneity

            他那博客我看了,通篇比喻来比喻去然而言之无物,拿一堆自造的"看上去很专业"的专有名词堆砌而成。
            通篇就这种感觉:

            FP和OO过度复杂了,在大工业上是行不通的,还是属于手工作坊那种强调个人技术的生产方式, 个人技术极大影响了产品质量,极不可靠的生产方式。FP和OO其实全是在走弯路, 花拳秀腿,花样作死。

            大概率是个民科。不过计算机的民科我还是第一次见…


            搜了一下,这么想的人看来不止我一个:

            拿这篇小文章到处贴来贴去不过反应寥寥

            https://news.ycombinator.com/item?id=18844310

            https://clojureverse.org/t/warehouse-workshop-model-update-the-pure-function-pipeline-data-flow/3729/2

            https://news.ycombinator.com/item?id=18967811

            https://news.ycombinator.com/item?id=18967837

            还在wikipedia里加了个链接,这应该算是原创研究吧,wiki不欢迎的那种

            https://en.wikipedia.org/wiki/Dataflow_programming

              @tctcab
              至少我用这种方法构造了一个几万行的项目.
              构造了从clojure到R语言基于语法树的DSL,
              是来自实践的总结, 我博文里讲得很清楚了,
              也有范例代码, 如果有问题可以具体提出,
              我会回答的,泛泛地提问我不知从何说起.

              另外,想象力很重要.搞分析的人思维不要太江化:-)
              以前在Clojure群,有人说我神棍, 据我发现, 都是
              初级人员.

              真功夫很简单, 小文章就够了, 搞套路, 花拳秀腿
              是玩杂耍的

              原来wiki不喜欢原创, 原创不受欢迎是第一回听说.

              Heterogeneity
              我这几天在编写markdown文学编程的notepad++
              pythonscript脚本,沉浸在各种选型组合和写代码,
              不能自拔,我有四个专业要学习讨论, 一个
              业余项目, 还有工作, 我很忙, 这个论坛我是好几天
              来看一下的.

              @Cloud2016 是太云吗? 太云以前帮过我,是我尊敬的
              专业人士, 对于帮助过我的人我都记在个人项目的感谢榜上,
              不敢怠慢.

              我认为R语言向量式编程就够了,这也是数据流编程.
              统计本是以数据为中心, 用数据流处理最是合适,
              我对R语言OO派更流行不可理解, 倒是Clojure语言上数据流更流行,

              R操纵数据的库五花八门,就象玩套路一样, 不可思议, 基本上在Clojure
              上我只用核心函数中的几十个集合函数.对于数据操纵,我更倾向于
              使用核心函数千锤百炼地运用, 这对提高数据建模能力很有帮助,
              喜欢五花八门库的人,倾向让数据模型适应这些库, 然后模型是很烂的.

              比如, ggplot2很成熟,有很多扩展, 我选用它做可视化, 但它的OO式理念
              我个人不是很赞同, 我更喜欢vega-lite这种数据驱动的可视化库.

              纯函数只有输入输出, 就象是自来水管, 通道运算符就象是转接头,
              连接纯函数,这是基本式, 对于序列类型数据, 用map, reduce, apply,
              filter等高阶函数进行处理, 避免循环状态,数据,处理逻辑混杂在一起,
              即不清晰, 打断了数据流, 也难以并行处理.我的项目几万行没有任何
              显式循环代码段, 尾递归也只有一个.

                对我来说,整个R系统就是一个类似RMDB的数据分析服务器,R语言我是以clojure数据表示的DSL,当成数据来操纵组合,使用时,和clojure数据一起组合变换,只使用分析函数和可视化函数,很难看出是R语言了:-)

                lincpa 不是!我沾了太云的光了,此处真想把太云 Call 出来,你的粉丝来了!

                1. OO 这套东西确实用在复杂的系统上, R 里面一切皆对象,R 继承自 S 语言,扒扒它的历史就会知道,它几乎就是为 处理数据而生 Rick Becker 在 UseR2016 的演讲 --- forty years of S 设计 S 和 R 系统就使用了的 OO 的,只不过用户用起来不需要动不动就写类什么的,这应该归功于封装还是什么?(小白一枚,楼上各位大神赐教啊)

                2. R 操作数据的包确实有很多,从数据导入导出,数据清理,数据变形,数据建模,数据可视化,数据报告,每一环都会有很多,但是对这个环境熟悉久了就会发现,好用的就是常用的那几个, tidyverse 确有优势,但我是基础函数党,能用基础函数操作数据的就用基础函数,因为它稳定,又不需要另外装包。

                3. 看到纯函数,我还以为复分析里的,吓一跳

                  Cloud2016 我也倾向于基础函数。扩展包的函数总让我不太放心,其稳定性有时候完全取决于开发者的心情。万一遇见个任性的开发者可咋办。而且我不太理解,为啥有些功能在基础函数已经有了,而 tidyverse 却重写一遍,徒增学习成本。