【问题标题】:R: Where is the mistake: if statement over multiple columnsR:错误在哪里:if 语句覆盖多列
【发布时间】:2020-05-12 18:40:38
【问题描述】:

我有以下数据表,列“字符”类

dt <- data.table(V1 = c("0", "1", "1/2", "4"), V2 = c("1/2", "3/4", "", ""))

我希望仅在第二列和第一列自然数中包含所有分数。我想出了以下解决方案:

if(str_detect(new$V1, "/")){
  new$V2 <- new$V1
  new$V1 <- 0
}

并且还尝试将其嵌入到函数中并以sapply 结束。

FractionExtraction <- function(x, y) {
  if(str_detect(x, "/")){
  y <- x 
  } else {y <- y}
  y
}

dt$V2  <- sapply(dt$V1, FractionExtraction, dt$V2)

我也尝试在 if 语句中使用 %in%,或者将“

Warning message:
In if (str_detect(new$V1, "/")) { :
  the condition has length > 1 and only the first element will be used

理想情况下,输出应如下所示:

> dt
   V1  V2
1:  0 1/2
2:  1 3/4
3:  0 1/2
4:  4    

任何帮助将不胜感激!

【问题讨论】:

  • 您认为在 data.table 上使用 dplyr 是否有问题?我选择了另一个,只是因为我发现语义更直接。例如,我不太理解 := 符号……让我说另一个对我来说更容易
  • 我知道了,但我认为当您的数据构造是 data.table 并且效率更高时,您需要一个 data.table 解决方案
  • 你说使用更少的内存?很高兴知道,谢谢!

标签: r if-statement sapply


【解决方案1】:

我们可以在i 中指定条件,然后将'V2' 和'V1' 列的值分配(:=)给'V1' 和0

library(data.table)
library(stringr)
dt[str_detect(V1, "/"), c('V2', 'V1') := .(V1, 0)]
dt
#   V1  V2
#1:  0 1/2
#2:  1 3/4
#3:  0 1/2
#4:  4    

在 OP 中。代码,它正在执行 if/else 未矢量化,并且 OP 通过循环“V1”进行修正,而“y”仍然是 sapply 中的整个列,这导致在每个元素中获得 4 个值'V1'。取而代之的是Map,但是代码也需要一些改动


基准测试

dt1 <- dt[rep(seq_len(.N), 1e7)]
system.time(dt1 %>%  mutate(V2 = ifelse(str_detect(V1, "/"), V1, V2),
          V1 = ifelse(str_detect(V1, "/"), 0, V1)))
#   user  system elapsed 
# 30.485   2.966  33.506 
system.time(dt1[str_detect(V1, "/"), c('V2', 'V1') := .(V1, 0)])
#   user  system elapsed 
#  5.143   0.689   5.811 

【讨论】:

    【解决方案2】:

    与dplyr:

    dt %>% 
      mutate(V2 = ifelse(str_detect(V1, "/"), V1, V2),
             V1 = ifelse(str_detect(V1, "/"), 0, V1))
    
      V1  V2
    1  0 1/2
    2  1 3/4
    3  0 1/2
    4  4    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多