[背景]
我有一些来自一组用户的在线事件数据:
userId
表示用户的ID。pageType
表示用户所在的当前页面。home
表示首页,content
表示内容页。- 页面已经按时间排序,所以第 1 行发生在第 2 行之前,第 2 行发生在第 3 行之前,...
- 实际数据大约有 200 万行和 8 种页面类型。
userId
是一个 36 个字符的java.util.UUID
对象。
[目标]
我想为每个 pageType
生成一个新列,并计算完全相同类型的先前页面浏览量(不包括当前页面浏览量)。
[示例数据]
生成实际数据的样本:
library(data.table)
DT <- data.table("userId"=rep(1:3, each=10),
"pageType"=c("home", "content", "home", "content", "home", "home", "content", "content", "home", "home",
"content", "content", "home", "home", "content", "home", "home", "content", "home", "content",
"home", "home", "content", "content", "home", "home", "content", "content", "home", "content"))
> DT
userId pageType
1: 1 home
2: 1 content
3: 1 home
4: 1 content
5: 1 home
6: 1 home
7: 1 content
8: 1 content
9: 1 home
10: 1 home
... ... ...
[我的尝试]
我试过用两种方法解决这个问题,但都太慢了。我还觉得我的解决方案没有按照设计的方式使用 data.table
。
解决方案一
- 按
pageType
过滤并按userId
递增。 - 为其他
pageType
设置缺失值。
代码如下:
FixPageView <- function(data, type) {
val <- 0
for (i in 1:nrow(data)) {
if (is.na(data[[type]][i])) {
set(data, i, type, val)
} else {
val <- data[[type]][i]
}
}
}
DT[pageType=="home", numHomePagesViewed:=0:(.N-1), by=userId]
DT[pageType=="content", numContentPagesViewed:=0:(.N-1), by=userId]
FixPageView(DT, "numHomePagesViewed")
FixPageView(DT, "numContentPagesViewed")
> DT
userId pageType numHomePagesViewed numContentPagesViewed
1: 1 home 0 0
2: 1 content 0 0
3: 1 home 1 0
4: 1 content 1 1
5: 1 home 2 1
6: 1 home 3 1
7: 1 content 3 2
8: 1 content 3 3
9: 1 home 4 3
10: 1 home 5 3
... ... ... ... ...
方案二
双重for
循环并逐行设置。
DT[, numHomePagesViewed := 0L][, numContentPagesViewed := 0L]
for (i in unique(DT$userId)) {
home_inc <- -1L
content_inc <- -1L
for (j in 1L:nrow(DT[userId==i])) {
if (DT$pageType[(i-1L)*10L + j] == "home") {
home_inc <- home_inc + 1L
set(DT, (i-1L)*10L + j, "numHomePagesViewed", home_inc)
} else {
set(DT, (i-1L)*10L + j, "numHomePagesViewed", max(0, home_inc))
}
if (DT$pageType[(i-1L)*10L + j] == "content") {
content_inc <- content_inc + 1L
set(DT, (i-1L)*10L + j, "numContentPagesViewed", content_inc)
} else {
set(DT, (i-1L)*10L + j, "numContentPagesViewed", max(0, content_inc))
}
}
}
> DT
userId pageType numHomePagesViewed numContentPagesViewed
1: 1 home 0 0
2: 1 content 0 0
3: 1 home 1 0
4: 1 content 1 1
5: 1 home 2 1
6: 1 home 3 1
7: 1 content 3 2
8: 1 content 3 3
9: 1 home 4 3
10: 1 home 5 3
... ... ... ... ...
[问题]
- 我可以做些什么来提高速度?
- 是否有更“
data.table
”的方式来解决这个问题?
最佳答案
我会尝试:
DT[,lapply(unique(pageType),
function(x) pmax(cumsum(pageType==x)-1,0)),by=userId]
接下来,您必须重命名获得的列。
如评论中所建议,您可以用一行分配名称:
DT[, paste0("num",unique(DT$pageType),"PagesViewed") :=
lapply(unique(pageType), function(x) pmax(cumsum(pageType==x)-1,0)), by=userId]
关于R data.table 按类别递增并将 NA 设置为最后一个非缺失值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32390521/