在 R 中创建一个运行计数变量?
Posted
技术标签:
【中文标题】在 R 中创建一个运行计数变量?【英文标题】:Creating a running counting variable in R? 【发布时间】:2015-07-21 10:45:17 【问题描述】:我有一个足球比赛结果数据集,我希望通过创建一组类似于 World Football Elo 公式的运行评分来学习 R。我遇到了一些在 Excel 中看似简单的事情在 R 中并不完全直观的问题。例如,4270 个观察值中的前 15 个带有必要变量:
date t.1 t.2 m.result
1 19960406 DC SJ 0.0
2 19960413 COL KC 0.0
3 19960413 NE TB 0.0
4 19960413 CLB DC 1.0
5 19960413 LAG NYRB 1.0
6 19960414 FCD SJ 0.5
7 19960418 FCD KC 1.0
8 19960420 NE NYRB 1.0
9 19960420 DC LAG 0.0
10 19960420 CLB TB 0.0
11 19960421 COL FCD 1.0
12 19960421 SJ KC 0.5
13 19960427 CLB NYRB 1.0
14 19960427 DC NE 0.5
15 19960428 FCD TB 1.0
我希望能够创建一个新变量,该变量将是 t.1 和 t.2 的总比赛次数的运行计数(即,截至 t 列中出现“DC”的日期的实例。 1 或 t.2):
date t.1 t.2 m.result ##t.1m ##t.2m
1 19960406 DC SJ 0.0 1 1
2 19960413 COL KC 0.0 1 1
3 19960413 NE TB 0.0 1 1
4 19960413 CLB DC 1.0 1 2
5 19960413 LAG NYRB 1.0 1 1
6 19960414 FCD SJ 0.5 1 2
7 19960418 FCD KC 1.0 2 2
8 19960420 NE NYRB 1.0 2 2
9 19960420 DC LAG 0.0 3 2
10 19960420 CLB TB 0.0 2 2
11 19960421 COL FCD 1.0 2 3
12 19960421 SJ KC 0.5 3 3
13 19960427 CLB NYRB 1.0 3 3
14 19960427 DC NE 0.5 4 3
15 19960428 FCD TB 1.0 4 3
在 Excel 中,这是一个(相对)简单的 =SUMPRODUCT 方程,例如:
E4=SUMPRODUCT((A:A<=A4)*(B:B=B4))+SUMPRODUCT((A:A<=A4)*(C:C=B4))
其中 E4 是 obs # 4 的 t.1m,A:A 是日期,B:B 是 t.1,C:C 是 t.2,等等。
但是在 R 中,我可以为我打印总和产品(即“DC”在我的数据集中玩了 576 场游戏),但出于某种原因(可能是我是新手,不耐烦,因反复试验而焦躁不安)我'我只是迷失了如何对观察数据进行运行计数,尤其是如何将运行计数变为变量,这对于任何游戏评分指数都至关重要。我知道存在“PlayerRatings”,我觉得对于我的 R 教育,我应该能够在没有那个包的 R 套件中做到这一点。 plyr 或 dplyr 当然可以。
作为参考,这是我的数据供您复制/粘贴到您的 R 中。
date<-c(19960406,19960413,19960413,19960413,19960413,19960414,19960418,19960420,19960420,19960420,19960421,19960421,19960427,19960427,19960428)
t.1<-c("DC","COL","NE","CLB","LAG","FCD","FCD","NE","DC","CLB","COL","SJ","CLB","DC","FCD")
t.2<-c("SJ","KC","TB","DC","NYRB","SJ","KC","NYRB","LAG","TB","FCD","KC","NYRB","NE","TB")
m.result<-c(0.0,0.0,0.0,1.0,1.0,0.5,1.0,1.0,0.0,0.0,1.0,0.5,1.0,0.5,1.0)
mtable<-data.frame(date,t.1,t.2,m.result)
mtable
【问题讨论】:
相关:Running count based on field in R。那位给出的答案在我的大问题上的运行速度比下面接受的答案要快得多。 【参考方案1】:在您的数据创建步骤中,请确保stringsAsFactors = FALSE
以避免出现问题。然后很容易做到。 (编辑:我把这个作为dplyr
的例子)
library(dplyr)
cross_count <- function(id, var)
length(which(mtable[id, var] == mtable[1:id, ] %>% select(t.1, t.2) %>% unlist))
mtable %>%
arrange(date) %>% # This makes sure the dates are in order
mutate(id = 1:nrow(.)) %>%
rowwise() %>%
mutate(t.1m = cross_count(id, 2), t.2m = cross_count(id, 3))
date t.1 t.2 m.result id t.1m t.2m
1 19960406 DC SJ 0.0 1 1 1
2 19960413 COL KC 0.0 2 1 1
3 19960413 NE TB 0.0 3 1 1
4 19960413 CLB DC 1.0 4 1 2
5 19960413 LAG NYRB 1.0 5 1 1
6 19960414 FCD SJ 0.5 6 1 2
7 19960418 FCD KC 1.0 7 2 2
8 19960420 NE NYRB 1.0 8 2 2
9 19960420 DC LAG 0.0 9 3 2
10 19960420 CLB TB 0.0 10 2 2
11 19960421 COL FCD 1.0 11 2 3
12 19960421 SJ KC 0.5 12 3 3
13 19960427 CLB NYRB 1.0 13 3 3
14 19960427 DC NE 0.5 14 4 3
15 19960428 FCD TB 1.0 15 4 3
【讨论】:
【参考方案2】:这是一个非常简单的解决方案,虽然不是很漂亮,但确实可以。
首先,只需更改您的数据以使比较更容易:
mtable<-data.frame(date,t.1,t.2,m.result, stringsAsFactors = FALSE)
编辑于:
如果您想确保匹配按日期排序,您可以使用@eipi10 指出的order
:
mtable = mtable[order(mtable$date), ]
请注意,如果日期的格式不是按时间顺序排列的整数顺序,您可以先使用as.Date()
将它们转换为日期格式。
我们要做的是,对于每一行,获取数据帧的一个子集,其中包含 t.1
和 t.2
列,所有行从 1 到所述行。所以 1:1、1:2、1:3 等等。在每次运行时,我们都会计算该团队出现的次数,并将其用作新列的结果。
mtable$t.1m <- sapply(1:nrow(mtable),
function(i) sum(mtable[1:i, c("t.1", "t.2")] == mtable$t.1[i]))
这是为t.1
中的团队完成的,在==
之后的参数稍有变化@我们可以为t.2
做:
mtable$t.2m <- sapply(1:nrow(mtable),
function(i) sum(mtable[1:i, c("t.1", "t.2")] == mtable$t.2[i]))
现在我们的数据框如下所示:
> mtable
date t.1 t.2 m.result t.1m t.2m
1 19960406 DC SJ 0.0 1 1
2 19960413 COL KC 0.0 1 1
3 19960413 NE TB 0.0 1 1
4 19960413 CLB DC 1.0 1 2
5 19960413 LAG NYRB 1.0 1 1
6 19960414 FCD SJ 0.5 1 2
7 19960418 FCD KC 1.0 2 2
8 19960420 NE NYRB 1.0 2 2
9 19960420 DC LAG 0.0 3 2
10 19960420 CLB TB 0.0 2 2
11 19960421 COL FCD 1.0 2 3
12 19960421 SJ KC 0.5 3 3
13 19960427 CLB NYRB 1.0 3 3
14 19960427 DC NE 0.5 4 3
15 19960428 FCD TB 1.0 4 3
【讨论】:
谢谢!这很好用。追问:我注意到你根本没有提到日期变量。假设我的数据分散在日期变量中,并且我想在团队玩游戏的最早时间排序我的运行计数。代码有变化吗? 您可以在运行 Molx 的代码之前按日期对表格进行排序:mtable = mtable[order(mtable$date), ]
。【参考方案3】:
似乎单独的列 t.1m 和 t.2m 用于记账,而您真的只对玩的游戏数量感兴趣吗?我使用with()
来处理 mtable 的列,而不必每次都编写 mtable
mtable$games <- with(mtable,
如果某个特定的团队参加比赛,它会作为第 1 队或第 2 队参加比赛
played <- t.1 == "DC" | t.2 == "DC"
比较是矢量化的,将 t.1 列的每个元素与“DC”等进行比较,逻辑比较也是矢量化的,因此单个|
。
数据的一个棘手部分是一天中有几支球队参加比赛,并且在比赛当天(显然)只有焦点球队应该增加。我通过弄清楚如何安排比赛来解决这个问题,以便焦点团队在比赛当天总是排在最后
o <- order(date, played)
然后计算游戏的累积总和
games <- cumsum(played[o])
并将游戏恢复到原来的顺序
games[order(o)]
)
这是结果
> head(mtable, 11)
date t.1 t.2 m.result games
1 19960406 DC SJ 0.0 1
2 19960413 COL KC 0.0 1
3 19960413 NE TB 0.0 1
4 19960413 CLB DC 1.0 2
5 19960413 LAG NYRB 1.0 1
6 19960414 FCD SJ 0.5 2
7 19960418 FCD KC 1.0 2
8 19960420 NE NYRB 1.0 2
9 19960420 DC LAG 0.0 3
10 19960420 CLB TB 0.0 2
11 19960421 COL FCD 1.0 3
这是一个实现此功能的函数,可以轻松指定焦点团队
gamesplayed <- function(date, t1, t2, focal="DC")
played <- t1 == focal | t2 == focal
o <- order(date, played)
cumsum(played[o])[order(o)]
【讨论】:
【参考方案4】:使用您提到的类似方式完成此操作:
sum(mtable$t.1 == 'DC', mtable$t.2 == 'DC')
【讨论】:
以上是关于在 R 中创建一个运行计数变量?的主要内容,如果未能解决你的问题,请参考以下文章
r 一个简单的R脚本,用于在Win / Open BUGS中创建在OpenBUGS中运行的邻接数据