我有以下数据表,其列数为 "字符 "类。
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
任何帮助将是非常感激的!
我们可以在 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
在上位机的代码中,它是在做一次 if/else
不是矢量化的,OP通过循环'V1'来弥补,而'y'仍然是整列的,在 sapply
而这将导致'V1'的每个元素都得到4个值。 相反,它可以是 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
随着 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