【问题标题】:R function runs, executes nothing (apparently)R函数运行,什么都不执行(显然)
【发布时间】:2018-06-22 17:51:07
【问题描述】:

我正在尝试使用函数根据向量中的 12 个元素之一将单个字母代码分配给数据源变量。这是向量:

> Grps
 [1] "ST"  "RW"  "LW"  "CF"  "CM"  "CDM" "CAM" "RM"  "LM"  "CB"  "RB"  "LB" 

这是函数:$PrimPos 保存 Grps 中每一行的值之一,$PosGrp 是单个字母代码(“F”、“M”或“D”)的目标。

AsgnPos <- function(j, b, e, pos) 
       {for(q in b:e)
           {if(CompleteDataset$PrimPos[j] == Grps[q]) 
           { CompleteDataset$PosGrp[j] <- pos}
       }
}

然后我循环遍历数据源 (CompleteDataset),对函数运行三个测试以查看要分配的代码。 (我意识到一旦我受到打击,我就可以打破常规,但现在它将遍历所有三个测试)。对于函数,我通过: j...CompleteDataset 的行号// b...该类别的 Grps 的第一个位置// e...该类别的 Grps 的最后一个位置// pos...应用于$PosGrp的字母代码//

for(i in 1:17981) {
 if(CompleteDataset$PrimPos[i] == "GK") {
   CompleteDataset$PosGrp[i] <- "G"
 } else {
    AsgnPos(i,1,4, "F")
    AsgnPos(i,5,9, "M")
    AsgnPos(i,10,12, "D")
 }  

}

我预计 for 例程将执行 17,981 次,对数据源的每一行执行一次。第一部分工作正常——它将“G”应用于 $PosGrp,用于在 $PrimPos 中具有“GK”的任何行。我希望反过来,该函数将运行以检查当前行的 $PrimPos 是否与 Grps 向量的元素之一匹配。当它这样做时,它应该将字母代码分配给 $PosGrp。

代码执行时没有显式错误,但除了将“G”分配给所有匹配的行之外,它什么也不做。 (我将 $PosGrp 字段默认为“Z”,除了那些更改为“G”的字段之外,它们仍然是“Z”。)

我已经尝试过调试,但我对此很陌生,即使我将它作为断点,我似乎也无法让它逐步执行该函数,所以我看不到那里发生了什么.但是我是否遗漏了一些明显的逻辑?

【问题讨论】:

  • 您需要在您的函数中添加一个return 参数,以便它实际返回一个输出(所以我猜输出将是dplyr 包中的return(CompleteDataset)?) Second, I suggest you look at the case_when` 函数。第三,根据经验,不要在函数外部分配东西,然后在函数内部使用它们,例如,在函数中添加参数 data 并将数据集传递到那里。同样在函数内部定义 Grps
  • 为了呼应@YannisVassiliadis,您需要编写自己的函数/这是为了练习吗?您可以使用来自dplyrcase_whenif_else 和来自stringrpaste0str_c 的组合
  • 我找不到 case_when to work;无论我安装了多少次 dplyr 并加载了库,它都无法识别该命令。所以我继续前进。另外,我正在努力自学,所以即使有其他方法可以走,这种方法也应该有效。
  • 如果您提供了一个可重现的示例,将会很有帮助。尝试使用&lt;&lt;- 来分配您的功能。这让我想起了我的一个老问题:stackoverflow.com/questions/20531514/…
  • Yannis——返回参数如何工作?我不需要它来返回输出;我想为函数内的变量赋值。我不确定我是否将值返回给函数调用,它将如何分配给 var。抱歉——也不清楚你指的是在函数之外分配东西然后在内部使用它们。这不是函数参数的全部意义,将值从外部带到内部吗?

标签: r function for-loop


【解决方案1】:

这是一个范围问题。对函数之外的对象进行操作时,请尝试使用 &lt;&lt;-

AsgnPos <- function(j, b, e, pos) {
    for(q in b:e){
        if(CompleteDataset$PrimPos[j] == Grps[q]){
            CompleteDataset$PosGrp[j] <<- pos
        }
    }
}

【讨论】:

    【解决方案2】:

    OP 想要根据PrimPos 的值向CompleteDataset 添加一个新变量PosGrp。这可以通过加入 lookup 表来有效地完成。

    使用查找表连接

    首先,构建查找表。它将包括所有组,包括"GK"

    # as defined by OP
    Grps <- c("ST", "RW", "LW", "CF", "CM", "CDM", "CAM", "RM", "LM", "CB", "RB", "LB")
    
    library(data.table)
    lookup <- data.table(
      PrimPos = c("GK", Grps), 
      PosGrp = c("G", rep("F", 4L), rep("M", 5L), rep("D", 3L))
    )
    
    lookup
    
        PrimPos PosGrp
     1:      GK      G
     2:      ST      F
     3:      RW      F
     4:      LW      F
     5:      CF      F
     6:      CM      M
     7:     CDM      M
     8:     CAM      M
     9:      RM      M
    10:      LM      M
    11:      CB      D
    12:      RB      D
    13:      LB      D
    

    请注意,列名与CompleteDataset 中使用的相同。这不是必需的,但以后可以节省一些输入。

    现在,我们可以使用CompleteDataset 加入查找表。 R 中有不同的选项。名称CompleteDataset 听起来可能是一个大型数据对象。因此,我建议在加入时使用 更新,它将新列 附加在适当的位置,以避免复制整个对象。

    library(data.table)
    setDT(CompleteDataset)[lookup, on = "PrimPos", PosGrp := PosGrp]
    

    使用我的虚拟数据集(参见下面的数据部分),修改后的

    CompleteDataset
    

    包含

              rn PrimPos PosGrp
        1:     1      LW      F
        2:     2      CF      F
        3:     3     CAM      M
        4:     4      RB      D
        5:     5      RW      F
       ---                     
    17977: 17977      LW      F
    17978: 17978      RB      D
    17979: 17979      RB      D
    17980: 17980      CM      M
    17981: 17981      RW      F
    

    或者,您可以使用基础 R

    merge(CompleteDataset, lookup)
    

    dplyr

    library(dplyr)
    left_join(CompleteDataset, lookup)
    

    结果是一样的,但是会创建一个新的数据对象,其中行和列的顺序可能已经改变。

    可重现的虚拟数据集

    Grps <- c("ST", "RW", "LW", "CF", "CM", "CDM", "CAM", "RM", "LM", "CB", "RB", "LB")
    n_rows <- 17981L
    set.seed(1L)
    CompleteDataset <- data.frame(
      rn = 1:n_rows,
      PrimPos = sample(c("GK", Grps), n_rows, replace = TRUE),
      stringsAsFactors = FALSE)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-29
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多