在给定日期 - 30天窗口内排名最近的学生分数

gib*_*z00 6 r rank dplyr data.table

以下是我的dataframe/data.table的样子.该rank列是我想要的计算字段.

library(data.table)
df <- fread('
             Name   Score         Date              Rank
             John    42         1/1/2018              3   
             Rob     85         12/31/2017            2
             Rob     89         12/26/2017            1
             Rob     57         12/24/2017            1
             Rob     53         08/31/2017            1
             Rob     72         05/31/2017            2
             Kate    87         12/25/2017            1
             Kate    73         05/15/2017            1
             ')
df[,Date:= as.Date(Date, format="%m/%d/%Y")]
Run Code Online (Sandbox Code Playgroud)

我试图在30天窗口内的数据中计算每个学生在每个给定时间点的等级.为此,我需要在给定的时间点获取所有学生的最新分数,然后通过等级函数.

在第1行,为的1/1/2018,John已经在过去30天的窗口,两个竞争对手:罗布与最近的得分8512/31/2017和凯特与最近的得分8712/25/2017和这两个日期都落在内1/1/2018 - 30天的窗口.约翰3得分最低42.如果只有一名学生date(at a given row) - 30 day window,则排名为1.

在第3行,日期是12/26/2017.所以Rob的得分12/26/201789.只有一个案例的另一名学生落入时间窗口,12/26/2017 - 30这是87凯特最近的得分()12/25/2017.因此,在时间窗口内(12/26/2017) - 30,Rob的得分89高于Kate的得分,87因此Rob获得了排名1.

我正在考虑使用这里的框架在过去的365天窗口中执行运行总计的有效方法,但是在使用排名之前努力想到一种方法来获取所有学生在给定时间点的所有最近得分.

Fra*_*ank 5

这似乎有效:

ranks = df[.(d_dn = Date - 30L, d_up = Date), on=.(Date >= d_dn, Date <= d_up), allow.cart=TRUE][, 
  .(LatestScore = last(Score)), by=.(Date = Date.1, Name)]

setorder(ranks, Date, -LatestScore)
ranks[, r := rowid(Date)]

df[ranks, on=.(Name, Date), r := i.r]

   Name Score       Date Rank r
1: John    42 2018-01-01    3 3
2:  Rob    85 2017-12-31    2 2
3:  Rob    89 2017-12-26    1 1
4:  Rob    57 2017-12-24    1 1
5:  Rob    53 2017-08-31    1 1
6:  Rob    72 2017-05-31    2 2
7: Kate    87 2017-12-25    1 1
8: Kate    73 2017-05-15    1 1
Run Code Online (Sandbox Code Playgroud)

...使用,last因为笛卡尔连接似乎排序,我们想要最新的测量.

更新加入的工作原理

i.前缀意味着它是从列ix[i, ...]加入,并指派:=总是在x.所以它正在查找iin的每一行x和找到匹配的位置,将值复制ix.

另一种有时有用的方法是查找xi,例如df[, r := ranks[df, on=.(Name,Date), x.r]]在某种情况下x.r仍然来自ranks表(现在位于x相对于连接的位置).


还有......

ranks = df[CJ(Name = Name, Date = Date, unique=TRUE), on=.(Name, Date), roll=30, nomatch=0]
setnames(ranks, "Score", "LatestScore")

# and then use the same last three lines above    
Run Code Online (Sandbox Code Playgroud)

我不确定一个与另一个的效率,但我想这取决于名称的数量,测量的频率以及测量天数重合的频率.

  • 即将发布像`df [,rank:= df [.(iName = Name,iDate1 = Date - 30,iDate2 = Date),on =.(Date> = iDate1,Date <= iDate2),by = .EACHI,.SD [order(x.Date),. SD [.N],by = Name] [,frank(-Score)[Name == iName]]] $ V1] []`按'.EACHI分组`但你的更简洁. (2认同)