TL; DR:这篇文章的大部分内容都包含了我尽可能明确的例子,但问题的核心包含在中间部分"实际问题"将例子简化为骨头。
我有一个数据库,其中包含有关足球比赛的数据,我试图从中提取一些统计数据 该数据库只包含一个名为' allMatches'的表,其中eache条目表示匹配,字段(我只包括绝对必要的字段,以便了解问题是什么)表是:
对于数据库中的每个条目,我必须提取一些关于离开和主队的统计信息。当您考虑所有以前的比赛的统计数据时,这可以很容易地实现,例如,获得目标得分和失败的统计数据,首先我运行此查询:
singleTeamAllMatches=
select ID as MatchID,
Date as Date,
HT as Team,
HG as Scored,
AG as Conceded
from allMatches
UNION ALL
select ID as MatchID,
Date as Date,
AT as Team,
AG as Scored,
HG as Conceded
from allMatches;
这不是绝对必要的,因为它只是以这种方式转换原始表:
this row in allMatches:
|ID |Date | HT |AT |HG | AG|
|42 |2011-05-08 |Genoa |Sampdoria | 2 | 1 |
"becomes" two rows in singleTeamAllMatches:
|MatchID |Date |Team |Scored|Conceded|
|42 |2011-05-08 |Genoa | 2 | 1 |
|42 |2011-05-08 |Sampdoria | 1 | 2 |
但允许我通过一个非常简单的查询获得我需要的统计数据:
select a.MatchID as MatchID,
a.Team as Team,
Sum(b.Scored) as totalScored,
Sum(b.Conceded) as totalConceded
from singleTeamAllMatches a, singleTeamAllMatches b
where a.Team == b.Team AND b.Date < a.Date
我最终得到一个查询,当运行时,返回:
换句话说,如果在最后一个查询中我得到:
|MatchID| Team |totalScored|totalConceded|
|42 | Genoa |38 | 40 |
|42 | Sampdoria |30 | 42 |
这意味着热那亚和桑普多利亚队在比赛中与对手42队进行了对战,在那场比赛之前,热那亚队打入38球并失球40分,而桑普多利亚队则得分30分,失球42分。
现在,这很容易,因为我考虑以前的所有比赛,我不知道如何完成是如何只考虑之前的6场比赛获得完全相同的统计数据。例如,让我们在singleTeamAllMatches中说:
|MatchID |Date |Team |Scored|Conceded|
|1 |2011-05-08 |TeamA | 1 | 5 |
|2 |2011-06-08 |TeamA | 0 | 2 |
|3 |2011-07-08 |TeamA | 3 | 0 |
|4 |2011-08-08 |TeamA | 4 | 0 |
|5 |2011-09-08 |TeamA | 1 | 0 |
|6 |2011-10-08 |TeamA | 0 | 1 |
|7 |2011-11-08 |TeamA | 0 | 1 |
|8 |2011-12-08 |TeamA | 1 | 1 |
我需要找到一种方法来获得这样的东西:
|MatchID| Team |totalScored|totalConceded|
|1 | TeamA |0 | 0 |
|2 | TeamA |1 | 5 |
|3 | TeamA |1 | 7 |
|4 | TeamA |4 | 7 |
|5 | TeamA |8 | 7 |
|6 | TeamA |9 | 7 |
|7 | TeamA |9 | 8 |
|8 | TeamA |8 | 4 |
让我们看看此查询中的最后两行:
第7排意味着在比赛7之前的最后6场比赛(比赛1-6)中,teamA打进了9个进球并且丢了8
第8排并未受到比赛1中进球的影响,因为它只是告诉我们在比赛前的最后6场比赛中8场比赛(比赛2-7),球队A打进8球并失球4。
有没有办法通过sqldf包用sql获取?
(编辑:实际上任何解决方案都可以,使用dplyr包,任务几乎是微不足道的,并且有效地完成)
目前,我唯一想到的就是导入R中的数据并使用sql&#39; LIMIT&#39;循环遍及allMatches中的所有行。和sqldf R包。
以下是对我使用的代码中使用的示例I的修改。这只是一个仅为主队获取统计数据的示例,但完整的代码很长,在这里不会有用。
allMatches和singleTeamAllMatches是数据框,其结构和内容与我上面描述的表和查询相同。
lastMatchesData <- NULL
for(match in (1:nrow(allMatches))){
matchRow <- allMatches[match,]
T <- matchRow$HT
Date <- matchRow$Date
ID <- matchRow$ID
lastMatches <- singleTeamAllMatches[singleTeamAllMatches$T == T & singleTeamAllMatches$Date < Date ,]
TPerformance <- sqldf("select sum(Scored) as Scored,
sum(Conceded) as Conceded
from
(select * from lastMatches order by Date DESC limit 6)")
newRow <- cbind(ID,TPerformance)
lastMatchesData <- rbind(lastMatchesData,newRow)
}
我不喜欢这个解决方案有两个原因:首先,它真的很丑陋和混乱,请记住这只是一个样本,但在将来我想我会修改这个代码和全sql解决方案会好得多。 第二个原因是它很慢,而且我的意思是非常慢,再次使用全SQL解决方案会好得多。
答案 0 :(得分:1)
对totalScored
和totalConceded
字段分别考虑correlated aggregate subqueries,在最后6场比赛中进行调整。在聚合查询中使用派生表子查询来检查其性能。
SELECT t1.Date, t1.MatchID, t1.Team,
(SELECT Sum(t2.Scored)
FROM (SELECT t2sub.MatchID, t2sub.Team, t2sub.Scored
FROM singleTeamAllMatches t2sub
WHERE t2sub.Team = t1.Team
AND t2sub.Date < t1.Date
ORDER BY t2sub.Date DESC
LIMIT 6) As t2
) As totalScored,
(SELECT Sum(t3.Conceded)
FROM (SELECT t3sub.MatchID, t3sub.Team, t3sub.Conceded
FROM singleTeamAllMatches t3sub
WHERE t3sub.Team = t1.Team
AND t3sub.Date < t1.Date
ORDER BY t3sub.Date DESC
LIMIT 6) As t3
) As totalConceded
FROM singleTeamAllMatches t1
答案 1 :(得分:1)
以下是我使用dplyr提出的一个解决方案:
library(dplyr)
df <- df %>% group_by(Team) %>% mutate(cumScored = cumsum(Scored), totalScored = cumScored - ifelse(row_number() >= 7, lag(cumScored, 6), 0), cumConceded = cumsum(Conceded), totalConceded = cumConceded - ifelse(row_number() >= 7, lag(cumConceded, 6), 0)) %>% select(-cumScored, -cumConceded)
这个想法是首先计算得分和让步的累积总和,然后仅保留最后六个匹配,从当前累积总和中减去累积总和的第6个滞后,这样就可以获得过去六个累计总和的累计总和比赛滞后。我无法找到一种方法来实现累积总和超过任意数量的滞后。因此,使用添加新列然后取消选择它的技巧。希望这会有所帮助。
答案 2 :(得分:1)