R 使用函数选择data.table行
我有一个R 使用函数选择data.table行,r,data.table,R,Data.table,我有一个数据表和一个日期列表。我希望使用一个函数来过滤和修改行,该函数检查日期是否与列表相符 # example data set.seed(1) tt <- sample( seq(as.POSIXct("2011-10-02"), as.POSIXct("2014-04-06"), by = "day"), 10) IR1 <- data.table(tstamp = sort(tt), dLoc = 1L:10L)
数据表和一个日期列表。我希望使用一个函数来过滤和修改行,该函数检查日期是否与列表相符
# example data
set.seed(1)
tt <- sample(
seq(as.POSIXct("2011-10-02"), as.POSIXct("2014-04-06"),
by = "day"), 10)
IR1 <- data.table(tstamp = sort(tt), dLoc = 1L:10L)
然而,这似乎容易出错:函数适合此任务。。。我的坏了
DLStest <- function(dd, DLSobj) {
any(sapply(DLSobj, function(X) dd %between% X))
}
但是它没有起作用:所有的行都被转换了(不仅仅是范围内的行,就像我丑陋的黑客代码中的情况一样)
是否有使用函数选择行的方法,或者有基于多个范围检查选择行的其他方法
更新(感谢发现问题的弗兰克)
您确实可以使用返回向量或布尔值的函数进行过滤。这个错误完全与我的初始函数有关
DLStest_old <- function(dd, DLSobj) {
any(sapply(DLSobj, function(X) dd %between% X))
}
解决方法是使用apply
分别测试矩阵的每一行
DLStest <- function(dd, DLSobj) {
apply(sapply(DLSobj, function(X) dd %between% X), 1, any)
}
您的数据在DLSlist中似乎没有重叠的范围,在这种情况下,应该可以使用-
library(data.table)
#creating the data
DLSlist <- data.table(read.csv(textConnection('
"2011-10-02", "2012-04-01"
"2012-10-07", "2013-04-07"
"2013-10-06", "2014-04-06"
"2014-10-05", "2015-04-05"
"2015-10-04", "2016-04-03"
"2016-10-02", "2017-04-02"'), header = FALSE))
IR1 <- data.table(
tstamp = c("2011-10-01", "2012-10-06", "2014-10-07","2016-10-03")
)
#fixing data type
IR1[,tstamp := as.Date(tstamp,"%Y-%m-%d")]
DLSlist[,V1 := as.Date(V1,"%Y-%m-%d")]
DLSlist[,V2 := as.Date(V2,"%Y-%m-%d")]
DLSlist[,tstamp := V1]
#setting a key for data.table to find the closest match
setkey(IR1,tstamp)
setkey(DLSlist,tstamp)
#roll = Inf finds the closest match for the key
IR2 <- DLSlist[IR1, roll = Inf]
#Doing the operation where condition is satisfied
IR2[tstamp > V1 & tstamp < V2 , tstamp2 := tstamp + 60*60]
库(data.table)
#创建数据
DLSlist您希望使用逻辑向量进行子集。在初始公式中,函数仅返回单个值(而不是向量),从而导致赋值影响所有行或所有行
IR <- copy(IR1)
DLStest_old <- function(dd, DLSobj) {
any(sapply(DLSobj, function(X) dd %between% X))
}
# on the whole tstamp vector at once
IR[,DLStest_old(tstamp, DLSlist)]
# TRUE
请注意,我将其放在data.table的j
位置以返回结果。通常,要通过表达式进行子集,可以将其置于i
位置(第一个逗号之前),但是“by”不适用于i
表达式,因此对于这种方法,最好保存逻辑向量,然后通过它进行子集:
# by row, for use in i
change_em <- IR[,DLStest_old(tstamp, DLSlist),by=1:nrow(IR)]$V1
IR[change_em,tstamp:=tstamp+1e15][]
您发现的另一个解决方案是使用*apply
系列中的某些内容:
DLStest_apply <- function(dd, DLSobj) {
apply(sapply(DLSobj, function(X) dd %between% X), 1, any)
}
# apply "any" on the margin of the sapply result
IR[,DLStest_apply(tstamp, DLSlist)]
# TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE
所以这应该很快。通常,sapply
可以返回不同类型的结果
另外,我认为日期很难一目了然,如果你能提前知道你不需要日期,最好不要在示例中使用日期。+1DLStest(IR1$tstamp,DLSlist)
是否给出了预期的结果?我认为它应该只给出整个tstamp向量的一个真或假值。如果您将by=1:nrow(IR1)
添加进来,它可能会工作。。。。给出适当的可重复的例子可能会得到更好更快的答案。@Frank:你是对的,它只给出了一个logi
值。不幸的是,IR1[DLStest(tstamp,DLSlist),tstamp:=tstamp+60*60,by=1:nrow(IR1)]
不起作用。@geektrader--对不起,伙计。现在修好了。@Frank,你应该回答我,这样我才能接受。您是对的,问题在于原始函数只返回一个值。当我尝试按行应用函数赋值时,它失败了--请参阅我对原始问题的评论。你能举个例子吗?@ricardo啊,你是对的,你不能把它放在i槽里。我已经编辑了答案。我认为,你的解决方案和apply是更好的选择。
> (IR1[DLStest(tstamp, DLSlist), dLoc := dLoc + 1000L])
tstamp dLoc
1: 2011-11-27 01:00:00 1001
2: 2012-04-03 00:00:00 2
3: 2012-06-01 00:00:00 3
4: 2012-09-06 00:00:00 4
5: 2013-03-09 01:00:00 1005
6: 2013-04-25 00:00:00 6
7: 2013-05-25 00:00:00 7
8: 2013-12-29 01:00:00 1008
9: 2014-01-09 01:00:00 1009
10: 2014-02-08 01:00:00 1010
library(data.table)
#creating the data
DLSlist <- data.table(read.csv(textConnection('
"2011-10-02", "2012-04-01"
"2012-10-07", "2013-04-07"
"2013-10-06", "2014-04-06"
"2014-10-05", "2015-04-05"
"2015-10-04", "2016-04-03"
"2016-10-02", "2017-04-02"'), header = FALSE))
IR1 <- data.table(
tstamp = c("2011-10-01", "2012-10-06", "2014-10-07","2016-10-03")
)
#fixing data type
IR1[,tstamp := as.Date(tstamp,"%Y-%m-%d")]
DLSlist[,V1 := as.Date(V1,"%Y-%m-%d")]
DLSlist[,V2 := as.Date(V2,"%Y-%m-%d")]
DLSlist[,tstamp := V1]
#setting a key for data.table to find the closest match
setkey(IR1,tstamp)
setkey(DLSlist,tstamp)
#roll = Inf finds the closest match for the key
IR2 <- DLSlist[IR1, roll = Inf]
#Doing the operation where condition is satisfied
IR2[tstamp > V1 & tstamp < V2 , tstamp2 := tstamp + 60*60]
> IR2
tstamp V1 V2 tstamp2
1: 2011-10-01 <NA> <NA> <NA>
2: 2012-10-06 2011-10-02 2012-04-01 <NA>
3: 2014-10-07 2014-10-05 2015-04-05 2024-08-15
4: 2016-10-03 2016-10-02 2017-04-02 2026-08-12
IR <- copy(IR1)
DLStest_old <- function(dd, DLSobj) {
any(sapply(DLSobj, function(X) dd %between% X))
}
# on the whole tstamp vector at once
IR[,DLStest_old(tstamp, DLSlist)]
# TRUE
# by row
IR[,DLStest_old(tstamp, DLSlist),by=1:nrow(IR)]$V1
# TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE
# by row, for use in i
change_em <- IR[,DLStest_old(tstamp, DLSlist),by=1:nrow(IR)]$V1
IR[change_em,tstamp:=tstamp+1e15][]
tstamp dLoc
1: ))0'-06-03 15:45:52 1
2: 2012-04-03 00:00:00 2
3: 2012-06-01 00:00:00 3
4: 2012-09-07 00:00:00 4
5: ))0'-06-03 15:45:52 5
6: 2013-04-26 00:00:00 6
7: 2013-05-25 00:00:00 7
8: ))0'-06-03 15:45:52 8
9: ))0'-06-03 15:45:52 9
10: ))0'-06-03 15:45:52 10
DLStest_apply <- function(dd, DLSobj) {
apply(sapply(DLSobj, function(X) dd %between% X), 1, any)
}
# apply "any" on the margin of the sapply result
IR[,DLStest_apply(tstamp, DLSlist)]
# TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE
class(sapply(DLSlist, function(X) IR$tstamp %between% X))
# "matrix"