用R

时间:2016-01-03 22:45:39

标签: sql r limit dplyr

TL; DR:这篇文章的大部分内容都包含了我尽可能明确的例子,但问题的核心包含在中间部分"实际问题"将例子简化为骨头。

我的问题:

我有一个数据库,其中包含有关足球比赛的数据,我试图从中提取一些统计数据 该数据库只包含一个名为' allMatches'的表,其中eache条目表示匹配,字段(我只包括绝对必要的字段,以便了解问题是什么)表是:

  • ID:int,表的主键
  • 日期:日期,比赛日期
  • HT:varchar,主队
  • AT:varchar,客场球队
  • HG:int,主队得分
  • AG:int,客队比分

对于数据库中的每个条目,我必须提取一些关于离开和主队的统计信息。当您考虑所有以前的比赛的统计数据时,这可以很容易地实现,例如,获得目标得分和失败的统计数据,首先我运行此查询:

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:原始数据库中相应匹配项的ID
  • 团队:此行中的数据大约是
  • 的团队
  • totalScored:球队在ID
  • 指示的所有比赛中得分的进球
  • totalConceded:团队在ID
  • 指示的所有比赛中得分的目标

换句话说,如果在最后一个查询中我得到:

|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解决方案会好得多。

3 个答案:

答案 0 :(得分:1)

totalScoredtotalConceded字段分别考虑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)

如果您要使用R,请不要特别注意。使用MS SQL {/ 1}}可以轻松实现这一点。

所以,你可以这样做:

PARTITION

检查结果 here ,它与您想要的输出相同。