以下是该问题的示例数据,代码和说明:
require(data.table)
require(dplyr)
df1 <- read.table(text= "
col1 col2 col3 col4 col5
123 121 16519 1 4
123 121 16519 2 5
123 121 16518 3 5
123 121 16517 4 6
123 121 16512 5 7
123 121 16554 6 8
124 333 16554 7 9
124 333 16552 8 5
124 333 16549 1 1
124 333 16495 2 2
124 555 16573 4 4
125 555 16573 5 3
125 555 16569 6 5
125 555 16567 7 6
125 555 16568 8 7
", header=TRUE, na.strings=NA, stringsAsFactors=FALSE)
df2 <- distinct(df1[c("col1","col2","col3")])
setnames(df2, old=c("col1","col2","col3"), new=c("col11","col22","col33"))
res <- vector("list", nrow(df2))
for(i in 1:nrow(df2)) {
one_row <- df2[i,]
df <- merge(select(one_row, col11, col22, col33),
select(df1,col1,col2,col3,col4,col5),by=NULL)%>%
filter((col3 >= (col33-(7))) & (col3 < col33))
res[[i]] = df%>%
group_by(col11, col22,col33)%>%
summarise(Averagecol4=mean(col4,na.rm=TRUE), Count=n())
}
as.data.frame(do.call("rbind", res))
# col11 col22 col33 Averagecol4 Count
# 1 123 121 16519 4.0 3
# 2 123 121 16518 4.5 2
# 3 123 121 16517 5.0 1
# 4 123 121 16554 4.5 2
# 5 124 333 16554 4.5 2
# 6 124 333 16552 1.0 1
# 7 124 555 16573 7.0 3
# 8 125 555 16573 7.0 3
# 9 125 555 16569 7.5 2
# 10 125 555 16568 7.0 1
data.frame
。data.frame
res
,对于df2
中的每一行,执行与df1
的连接,然后执行条件过滤,聚合并将结果存储在{的相应索引中{1}}。res
最后的结果是获得最终rbind
。问题是,对于data.frame
,需要花费很多时间。我怎样才能加快速度?
答案 0 :(得分:1)
这是 data.table 解决方案,使用新的非equi 加入功能,目前在development version of data.table, v1.9.7中可用:
请参阅链接以获取安装说明。从df1
(这是一个data.frame)开始,这是我的进展方式:
require(data.table) # v1.9.7+
df2 = setDT(df1)[, .N, by = col1:col3][, col3_minus_7 := col3 - 7] ## (1)
ans = df1[df2, ## (2)
on = .(col3 >= col3_minus_7, col3 < col3), ## (3)
.(col1 = i.col1, col2 = i.col2,
mean = mean(col4, na.rm=TRUE), count = .N), ## (4)
by = .EACHI, ## (5)
nomatch = 0L, ## (6)
allow.cartesian = TRUE] ## (7)
setnames(ans, 1:2, c("col3_minus_7", "col3")) ## (8)
# col3_minus_7 col3 col1 col2 mean count
# 1: 16512 16519 123 121 4.0 3
# 2: 16511 16518 123 121 4.5 2
# 3: 16510 16517 123 121 5.0 1
# 4: 16547 16554 123 121 4.5 2
# 5: 16547 16554 124 333 4.5 2
# 6: 16545 16552 124 333 1.0 1
# 7: 16566 16573 124 555 7.0 3
# 8: 16566 16573 125 555 7.0 3
# 9: 16562 16569 125 555 7.5 2
# 10: 16561 16568 125 555 7.0 1
[1]获取唯一的行(通过col1, col2, col3
进行分组时间接生成计数 - 只是另一种方式)并添加一个新列col3_minus_7
,我们稍后需要这些列用于加入条件。
[2] df1[df2,
- 针对df2
的每一行,在df1
中查找匹配的行索引。
[3]根据条件:on = .(col3 >= col3_minus_7, col3 < col3)
,即df1$col3 >= df2$col3_minus_7
和 df1$col3 < df2$col3
。
[4] + [5]对于每个 df2
(.EACHI
)的匹配行,计算所需的表达式(平均值和计数以及其他cols)。详细了解by=.EACHI
here。
[6]如果df2
在指定的条件df1
中没有任何匹配的行,则不要返回任何内容。
[7] allow.cartesian
是用于保护意外无效连接的参数。阅读它here。
[8]手动重命名间隔列(现在,应该很快就会自动处理)。