逐行跟踪完整级别更改

gib*_*z00 4 r zoo dplyr data.table

这就是我的数据框架的样子.最右边的列("FullCycle")是我想要的列.对于给定的名称和在给定的时间点,我想看到一个人的整个水平变化周期.

 library(data.table)
     dt <- fread('
        Name      Level     Date         RecentLevelChange  FullCycle
        John       1       2016-01-01       NA                1
        John       1       2016-01-10       NA                1
        John       2       2016-01-17       1->2              1->2
        John       2       2016-01-18       NA                1->2
        John       3       2016-01-19       2->3              1->2->3
        John       4       2016-01-20       3->4              1->2->3->4
        John       4       2016-01-21       NA                1->2->3->4
        John       7       2016-01-22       4->7              1->2->3->4->7
        Tom        1       2016-01-10       NA                1
        Tom        2       2016-01-17       1->2              1->2
        Tom        2       2016-01-18       NA                1->2
        Tom        3       2016-01-19       2->3              1->2->3
        Tom        4       2016-01-20       3->4              1->2->3->4
        Tom        4       2016-01-21       NA                1->2->3->4
        Tom        7       2016-01-22       4->7              1->2->3->4->7
  ')
Run Code Online (Sandbox Code Playgroud)

我通过尝试创建了"RecentLevelChange"字段

require(dplyr)
dt[,RecentLevelChange := 
as.character(ifelse(lag(Level)==Level  ,NA,
paste(lag(Level),Level,sep="->"))),by=Name]
Run Code Online (Sandbox Code Playgroud)

但我不知道如何创建"FullCycle"专栏.我衷心感谢你的帮助.

MrF*_*ick 5

这是一个计算路径的辅助函数

paths <- function(x) {
    sapply(Reduce(function(prev, cur) 
        unique(c(prev,cur)), x, accumulate=T), 
        function(x) paste(x, collapse="->")
    )
 }
Run Code Online (Sandbox Code Playgroud)

使用use Reduce()来构建直到给定点的唯一级别列表.(这假设行已正确排序).然后我们可以将此功能应用于每个人

dt[,path:=paths(Level), by="Name"]
Run Code Online (Sandbox Code Playgroud)

这产生了

    Name Level       Date RecentLevelChange          path
 1: John     1 2016-01-01                NA             1
 2: John     1 2016-01-10                NA             1
 3: John     2 2016-01-17              1->2          1->2
 4: John     2 2016-01-18                NA          1->2
 5: John     3 2016-01-19              2->3       1->2->3
 6: John     4 2016-01-20              3->4    1->2->3->4
 7: John     4 2016-01-21                NA    1->2->3->4
 8: John     7 2016-01-22              4->7 1->2->3->4->7
 9:  Tom     1 2016-01-10                NA             1
10:  Tom     2 2016-01-17              1->2          1->2
11:  Tom     2 2016-01-18                NA          1->2
12:  Tom     3 2016-01-19              2->3       1->2->3
13:  Tom     4 2016-01-20              3->4    1->2->3->4
14:  Tom     4 2016-01-21                NA    1->2->3->4
15:  Tom     7 2016-01-22              4->7 1->2->3->4->7
Run Code Online (Sandbox Code Playgroud)

如果你想跟踪用户是否回到以前的水平,你可以使用类似的东西

paths <- function(x) {
    sapply(Reduce(function(prev, cur) 
        rle(c(prev,cur))$values, x, accumulate=T), 
        function(x) paste(x, collapse="->")
    )
 }
Run Code Online (Sandbox Code Playgroud)

例如

paths(c(1,2,3,2,1))
# [1] "1"             "1->2"          "1->2->3"       "1->2->3->2"   
# [5] "1->2->3->2->1"
Run Code Online (Sandbox Code Playgroud)

  • 我认为`dt [,path:= {r = within.list(rle(Level),{values = Reduce(function(x,y)paste(x,y,sep =" - >"),values,accumulate =是的)}); inverse.rle(r)},by = Name]`是最干净的方式,但不会作为一个单独的答案发布,因为我认为它与这一个基本相同.随意添加它. (3认同)
  • rle的替代:`Reduce(function(x,y)c(x,if(y!= tail(x,1))y),Level,accumulate = TRUE) (2认同)