显然我做得不对。这个方法有效,但实际上并不实用。请记住,我正在使用的示例数据运行得很快,但如果您要在400k行+的DT上尝试此操作,那么您将等待一段时间。
我最初是这样做的,这样我就可以用一个名字将日期转换为财政周(周五到周四)。我希望能够查看DT中的每个日期,测试它落入哪个范围,然后返回周名称。它就像一个魅力!但是,就像我说的那样,非常缓慢。
然后我认为这对于我可能需要做的任何逐行调整都是一种很好的技巧,但除非我能以某种方式对其进行优化,否则我可能需要重新思考...
因此,让我们使用mtcars数据集,假设我们想看看每行中的cyl是什么,然后将该数字转换为它的单词。
cyl.word <- function(c) {
r <- "Huh?"
if(c==4) {r <- "Four"}
if(c==6) {r <- "Six"}
if(c==8) {r <- "Eight"}
return(r)
}
按照您的预期工作,如果您键入cyl.word(4),则会得到“四”。大。让我们将它应用于DT ......
cars <- data.table(mtcars)
cars[, Word:=cyl.word(cars$cyl[.I]), by=cyl]
head(cars)
mpg cyl disp hp drat wt qsec vs am gear carb Word
1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Six
2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Six
3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Four
4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Six
5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Eight
6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Six
我认为减速显然是由[.I]引起的,但如果没有它,它似乎抓住整个cyl的向量并且只使用第一个用于函数,它们都返回“六”:
cars[, Word:=cyl.word(cars$cyl), by=cyl]
head(cars)
mpg cyl disp hp drat wt qsec vs am gear carb Word
1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Six
2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Six
3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Six
4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Six
5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Six
6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Six
它还给了我这个错误信息:
Warning messages:
1: In if (c == 4) { :
the condition has length > 1 and only the first element will be used
2: In if (c == 6) { :
the condition has length > 1 and only the first element will be used
3: In if (c == 8) { :
the condition has length > 1 and only the first element will be used
这就是为什么我使用.I变量来告诉函数看哪个迭代......
答案 0 :(得分:6)
使用向量化函数match()
可以大大加快计算速度:
library(data.table)
cars <- data.table(mtcars)
cyl.word <- function(x) {
c("Four", "Six", "Eight", "Huh?")[match(x, c(4,6,8), nomatch=4)]
}
cars[, Word:=cyl.word(cyl)]
head(cars)
# mpg cyl disp hp drat wt qsec vs am gear carb Word
# 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Six
# 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Six
# 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Four
# 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Six
# 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Eight
# 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Six
答案 1 :(得分:2)
您也可以加入另一个data.table
,这应该非常快。 &#34;咦&#34;将是NA
。
library(data.table)
cars <- data.table(mtcars)
cars[32]$cyl <- 10
dt2 <- data.table(cyl = c(4,6,8), word = c("Four", "Six", "Eight"))
setkey(cars, cyl)
setkey(dt2, cyl)
cars <- dt2[cars, nomatch = NA]
tail(cars)
# cyl word mpg disp hp drat wt qsec vs am gear carb
# 1: 8 Eight 15.2 304 150 3.15 3.435 17.30 0 0 3 2
# 2: 8 Eight 13.3 350 245 3.73 3.840 15.41 0 0 3 4
# 3: 8 Eight 19.2 400 175 3.08 3.845 17.05 0 0 3 2
# 4: 8 Eight 15.8 351 264 4.22 3.170 14.50 0 1 5 4
# 5: 8 Eight 15.0 301 335 3.54 3.570 14.60 0 1 5 8
# 6: 10 NA 21.4 121 109 4.11 2.780 18.60 1 1 4 2
按键加入match
和data.table
非常快。以下是更大数据集的基准。
library(microbenchmark)
N <- 50000
cars <- data.table(mtcars[rep(seq_len(nrow(mtcars)), N), ])
dim(cars)
#[1] 1600000 11
microbenchmark(
MATCH = {cyl.word <- function(x) {
c("Four", "Six", "Eight", "Huh?")[match(x, c(4,6,8), nomatch=4)]}
cars[, match_word:=cyl.word(cyl)]},
DTJOIN = {dt2 <- data.table(cyl = c(4,6,8), word = c("Four", "Six", "Eight"))
setkey(cars, cyl)
setkey(dt2, cyl)
new_cars <- dt2[cars, nomatch = NA]})
#Unit: milliseconds
# expr min lq median uq max neval
# MATCH 36.73572 41.16291 50.89132 63.22235 271.3654 100
# DTJOIN 29.56963 33.72217 39.51063 61.92716 268.3304 100