根据 R 中另一个数据框中的比较值更改一个数据框中的值

Alter values in one data frame based on comparison values in another in R

我正在尝试将 POSIXct 列中的 date/times 减去一小时,该列早于或等于该特定 ID 的不同比较数据框中规定的时间。

例如:

#create sample data
Time<-as.POSIXct(c("2015-10-02 08:00:00","2015-11-02 11:00:00","2015-10-11 10:00:00","2015-11-11 09:00:00","2015-10-24 08:00:00","2015-10-27 08:00:00"), format = "%Y-%m-%d %H:%M:%S")
ID<-c(01,01,02,02,03,03)
data<-data.frame(Time,ID)

产生这个:

                 Time ID
1 2015-10-02 08:00:00  1
2 2015-11-02 11:00:00  1
3 2015-10-11 10:00:00  2
4 2015-11-11 09:00:00  2
5 2015-10-24 08:00:00  3
6 2015-10-27 08:00:00  3

然后我有另一个数据框,其中包含每个 ID 的关键日期和时间以供比较。数据中的时间应该与 ComparisonData 中的 Comparison 进行比较,以获取与之关联的特定 ID。如果数据中的时间值早于或等于比较值,则应从数据中的值中减去一小时:

#create sample comparison data
Comparison<-as.POSIXct(c("2015-10-29 08:00:00","2015-11-02 08:00:00","2015-10-26 08:30:00"), format = "%Y-%m-%d %H:%M:%S")
ID<-c(01,02,03)
ComparisonData<-data.frame(Comparison,ID)

这应该是这样的:

           Comparison  ID
1 2015-10-29 08:00:00   1
2 2015-11-02 08:00:00   2
3 2015-10-26 08:30:00   3

综上所述,代码应该检查某个ID的所有时间,看是否有任何时间早于或等于ComparisonData中指定的值,如果是,则减去一小时。这应该将此数据框作为输出:

                 Time  ID
1 2015-10-02 07:00:00   1
2 2015-11-02 11:00:00   1
3 2015-10-11 09:00:00   2
4 2015-11-11 09:00:00   2
5 2015-10-24 07:00:00   3
6 2015-10-27 08:00:00   3

我看过类似的解决方案,例如 this,但我无法理解如何使用具有特定 ID 的正确时间来检查时间。

我认为 ddply 似乎是一个很有前途的选择,但我不确定如何使用它来解决这个特定问题。

我相信会有比这更好的解决方案,但是,我认为这是可行的。

for(i in 1:nrow(data)) {
  if(data$Time[i] < ComparisonData[data$ID[i], 1]){
   data$Time[i] <- data$Time[i] - 3600
  }
}



#          Time ID
#1 2015-10-02 07:00:00  1
#2 2015-11-02 11:00:00  1
#3 2015-10-11 09:00:00  2
#4 2015-11-11 09:00:00  2
#5 2015-10-24 07:00:00  3
#6 2015-10-27 08:00:00  3

这将遍历 data 中的每一行。

ComparisonData[data$ID[i], 1] 获取 ComparisonData 中对应 IDtime 列。如果这大于 data 中的 Time 列,则将时间减少 1 小时。

这是一个使用 data.table 的快速有效的解决方案。首先我们通过 ID 连接两个数据集,然后只修改小于或等于 Comparison

Time
library(data.table) # v1.9.6+
setDT(data)[ComparisonData, end := i.Comparison, on = "ID"]
data[Time <= end, Time := Time - 3600L][, end := NULL]
data
#                   Time ID
# 1: 2015-10-02 07:00:00  1
# 2: 2015-11-02 11:00:00  1
# 3: 2015-10-11 09:00:00  2
# 4: 2015-11-11 09:00:00  2
# 5: 2015-10-24 07:00:00  3
# 6: 2015-10-27 08:00:00  3

或者,我们可以在使用 ifelse 加入时一步完成此操作(虽然不确定效率如何)

setDT(data)[ComparisonData, 
            Time := ifelse(Time <= i.Comparison, 
                           Time - 3600L, Time), 
            on = "ID"]
data
#                   Time ID
# 1: 2015-10-02 07:00:00  1
# 2: 2015-11-02 11:00:00  1
# 3: 2015-10-11 09:00:00  2
# 4: 2015-11-11 09:00:00  2
# 5: 2015-10-24 07:00:00  3
# 6: 2015-10-27 08:00:00  3