【问题标题】:In R, how to replace values in multiple columns with a vector of values equal to the same width?在R中,如何用等于相同宽度的值向量替换多列中的值?
【发布时间】:2013-09-29 23:36:01
【问题描述】:

我正在尝试用长度为 2 的向量替换 2 列中每一行的值。它更容易向您展示。

首先是一些数据。

set.seed(1234) 
x<-data.frame(x=sample(c(0:3), 10, replace=T))
x$ab<-0 #column that will be replaced
x$cd<-0 #column that will be replaced

数据如下:

   x ab cd
1  0  0  0
2  2  0  0
3  2  0  0
4  2  0  0
5  3  0  0
6  2  0  0
7  0  0  0
8  0  0  0
9  2  0  0
10 2  0  0

每次 x=2 或 x=3,我想 ab=0 和 cd=1。

我的尝试是这样的:

x[with(x, which(x==2|x==3)), c(2:3)] <- c(0,1)

没有达到预期的结果:

   x ab cd
1  0  0  0
2  2  0  1
3  2  1  0
4  2  0  1
5  3  1  0
6  2  0  1
7  0  0  0
8  0  0  0
9  2  1  0
10 2  0  1

你能帮帮我吗?

【问题讨论】:

  • ab已经是0,所以只需要改cd
  • +1 是一个可重现的例子。

标签: r vector replace dataframe multiple-columns


【解决方案1】:

它不能按您想要的那样工作的原因是因为 R 以列优先布局存储矩阵和数组。当您将较短的数组分配给较长的数组时,R 会循环遍历较短的数组。例如,如果您有

x<-rep(0,20)
x[1:10]<-c(2,3)

然后你会得到

 [1] 2 3 2 3 2 3 2 3 2 3 0 0 0 0 0 0 0 0 0 0

在您的情况下发生的情况是 x 等于 2 或 3 的子数组正在通过循环遍历向量 c(0,1) 逐列填充。我不知道有什么简单的方法可以改变这种行为。

这里最简单的做法可能就是一次填写一列。或者,您可以这样做:

indices<-with(x, which(x==2|x==3))
x[indices,c(2,3)]<-rep(c(0,1),each=length(indices))

【讨论】:

    【解决方案2】:

    另一种选择:使用 data.table,这是一个单行:

    require(data.table)
    DT <- data.table(x)
    DT[x%in%2:3,`:=`(ab=0,cd=1)]
    

    原答案:您可以传递行列对矩阵:

    ijs <- expand.grid(with(x, which(x==2|x==3)),c(2:3))
    ijs <- ijs[order(ijs$Var1),]
    
    x[as.matrix(ijs)] <- c(0,1)
    

    产生

       x ab cd
    1  0  0  0
    2  2  0  1
    3  2  0  1
    4  2  0  1
    5  3  0  1
    6  2  0  1
    7  0  0  0
    8  0  0  0
    9  2  0  1
    10 2  0  1
    

    我的原始答案在我的计算机上有效,但不是评论者的。

    【讨论】:

    • 您的 data.table 示例运行良好,但是当我运行您的第一个答案时出现错误:Error in [&lt;-.data.frame(*tmp*, as.matrix(ijs), value = c(0, 1)) : only logical matrix subscripts are allowed in replacement
    • 嗯,这很奇怪。也许我们正在使用不同版本的 R?我看到你在谷歌上到处报告的错误,但不是最近......我的?Extract.data.frame 也只提到使用逻辑矩阵。
    • 我在使用 R 版本 2.15.3 时遇到错误,但在 3.0.0 版本中它可以工作,但不知道为什么..
    • 我认为邓肯·默多克可能在这两者之间进行了更改:r.789695.n4.nabble.com/…
    【解决方案3】:

    为多列和多值泛化:

    mycol<-as.list(names(x)[-1])
    myvalue<-as.list(c(0,1))
    kk<-Map(function(y,z) list(x[x[,1] %in% c(2,3),y]<-z,x),mycol, myvalue)
    myresult<-data.frame(kk[[2]][[2]])
    
    
    x ab cd
    1  1  0  0
    2  1  0  0
    3  0  0  0
    4  0  0  0
    5  0  0  0
    6  3  0  1
    7  2  0  1
    8  3  0  1
    9  3  0  1
    10 0  0  0
    

    【讨论】:

      【解决方案4】:

      你可以使用ifelse:

      > set.seed(1234) 
      > dat<-data.frame(x=sample(c(0:3), 10, replace=T))
      > dat$ab <- 0 
      > dat$cd <- ifelse(dat$x==2 | dat$x==3, 1, 0)
      
         x ab cd
      1  0  0  0
      2  2  0  1
      3  2  0  1
      4  2  0  1
      5  3  0  1
      6  2  0  1
      7  0  0  0
      8  0  0  0
      9  2  0  1
      10 2  0  1
      

      【讨论】:

        【解决方案5】:

        那又怎样?

         x[x$x%in%c(2,3),c(2,3)]=matrix(rep(c(0,1),sum(x$x%in%c(2,3))),ncol=2,byrow=TRUE)
        

        【讨论】:

        • 哦!刚看到这和mrips的第二个建议很相似。
        【解决方案6】:
        x$ab[x$x==2 | x$x==3] <- 0
        x$cd[x$x==2 | x$x==3] <- 1
        

        编辑

        这是一种适用于大量列的通用方法。您只需为每列创建一个替换值向量即可。

        set.seed(1234) 
        y<-data.frame(x=sample(c(0:3), 10, replace=T))
        y$ab<-4 #column that will be replaced
        y$cd<-2 #column that will be replaced
        y$ef<-0 #column that will be replaced
        y
        
        #   x ab cd ef
        #1  0  4  2  0
        #2  2  4  2  0
        #3  2  4  2  0
        #4  2  4  2  0
        #5  3  4  2  0
        #6  2  4  2  0
        #7  0  4  2  0
        #8  0  4  2  0
        #9  2  4  2  0
        #10 2  4  2  0
        
        replacement.values <- c(10,20,30)
        
        y2 <- y
        y2[,2:ncol(y)] <- sapply(2:ncol(y), function(j) { 
                            apply(y, 1, function(i) {
                              ifelse((i[1] %in% c(2,3)), replacement.values[j-1], i[j])
                            })
                          })
        y2
        
        #   x ab cd ef
        #1  0  4  2  0
        #2  2 10 20 30
        #3  2 10 20 30
        #4  2 10 20 30
        #5  3 10 20 30
        #6  2 10 20 30
        #7  0  4  2  0
        #8  0  4  2  0
        #9  2 10 20 30
        #10 2 10 20 30
        

        【讨论】:

        • 虽然这个例子只有两列,但我用我的实际数据替换了更多。
        • 我不确定你的意思,但你可以用同样的方式替换第三列:x$ef[x$x==2 | x$x==3] &lt;- 2
        • @jnam27 我添加了一种通用方法,可以处理许多列。
        猜你喜欢
        • 2016-06-10
        • 2012-11-10
        • 1970-01-01
        • 2019-05-07
        • 2021-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-31
        相关资源
        最近更新 更多