如何在R中基于最近匹配时间压缩数据帧
我有一个数据帧,当前包含两个HH:MM:SS格式的“时间”列。我希望压缩此数据帧,以便每个唯一的“id”值只有一行。我希望为每个唯一的“id”值保留行,该值具有与“time2”值最匹配的“time1”值。但是,“time1”必须大于“time2” 下面是一个简单的例子:如何在R中基于最近匹配时间压缩数据帧,r,time,match,datetime-format,R,Time,Match,Datetime Format,我有一个数据帧,当前包含两个HH:MM:SS格式的“时间”列。我希望压缩此数据帧,以便每个唯一的“id”值只有一行。我希望为每个唯一的“id”值保留行,该值具有与“time2”值最匹配的“time1”值。但是,“time1”必须大于“time2” 下面是一个简单的例子: > dput(df) structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L), count = c(23
> dput(df)
structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L,
3L, 3L, 4L, 4L, 4L, 4L), count = c(23L, 23L, 23L, 23L, 45L, 45L,
45L, 45L, 67L, 67L, 67L, 67L, 88L, 88L, 88L, 88L), time1 = structure(c(1L,
1L, 1L, 1L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 3L, 3L, 3L, 3L), .Label = c("00:13:00",
"01:13:00", "07:18:00", "18:14:00"), class = "factor"), time2 = structure(c(4L,
1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L), .Label = c("00:00:00",
"06:00:00", "12:00:00", "18:00:00"), class = "factor"), afn = c(3.36,
0.63, 1.77, 3.89, 3.36, 0.63, 1.77, 3.89, 3.36, 0.63, 1.77, 3.89,
3.36, 0.63, 1.77, 3.89), dfn = c(201.67, 157.27, 103.55, 191.41,
201.67, 157.27, 103.55, 191.41, 201.67, 157.27, 103.55, 191.41,
201.67, 157.27, 103.55, 191.41)), .Names = c("id", "count", "time1",
"time2", "afn", "dfn"), class = "data.frame", row.names = c(NA,
-16L))
> df
id count time1 time2 afn dfn
1 1 23 00:13:00 18:00:00 3.36 201.67
2 1 23 00:13:00 00:00:00 0.63 157.27
3 1 23 00:13:00 06:00:00 1.77 103.55
4 1 23 00:13:00 12:00:00 3.89 191.41
5 2 45 01:13:00 18:00:00 3.36 201.67
6 2 45 01:13:00 00:00:00 0.63 157.27
7 2 45 01:13:00 06:00:00 1.77 103.55
8 2 45 01:13:00 12:00:00 3.89 191.41
9 3 67 18:14:00 18:00:00 3.36 201.67
10 3 67 18:14:00 00:00:00 0.63 157.27
11 3 67 18:14:00 06:00:00 1.77 103.55
12 3 67 18:14:00 12:00:00 3.89 191.41
13 4 88 07:18:00 18:00:00 3.36 201.67
14 4 88 07:18:00 00:00:00 0.63 157.27
15 4 88 07:18:00 06:00:00 1.77 103.55
16 4 88 07:18:00 12:00:00 3.89 191.41
在上述情况下,我想以这个矩阵结束:
id count time1 time2 afn dfn
1 23 00:13:00 00:00:00 0.63 157.27
2 45 01:13:00 00:00:00 0.63 157.27
3 67 18:14:00 18:00:00 3.36 201.67
4 88 07:18:00 06:00:00 1.77 103.55
我以前使用过ddply()函数来压缩数据帧,但没有使用合并的匹配规则。我必须应用这是一个有很多列的数据框架(比这里给出的简单示例多得多),所以任何关于如何做到这一点的建议都是非常棒的。任何帮助都将不胜感激。非常感谢 下面是一个使用强大的
dplyr
包的方法:
library(dplyr)
(df %.%
mutate(timeDiff = as.integer(strptime(time1, "%X") - strptime(time2, "%X")),
posDiff = timeDiff >= 0) %.%
filter(posDiff) %.%
group_by(id) %.%
filter(min(timeDiff) == timeDiff))[names(df)]
# id count time1 time2 afn dfn
# 1 1 23 00:13:00 00:00:00 0.63 157.27
# 2 2 45 01:13:00 00:00:00 0.63 157.27
# 3 3 67 18:14:00 18:00:00 3.36 201.67
# 4 4 88 07:18:00 06:00:00 1.77 103.55
这里有一些解决方案 1)ave这使用时间
时间以及子集和ave
从R的基础:
library(chron)
delta <- as.vector(times(df$time1) - times(df$time2))
df2 <- subset(df, delta > 0)
df2[ave(delta, df2$id, FUN = function(delta) delta == min(delta)) == 1, ]
3)sqldf
library(sqldf)
sqldf("select *, min(strftime('%s', time1) - strftime('%s', time2)) delta
from (select * from df where strftime('%s', time1) > strftime('%s', time2))
group by id")[seq_along(df)]
或者我们在R中计算delta
,然后使用sqldf
:
library(sqldf)
library(chron)
df2 = transform(df, delta = as.vector(times(time1) - times(time2)))
sqldf("select *, min(delta) delta
from (select * from df2 where delta > 0)
group by id")[-ncol(df2)]
4)数据表
library(data.table)
library(chron)
DT <- data.table(df)
DT[, delta := times(time1) - times(time2)
][delta > 0
][, .SD[delta == min(delta)], by = id
][, seq_along(df), with = FALSE]
库(data.table)
图书馆(计时)
DT 0
][,.SD[delta==min(delta)],by=id
][,顺时针(df),带=假]
添加了其他解决方案。已更正库
和子集
语句。较小的改进。使用ddply
和merge
的方法。(假设“最近匹配时间”是difftime
s的最小绝对值)
t1我想指出,订购表明18:00:00
在00:00:00
@G之前。Grothendieck:非常感谢您提供了许多不同的选择。dplyr太棒了!只是一件小事:它应该读取代码行3上的df2 0)
而不是子集(df2…
?非常感谢你的帮助!是的,我现在已经修好了。谢谢。@Sven:也非常感谢dplyr的建议。我必须对这个包裹做更多的调查。@Julien:谢谢你的回答。在代码中定义数据的地方应该有额外的一行吗?哦,不,对不起,它是“df”而不是“datas”事实上,请注意,strtime输出包括今天的日期,因此如果碰巧t1设置在午夜之前,然后t2设置在午夜之后,那么t1和t2将具有不同的日期,而如果它们在同一天运行,则具有相同的日期。当然,这是极不可能的,但这是可能的。
library(data.table)
library(chron)
DT <- data.table(df)
DT[, delta := times(time1) - times(time2)
][delta > 0
][, .SD[delta == min(delta)], by = id
][, seq_along(df), with = FALSE]
t1 <- strptime(df$time1, "%H:%M:%S")
t2 <- strptime(df$time2, "%H:%M:%S")
df$min.diff <- abs(as.numeric(difftime(t1, t2, units='mins')))
d1 <- ddply(df, .(id), summarize, min.diff = min(min.diff))
> merge(df, d1, by = c("id", "min.diff"))
id min.diff count time1 time2 afn dfn
1 1 13 23 00:13:00 00:00:00 0.63 157.27
2 2 73 45 01:13:00 00:00:00 0.63 157.27
3 3 14 67 18:14:00 18:00:00 3.36 201.67
4 4 78 88 07:18:00 06:00:00 1.77 103.55