【问题标题】:Problems with looping through data.table in R. Condition to compare does not change在 R 中循环遍历 data.table 的问题。比较条件没有改变
【发布时间】:2020-10-15 21:20:20
【问题描述】:

我在数据表中创建分类变量时遇到问题。我的目标是将 RA 变量分解为不同的组,高组、中组和低组。第一步是使用 quantile 函数基于 RA 创建不同的级别。这不是问题:

base.dat <- read.csv("file:///C:/Users/Owner/Documents/baseball csv.csv", header=TRUE)
base.dat.70 <- base.dat[base.dat$yearID>=1970, ]
base.dat.70.reduce <- base.dat.70[ , c(1, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 27)]
table <- data.table(base.dat.70.reduce)

table[ ,med.RA:=median(RA), by=yearID]
table[ ,RA.low:=quantile(RA, .33), by=yearID]
table[,RA.high:=quantile(RA, .67), by=yearID]

以上代码正确创建了RA.low和RA.high变量,不同年份的变量不同。

问题在于下一个代码块。我想将每一行与其 RA.low 和 RA.high 进行比较,以将其置于低、中或高组中。不同年份的情况会有所不同。代码如下:


 table[ , RA.level:= { if (RA <RA.low) "Low RA"
  else if (RA <RA.high) "Medium RA"
  else "High RA"}, by=RA] 

kable(head(table))
kable(tail(table))

我收到一堆警告,'In if (RA 1 并且只使用第一个元素'

我以前得到过这些,对于数据帧使用 for 循环,我已经能够处理它们。但是这个输出并不完全有效。前五行没问题。这些都是正确的。如果 RA 在 RA.low 和 RA.high 之间,它应该是 Medium RA。如果它低于 RA.low,它应该是低的,如果它高于 RA.high,它应该是高的。这些似乎都是正确的。它们都是同一年的,所以 RA.low 和 RA.high 都是一样的。

问题在于打印出表格的最后六行。

在第一行,776 的 RA 被归类为高,而它应该是中等。在第三行中,704 的 RA 被归类为高,而它应该是低的。在第六行,672 的 RA 被归类为中等,而应该是低的。

我认为评估只针对 RA.low 和 RA.high 的初始值进行,即 1970 年的值。但在那种情况下,第六行应该仍然很低,因为 RA.low 是 677 1970 年,第三排也是中等,不高。

对于这个问题,我深表歉意,我相信修复很容易。我只是不太清楚到底发生了什么。

提前致谢。

【问题讨论】:

标签: r data.table


【解决方案1】:

我将演示 fcase 和嵌套的 fifelse(如果您使用的是 1.13.0 之前的版本)。

MT <- as.data.table(mtcars)

MT[, c("lo", "med", "hi") :=
       .(quantile(disp, 0.33), median(disp), quantile(disp, 0.67)), by = .(cyl)]
MT
#      mpg cyl  disp  hp drat    wt  qsec vs am gear carb     lo   med      hi
#  1: 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 160.00 167.6 168.748
#  2: 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 160.00 167.6 168.748
#  3: 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1  83.83 108.0 120.240
#  4: 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 160.00 167.6 168.748
#  5: 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 308.06 350.5 360.000
# ---                                                                         
# 28: 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2  83.83 108.0 120.240
# 29: 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4 308.06 350.5 360.000
# 30: 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6 160.00 167.6 168.748
# 31: 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8 308.06 350.5 360.000
# 32: 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2  83.83 108.0 120.240

MT[, intrvl1 := fcase(
  disp < lo, "low",
  data.table::between(disp, lo, hi), "med",
  disp > hi, "high") ]

MT[, intrvl2 :=
       fifelse(disp < lo, "low",
               fifelse(disp > hi, "high", "med")) ]

MT
#      mpg cyl  disp  hp drat    wt  qsec vs am gear carb     lo   med      hi intrvl1 intrvl2
#  1: 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 160.00 167.6 168.748     med     med
#  2: 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 160.00 167.6 168.748     med     med
#  3: 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1  83.83 108.0 120.240     med     med
#  4: 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 160.00 167.6 168.748    high    high
#  5: 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 308.06 350.5 360.000     med     med
# ---                                                                                         
# 28: 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2  83.83 108.0 120.240     med     med
# 29: 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4 308.06 350.5 360.000     med     med
# 30: 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6 160.00 167.6 168.748     low     low
# 31: 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8 308.06 350.5 360.000     low     low
# 32: 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2  83.83 108.0 120.240    high    high

一些注意事项:

  • 我使用data.table::between(完全限定)是因为我也经常加载dplyr,它的between 版本要求第二个和第三个参数的长度为1,从而破坏了任何向量化操作; data.table::between 接受长度相同(或 1)的所有三个参数。

  • fcase 代码中,我演示了我们不需要 between 的条件,因为我们可以测试lohi,其他一切都在它们之间。

  • 如果您有 1.13.0 或更高版本,我强烈建议 fcase 超过嵌套的 fifelse;虽然性能可能会更好(我没有测试过),但我认为fcase 的可读性(以及因此的可维护性)要好得多。嵌套的fifelse 很容易忽略缩进并忘记你在“ifs”中的位置。

  • 虽然您最初尝试按行执行此操作(使用 by=RA),但通常最好在 R 中以向量形式执行操作。不过,在您的尝试中,您按 numeric 分组,这应该通常是唯一的,但肯定有模棱两可的余地。如果你必须看到一个按行的解决方案,那么最好使用by=seq_len(nrow(DT))

    MT[, intrvl3 := c("low", "med", "high")[findInterval(disp, c(-Inf, lo, hi, Inf))],
       by = seq_len(nrow(MT))]
    MT
    #      mpg cyl  disp  hp drat    wt  qsec vs am gear carb     lo   med      hi intrvl1 intrvl2 intrvl3
    #  1: 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 160.00 167.6 168.748     med     med     med
    #  2: 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 160.00 167.6 168.748     med     med     med
    #  3: 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1  83.83 108.0 120.240     med     med     med
    #  4: 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 160.00 167.6 168.748    high    high    high
    #  5: 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 308.06 350.5 360.000     med     med    high
    # ---                                                                                                 
    # 28: 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2  83.83 108.0 120.240     med     med     med
    # 29: 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4 308.06 350.5 360.000     med     med     med
    # 30: 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6 160.00 167.6 168.748     low     low     low
    # 31: 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8 308.06 350.5 360.000     low     low     low
    # 32: 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2  83.83 108.0 120.240    high    high    high
    

    如你所见,这是一个右闭现象。

【讨论】:

  • 非常感谢您的帮助!我对数据表很陌生,所以这对我有很大帮助。
  • 如果这回答了您的问题,请accept it。谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多