R 需要帮助优化类似cumsum的代码-sqldf、data.table、非equi联接
正在寻找帮助以优化我的sqldf代码,该代码基于非相等联接生成聚合的历史统计数据,即数据仅聚合到当前数据行 重要的是,任何解决方案都能够适用于许多不同的组,如按tourney_名称筛选聚合等。。在sqldf示例中 获取数据:R 需要帮助优化类似cumsum的代码-sqldf、data.table、非equi联接,r,dplyr,data.table,cumsum,R,Dplyr,Data.table,Cumsum,正在寻找帮助以优化我的sqldf代码,该代码基于非相等联接生成聚合的历史统计数据,即数据仅聚合到当前数据行 重要的是,任何解决方案都能够适用于许多不同的组,如按tourney_名称筛选聚合等。。在sqldf示例中 获取数据: library(dplyr); library(sqldf); data_list <- list() for(i in 2000:2018){ data_list[[i]] <- readr::read_csv(paste0('ht
library(dplyr); library(sqldf); data_list <- list()
for(i in 2000:2018){
data_list[[i]] <-
readr::read_csv(paste0('https://raw.githubusercontent.com/JeffSackmann/tennis_atp/master/atp_matches_',i,'.csv')) %>%
as.data.frame}
data <- data.table::rbindlist(data_list)
data <- select(data, tourney_name, tourney_date, match_num, winner_id, winner_name, loser_id, loser_name)
system.time(
data2 <- sqldf("select a.*,
count(b.winner_id) as winner_overall_wins
from data a
left join data b
on (a.winner_id = b.winner_id and a.tourney_date > b.tourney_date)
group by a.tourney_name, a.tourney_date, a.match_num, a.winner_id
order by tourney_date desc, tourney_name, match_num desc",
stringsAsFactors = FALSE)
) # takes 16 sec, would like to look for a vectorized solution
head(data2)
库(dplyr);图书馆(sqldf);data_listOP要求优化大量级联sqldf
语句(在OP编辑之前)。不幸的是,OP没有口头解释他实现了哪些聚合。因此,需要大量的逆向工程
无论如何,下面是我将使用data.table
实现相同结果的方法。OP的sqldf
代码的执行时间从16秒减少到数据.table
版本的不到0.2秒
data.table
已编辑示例的版本
OP编辑了该问题,以减少sqldf
语句的数量。现在,只计算一个聚合
data2
中的新列winner\u total\u wins
是在实际锦标赛开始之前,获胜者赢得的所有比赛的计数。此号码附在获胜者赢得的实际锦标赛的所有比赛上。(请注意,这与实际比赛之前赢得的比赛计数不同)
自1.9.8版(2016年11月25日)以来,data.table
能够进行非等联接。此外,fread()
建议只读取所选列,这将进一步加快I/O速度
library(data.table) # v1.11.2
urls <- sprintf(
"https://raw.githubusercontent.com/JeffSackmann/tennis_atp/master/atp_matches_%i.csv",
2000:2018)
selected_cols <- c("tourney_name", "tourney_date", "match_num",
"winner_id", "winner_name",
"loser_id", "loser_name")
# read only selected columns from files & combine into one data object
matches <- rbindlist(lapply(urls, fread, select = selected_cols))
# non-equi join to compute aggregate, second join to append, order result
system.time({
result_nej <- matches[
unique(matches[matches, on = .(winner_id, tourney_date < tourney_date),
.(winner_overall_wins = .N), by = .EACHI]),
on = .(winner_id, tourney_date)][
order(-tourney_date, tourney_name, -match_num)]
})
使用cumsum()
和shift()
还有一种更快的替代解决方案:
system.time({
#累积操作需要有序的数据
设置顺序(比赛、锦标赛日期、锦标赛名称、比赛编号)
#添加锦标赛id以方便和简洁
比赛[,t\U id:=rleid(锦标赛日期,锦标赛名称)]
#按球员和锦标赛汇总
p_t_histOP要求优化大量级联sqldf
语句(在OP编辑之前)。不幸的是,OP没有口头解释他实现了哪些聚合。因此,需要大量的反向工程
无论如何,我将使用data.table
实现相同的结果。OP的sqldf
代码的执行时间从16秒减少到data.table
版本的不到0.2秒
data.table
已编辑示例的版本
OP编辑了这个问题,以减少sqldf
语句的数量。现在,只计算一个聚合
data2
中的新列winner\u total\u wins
是在实际锦标赛开始之前,赢家赢得的所有比赛的计数。此数字附加到赢家赢得的实际锦标赛的所有比赛。(请注意,这与实际比赛之前赢得的比赛计数不同)
自1.9.8版(2016年11月25日)以来,数据表
能够进行非等联接。此外,fread()
可以建议只读取所选列,从而进一步加快I/O速度
library(data.table) # v1.11.2
urls <- sprintf(
"https://raw.githubusercontent.com/JeffSackmann/tennis_atp/master/atp_matches_%i.csv",
2000:2018)
selected_cols <- c("tourney_name", "tourney_date", "match_num",
"winner_id", "winner_name",
"loser_id", "loser_name")
# read only selected columns from files & combine into one data object
matches <- rbindlist(lapply(urls, fread, select = selected_cols))
# non-equi join to compute aggregate, second join to append, order result
system.time({
result_nej <- matches[
unique(matches[matches, on = .(winner_id, tourney_date < tourney_date),
.(winner_overall_wins = .N), by = .EACHI]),
on = .(winner_id, tourney_date)][
order(-tourney_date, tourney_name, -match_num)]
})
使用cumsum()
和shift()
还有一种更快的替代解决方案:
system.time({
#累积操作需要有序的数据
设置顺序(比赛、锦标赛日期、锦标赛名称、比赛编号)
#添加锦标赛id以方便和简洁
比赛[,t\U id:=rleid(锦标赛日期,锦标赛名称)]
#按球员和锦标赛汇总
p_t___________________________________________________________________用最少的列和行来演示您正在尝试做的事情。我猜您想要的是类似于a[b,on=(p1_id,tourney_date>tourney_date)的东西,…]
,但我不想实际运行所有要检查的代码,抱歉。请务必在上查看此指南。感谢您的帮助…我在1 swoop中尝试了连接和聚合,但没有成功。您建议先进行连接,然后再进行聚合吗?data3a[data3b,list(p1_总体_wins2=sum(p1_赢得),p1_totall_losses2=sum(p1_won==0),p1_totall_ace2=mean(p1_ace,na.rm=TRUE)),by=list(tourney_name,tourney_date,match_num,p1_id),on=(p1_id=p1_id2,tourney_date>tourney_date2),allow.cartesian=TRUE]
也非常关注使我的示例具有可复制性,并希望检查一个大型数据集,因此是一个很长的示例。我将尝试将其归结为更基本的概念,看看是否能够理解,然后问一个更简单的问题。谢谢!这个问题太长了(对我来说).一般来说,如果你的问题比一页长,你要求的太多了。将你的问题简化为其核心内容。只是想展示我所有的尝试…我将尝试简化。让我知道现在是否更好。这是一个开始。如果你有一个小(!)用最少的列和行来演示您正在尝试做的事情。我猜您想要的是类似于a[b,on=(p1_id,tourney_date>tourney_date)的东西,…]
,但我不想实际运行所有要检查的代码,抱歉。请务必在上查看此指南。感谢您的帮助…我在1 swoop中尝试了加入和聚合,但没有效果。那么,您是否建议进行加入
tourney_name tourney_date match_num winner_id winner_name loser_id loser_name winner_overall_wins
1: Australian Open 20180115 701 103819 Roger Federer 105227 Marin Cilic 1128
2: Australian Open 20180115 602 103819 Roger Federer 111202 Hyeon Chung 1128
3: Australian Open 20180115 504 103819 Roger Federer 104607 Tomas Berdych 1128
4: Australian Open 20180115 408 103819 Roger Federer 105916 Marton Fucsovics 1128
5: Australian Open 20180115 316 103819 Roger Federer 104755 Richard Gasquet 1128
---
1131: Marseille 20000207 3 103819 Roger Federer 102179 Antony Dupuis 4
1132: Davis Cup WG R1: SUI vs AUS 20000204 2 103819 Roger Federer 102882 Mark Philippoussis 3
1133: Australian Open 20000117 90 103819 Roger Federer 102466 Jan Kroslak 1
1134: Australian Open 20000117 52 103819 Roger Federer 102021 Michael Chang 1
1135: Adelaide 20000103 2 103819 Roger Federer 102533 Jens Knippschild 0
system.time({
# cumumlative operations require ordered data
setorder(matches, tourney_date, tourney_name, match_num)
# add tourney id for convenience and conciseness
matches[, t_id := rleid(tourney_date, tourney_name)]
# aggregate by player and tourney
p_t_hist <- matches[, .(winner_won = .N), by = .(winner_id, t_id)]
# compute cumulative sum for each player and
# lag to show only matches of previous tourneys
tmp <- p_t_hist[order(t_id),
.(t_id, winner_overall_wins = shift(cumsum(winner_won))),
by = winner_id]
# append new column & order result
result_css <- matches[tmp, on = .(t_id, winner_id)][order(-t_id)]
})
p_name <- "Federer"; result_css[winner_name %like% p_name | loser_id %like% p_name]