OP 有 asked for an explanation 为什么他的两种方法“不起作用”以及为什么第三种方法会发出警告。
令我惊讶的是,答案比我预期的更难找到,而调查给了我一些新的见解。
需要调查的问题
更准确地说,所有三种方法都会产生相同的警告消息:
在 unclass(e1) + unclass(e2) 中:
较长的对象长度不是较短对象长度的倍数
此外,前两种方法不会遇到错误情况,而只返回一个
2 列的空 data.table(0 行):日期、年份
警告信息说明
在所有三种方法中,OP 通过将长度为 1000 的向量(例如 as.Date(paste(year,"-06-04",sep="")))与长度为 7 的向量 (-3:3) 组合来创建 %in% 运算符的 RHS。在 R 中,较短的向量会在必要时被回收(当它们仅部分地回收时会发出警告),请参阅help("Arithmetic")。
这可以用一个简单的例子来证明
1:10 + (-3:3)
[1] -2 0 2 4 6 8 10 5 7 9
Warning message:
In 1:10 + (-3:3) :
longer object length is not a multiple of shorter object length
上述结果很可能不是 OP 所想的。我想他想将第一个向量的每个元素与第二个向量的每个元素结合起来。这可以通过outer()函数或使用expand.grid()或data.table的交叉连接CJ()来实现:
outer(1:10, -3:3, "+")
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] -2 -1 0 1 2 3 4
[2,] -1 0 1 2 3 4 5
[3,] 0 1 2 3 4 5 6
[4,] 1 2 3 4 5 6 7
[5,] 2 3 4 5 6 7 8
[6,] 3 4 5 6 7 8 9
[7,] 4 5 6 7 8 9 10
[8,] 5 6 7 8 9 10 11
[9,] 6 7 8 9 10 11 12
[10,] 7 8 9 10 11 12 13
CJ(1:10, -3:3)[, V3 := V1 + V2][]
V1 V2 V3
1: 1 -3 -2
2: 1 -2 -1
3: 1 -1 0
4: 1 0 1
5: 1 1 2
---
66: 10 -1 9
67: 10 0 10
68: 10 1 11
69: 10 2 12
70: 10 3 13
V1 V2 V3
小数Date
第二个问题更难追踪。这是由 OP 创建示例数据的方式引起的:
test <- data.table(date=as.Date(Sys.time())+runif(1000,1,365))
runif(1000,1,365) 创建一个由double 组成的向量,非整数值:
set.seed(3); head(runif(1000,1,365))
[1] 62.16712 294.93597 141.11902 120.29529 220.16465 220.99944
这些被添加到创建小数日期的Date 值。打印时小数部分不可见:
as.Date("2018-01-01") + c(0, 0.1)
[1] "2018-01-01" "2018-01-01"
只有将日期转换为numeric 或POSIXct 时才会变得明显:
as.POSIXct(as.Date("2018-01-01") + c(0, 0.1))
[1] "2018-01-01 01:00:00 CET" "2018-01-01 03:23:59 CET"
现在,很明显为什么
test[date %in% (as.Date(paste(year,"-06-04",sep="")) + (-3:3)),]
从未找到匹配项。 LHS date 始终具有小数部分,而 RHS 具有 integerish 值而没有小数部分。根本原因是Date是使用double构造的。请注意,data.table 包引入了基于整数的日期类 IDate。
对用于创建示例数据的 OP 代码有一个简单的修复:
set.seed(3)
test <- data.table(date = as.Date(Sys.time()) + as.integer(runif(1000,1,365)))
也可以使用Sys.Date() 和sample.int():
set.seed(3)
test1 <- data.table(date = Sys.Date() + sample.int(365, 1000, TRUE))