如何在R中查找值

4

有人能帮忙吗?我有一个数据框(set_rise),每行包含当天日落时间和第二天日出时间。我有第二个数据框(data),其中有一个日期/时间列。我想在data中创建第二列,该列包含与白天或黑夜对应的字母,方法是获取data中的日期/时间,并检查它是否介于set_rise中的任何时间之间。

#df1- sunset, sunrise times
set_rise
                  set                rise 
1 2013-03-01 18:28:00 2013-03-02 08:27:00   
2 2013-03-02 18:31:00 2013-03-03 08:23:00    
3 2013-03-03 18:35:00 2013-03-04 08:19:00  
4 2013-03-04 18:38:00 2013-03-05 08:15:00   
5 2013-03-05 18:42:00 2013-03-06 08:12:00  
6 2013-03-06 18:45:00 2013-03-07 08:08:00   

#df2 my data    
  timedate
1 2013-03-01 19:00:00
2 2013-03-03 10:00:00
3 2013-03-06 00:01:00

我希望得到这样的输出
data
timedate night_day
2013-03-01 19:00:00  N
2013-03-03 10:00:00  D
2013-03-06 00:01:00  N

Output dput(set_rise)

dput(set_rise)
structure(list(set = structure(list(sec = 0, min = 28L, hour = 18L, 
mday = 1L, mon = 2L, year = 113L, wday = 5L, yday = 59L, 
isdst = 0L, zone = "WET", gmtoff = NA_integer_), .Names = c("sec", 
"min", "hour", "mday", "mon", "year", "wday", "yday", "isdst", 
 "zone", "gmtoff"), class = c("POSIXlt", "POSIXt")), rise = structure(list(
sec = 0, min = 27L, hour = 8L, mday = 2L, mon = 2L, year = 113L, 
wday = 6L, yday = 60L, isdst = 0L, zone = "WET", gmtoff = NA_integer_), .Names = c("sec", 
"min", "hour", "mday", "mon", "year", "wday", "yday", "isdst", 
"zone", "gmtoff"), class = c("POSIXlt", "POSIXt")), night = "N"), .Names = c("set", 
"rise", "night"), row.names = 1L, class = "data.frame")

dput(data)的输出结果

dput(data)
structure(list(timedate = structure(c(1362873600, 1362960000, 
1364342400), class = c("POSIXct", "POSIXt"))), .Names = "timedate",     row.names = c(NA, 
-3L), class = "data.frame")

1
如果您提供一个输出示例,这将有所帮助。 - felixmc
看起来你在搞乱日期转换。对于 set_rise,我得到了 13-03-01 的日期(它是 13 年而不是 2013 年)!只需提供 set_risedata,跳过如何构建它们的步骤。完成后,请发布 dput(set_rise)dput(data) 的输出。但在此之前,请检查日期是否符合您的意图。 - nicola
感谢回复,我已经解决了日期问题,并优化了发布的数据并发布了首选输出。 - jimken
谢谢,解决方案完美运行。 - jimken
感谢所有抽出时间帮助我的人,非常感激。由于速度较快,我已经接受了nicola的答案,因为我有许多大型数据集(每个约20,000个)。 - jimken
3个回答

1
我不确定我是否理解正确,但是这是一个开始: check_night() 检查每个 data$timedate 的值是否位于 set_rise 中的一个日出/日落时间内。
timedate <- c('2013-03-10 19:00:00', '2013-03-11 10:00:00', '2013-03-27 00:01:00')
data <- data.frame(timedate)
data$timedate <- as.POSIXct(data$timedate)

check_night <- function (t) {
  night <- "D"
  for (i in 1:length(rownames(set_rise))) {
    if ((t > set_rise[i,"set"]) && (t < set_rise[i,"rise"]))
      night <- "N"
  }
  return(night)
}

dplyr::mutate(.data = data, night=sapply(data$timedate, FUN = check_night))

# Output
             timedate night
1 0013-03-10 19:00:00     D
2 0013-03-11 10:00:00     N
3 0013-03-27 00:01:00     D

注意:可能存在不需要for循环的解决方案。

1
这需要一些准备,但非常快速。首先,将您的set_rise转换为POSIXct(而不是POSIXlt)。接下来,将日期转换为numeric并组合所有值,使它们形成交替的白天和黑夜值。然后,调用findInterval告诉您每个data日期所在的区间:如果区间是奇数,则是晚上,否则是白天。因此:
#convert to POSIXct
set_rise[]<-lapply(set_rise,as.POSIXct)
#combine all the numeric values together
intervals<-c(t(matrix(c(as.numeric(set_rise$set),as.numeric(set_rise$rise)),ncol=2)))
#call findInterval and set the values, checking the parity
c("D","N")[1+(findInterval(as.numeric(data$timedate),intervals) %% 2)]
#[1] "N" "D" "N"

0
我有一个与maj类似的解决方案,只是使用了嵌套的for循环而不是创建函数和sapply。我还使用strptime而不是as.POSIXct,因为后者会给我返回NA。如果您有一个大型数据集,请使用创建函数并使用sapply或lapply,这样更容易阅读,也更快速。我发布这篇文章是为了给您提供一些选择,maj的可能比我的更快且更优雅一些。
df1<-read.csv("~/mysrc/data/sunsethelp.csv", header=T, stringsAsFactors=F)
df1$set<-strptime(df1$set, "%m/%d/%Y %H:%M")
df1$rise<-strptime(df1$rise, "%m/%d/%Y %H:%M")

timedate<-c('2013-03-01 19:00:00', '2013-03-03 10:00:00', '2013-03-06     00:01:00')
df2 <- data.frame(timedate)
df2$timedate <- strptime(timedate, "%Y-%m-%d %H:%M")

for(i in seq(nrow(df2))){
  for(j in seq(nrow(df1))){
    df2$night_day[i]<-ifelse(df2$timedate[i]>df1$set[j] && df2$timedate[i]    <df1$rise[j], "N", "D")
    if(df2$night_day[i]=="N")
      break
  }
}

#Output
             timedate night_day
1 2013-03-01 19:00:00         N
2 2013-03-03 10:00:00         D
3 2013-03-06 00:01:00         N

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接