【发布时间】:2014-03-23 18:26:22
【问题描述】:
对不起,另一个新手问题。我正在尝试根据现有 ID 或索引获取部分数据框,然后根据第二列中值的差异创建新的 ID 或索引列。
例如,在下面的示例数据中,userID 1 似乎有 2 个会话:一个从 timeStamp 1 开始到 timeStamp 6 结束,另一个从 timeStamp 40 开始到 timeStamp 47 结束。如果两个 timeStamp 之间的差是= 30),那么这被认为是一个新会话。用户 2 只有 1 个会话; User3 有 3 个。
理想情况下,我希望在 sessionID 中保留用户 ID 信息;最后两列是所需格式的示例。如果将它们设为整数更容易,我可以稍后将 userID 和 sessID 连接起来。 var1, var2, varN 只是为了表明数据框中还有其他数据。
我试图避免传统的循环并获得 R-esque。我获取了 userID 和 timeStamp 信息,并通过 userID 创建了一个list,其中 timeStamps 作为列表 1 到最后一个 userID 的向量:
byUser <- with(myDF, split(timeStamp, userID))
部分真实数据如下所示:
structure(list(`1` = c(50108, 50108, 50171, 50175, 121316, 121316,
127228), `2` = c(55145, 745210, 1407020, 2283255),...
然后我使用diff 来获取每个向量中的时间戳之间的差异:
myDiff2 <- lapply(byUser, diff)
部分真实数据如下所示:
structure(list(`1` = c(0, 63, 4, 71141, 0, 5912), `2` = c(690065,
661810, 876235), `3` = c(109, 80, 98, 948417, 0),
...现在我觉得好像应该遍历每个列表,初始化 sessID,然后如果 myDiff2 中的值 > 1800 秒(30 分钟),则增加 sessID。
这似乎很长;请告诉我如何缩短它!提前致谢!
userID timeStamp var1 var2 varN sessID1 sessID2
1 1 1 x y N 1.0 1.1
2 1 3 x y N 1.0 1.1
3 1 6 x y N 1.0 1.1
4 1 40 x y N 1.1 1.2
5 1 42 x y N 1.1 1.2
6 1 43 x y N 1.1 1.2
7 1 47 x y N 1.1 1.2
8 2 5 x y N 2.0 2.1
9 2 8 x y N 2.0 2.1
10 3 2 x y N 3.0 3.1
11 3 5 x y N 3.0 3.1
12 3 38 x y N 3.1 3.2
13 3 39 x y N 3.1 3.2
14 3 39 x y N 3.1 3.2
15 3 82 x y N 3.2 3.3
16 3 83 x y N 3.2 3.3
17 3 90 x y N 3.2 3.3
18 3 91 x y N 3.2 3.3
19 3 102 x y N 3.2 3.3
数据示例的 dput() 在这里:
myDF <- structure(list(userID = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), timeStamp = c(1L, 3L,
6L, 40L, 42L, 43L, 47L, 5L, 8L, 2L, 5L, 38L, 39L, 39L, 82L, 83L,
90L, 91L, 102L), var1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "x", class = "factor"),
var2 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "y", class = "factor"),
varN = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "N", class = "factor"),
sessID1 = c(1, 1, 1, 1.1, 1.1, 1.1, 1.1, 2, 2, 3, 3, 3.1,
3.1, 3.1, 3.2, 3.2, 3.2, 3.2, 3.2), sessID2 = c(1.1, 1.1,
1.1, 1.2, 1.2, 1.2, 1.2, 2.1, 2.1, 3.1, 3.1, 3.2, 3.2, 3.2,
3.3, 3.3, 3.3, 3.3, 3.3)), .Names = c("userID", "timeStamp",
"var1", "var2", "varN", "sessID1", "sessID2"), class = "data.frame", row.names = c(NA,
-19L))
=== 以下答案的附录:
对于下一个新手:
选择一个“。” / 小数点分隔符对我来说可能并不出色:当 sessID 计数器从 9 滚动到 0 时,它导致了一些奇怪和非唯一的 sessID。
将分隔符更改为其他字符(例如连字符),一切正常。
@rawr 和@jlhoward - 感谢你们快速、正确且非常有帮助的回复:这两种方法都非常有效。 @jlhoward - 特别感谢 addt'l,高于职责的解释。 (@rawr 是第一个,所以我把答案归功于他。)
两种解决方案在性能上存在细微差别:data.table 更快,但需要预先将 data.frame 转换为 data.table。
再次感谢大家。
【问题讨论】: