【问题标题】:R loop unable to recognize an object I already created within the very same loopR循环无法识别我已经在同一个循环中创建的对象
【发布时间】:2011-07-20 09:32:52
【问题描述】:

如果你有时间,我想再问你一个问题。

我向您展示我之前在之前的问题中已经使用过的常用 df 数据框,作为我的真实 df 数据框的转换简化版本,在这里很难展示。但是主要特征还是一样的。

id <-c(1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3)
a <-c(3,1,3,3,1,3,3,3,3,1,3,2,1,2,1,3,3,2,1,1,1,3,1,3,3,3,2,1,1,3)
b <-c(3,2,1,1,1,1,1,1,1,1,1,2,1,3,2,1,1,1,2,1,3,1,2,2,1,3,3,2,3,2)
c <-c(1,3,2,3,2,1,2,3,3,2,2,3,1,2,3,3,3,1,1,2,3,3,1,2,2,3,2,2,3,2)
d <-c(3,3,3,1,3,2,2,1,2,3,2,2,2,1,3,1,2,2,3,2,3,2,3,2,1,1,1,1,1,2)
e <-c(2,3,1,2,1,2,3,3,1,1,2,1,1,3,3,2,1,1,3,3,2,2,3,3,3,2,3,2,1,4)
df <-data.frame(id,a,b,c,d,e)
df
df.list <- lapply(df[,2:6],function(x, id){ t(table(x, id, useNA = "ifany")) }, df$id)
df.list

你看,基本上我在这里创建的是出现在“a”到“e”列中的每个不同数字的出现总和的集合,并同时按列 id 中的 id 分组。

在下一步中,我创建了一个如下所示的循环:

for (i in names(df.list))
{
  df.list[i]
  assign( paste("var",i,sep=""),
          (matrix(matrix(unlist(df.list[i])),ncol=nlevels(factor(df[,i])),nrow=3))/10
        )
}

它将之前创建的列表中的每个元素除以 10。但是,这只是我想要实现的整个循环的前半部分,但至少它仍然可以正常工作,我对此没有任何问题,只需在此处将这些代码发送到 R ->

vara
varb
varc
vard
vare

当我尝试执行“for (k in 1:3)”部分时,现在更困难的部分来了。所以,让我们尝试再次发送这些行(当然还有整个循环的前半部分)。

for (i in names(df.list))
{
  df.list[i]
  assign( paste("var",i,sep=""),
          (matrix(matrix(unlist(df.list[i])),ncol=nlevels(factor(df[,i])),nrow=3))/10
        )

  for (k in 1:3)
    assign( paste("var",i,k,sep="."),
            vari[k,]*5 
          )
}

我的问题出在vari[k,]*5 行。 (实际上,此时我应该整理出矩阵乘法。)代码无法识别 vari 但是我之前已经定义了i。而且我不打算使用varavarbvarc...等,因为我需要将其自动化。原因:我将不得不定期刷新我的真实 df 数据框,因此变量的数量可能会随着时间而变化(我不一定只有从 ae 的变量,而是从 a 到 @ 987654333@或ay

所以我收到以下错误消息:

Error in assign(paste("var", i, k, sep = "."), vari[k, ] * 5): object 'vari' not found

我在这里错过了什么/做错了什么?我只想引用另一个我已经在同一个循环中创建但仍然无法识别的对象。这里有合适的解决方案吗?

非常感谢

【问题讨论】:

    标签: r loops for-loop


    【解决方案1】:

    我认为你可以替换

    vari[k,]*5 
    

    get( paste( "var", i, sep="" ) )*5 
    

    您真的需要以这种方式创建变量吗?如果您的数据集变得更大,我担心命名空间会失控。最好只创建一个列表对象,或者使用new.env 定义您自己的环境并在此环境中设置变量而不是全局变量?

    【讨论】:

    • 谢谢蒂姆!你是对的,我也有点害怕命名空间的大小失控但还没有找到更好的解决方案。所以我试试这个“new.env”,事实上听起来很棒。然而,这是一个我还不太了解的领域......直到我更深入地挖掘“new.env”的深度,你的建议“get”也将是完美的,所以谢谢。
    • 别担心! :) 是的,您可以使用new.env 创建一个环境对象,然后将其作为envir= 参数传递给assigngetls 等...玩得开心!
    • 只使用一个列表。无需乱搞环境。
    【解决方案2】:

    vari 确实无法识别,因为您保存了 vara、varb、varc、vard ......但不是 vari。名字中的 i 在这里没有改成数字!

    您想要达到的目标,可以通过以下方式轻松完成:

    lapply(df.list,function(i) i/10*5)
    

    我认为这只是一个示例,您的实际代码更复杂。但是,只需使用 lapply 并记住表格是矩阵。所有那些 unlist/matrix 的东西都是完全没有必要的。

    > is.matrix(df.list[[1]])
    [1] TRUE
    

    如果你真的,真的想删除表格属性,并且你想给出指定的名称,那么你的代码可以简化为:

    VarList <- sapply(names(df.list),function(i){
      out <- df.list[[i]]/10*5
    
      out <- matrix(out,ncol(out)) # in case you want to drop all table attributes
    
      colnames(out) <- paste(
                         paste("var",i,sep=""),
                         1:ncol(out),
                         sep=".")
      out
    },USE.NAMES=TRUE,simplify=FALSE)
    

    它为您提供了一个矩阵列表,其中变量名称是根据需要形成的。这也允许你做类似的事情

    > VarList[["d"]][,1:2]
         vard.1 vard.2
    [1,]    1.0    1.5
    [2,]    1.0    3.0
    [3,]    2.5    1.5
    

    这实质上允许您选择数字上的变量作为索引,并仅通过初始变量的名称选择矩阵。坚持下去,分配给全球环境并信任名称是非常危险的。

    【讨论】:

      【解决方案3】:

      @hadley 我同意。从我所见,矢量化循环几乎总是正确的答案。

      @lazlo 看看这些例子:Vectorizing a loopCoding the R-ight way - avoiding the for loop

      【讨论】:

      • 谢谢 Rob/Hadley,我去看看!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 2019-07-31
      • 2014-12-10
      相关资源
      最近更新 更多