Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 使用函数选择data.table行_R_Data.table - Fatal编程技术网

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
可以返回不同类型的结果



另外,我认为日期很难一目了然,如果你能提前知道你不需要日期,最好不要在示例中使用日期。

+1
DLStest(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"