在一定条件下提取最近的条目

Max*_*den 6 indexing split r plyr data.table

我正在努力完成以下工作:

示例数据集:

   belongID   uniqID   Time   Rating  
   1           101       5      0  
   1           102       4      0  
   2           103       4      0  
   2           104       3      0  
   2           105       2      5
   3           106       4      2  
   3           107       5      0  
   3           108       5      1 
Run Code Online (Sandbox Code Playgroud)

问题是:我想提取每个belongsID的最新条目(时间的最大值),除非此评级为0.如果最近条目的评级为0.我希望第一个条目具有评级(不是最高评级,只是第一个评级不为零的值).如果所有其他条目也为零,则需要选择最新的条目.

最终结果应该是:

   belongID   uniqID   Time   Rating  
   1           101       5      0  
   2           105       2      5
   3           108       5      1  
Run Code Online (Sandbox Code Playgroud)

数据集非常大,按belongsID排序.它不是按时间排序的,因此更新的条目可能会在具有相同belongsID的旧条目之后出现.

如果没有"0 Rating"约束,我使用以下函数来计算最近的条目:

>uniqueMax <- function(m, belongID = 1, time = 3) {
    t(
      vapply(
         split(1:nrow(m), m[,belongID]), 
         function(i, x, time) x[i, , drop=FALSE][which.max(x[i,time]),], m[1,], x=m, time=time
      )
    )
 }
Run Code Online (Sandbox Code Playgroud)

我不知道如何纳入"0评级"约束.

编辑:后续问题:

有没有人知道getRating如果不仅评估零,应该如何改变功能,但需要考虑更多的评级(例如0,1,4和5)?因此,除非评级为0或1或4或5,否则分配给最近的?如果评级为0,1,4,5,则分配给具有不同评级的最近一个条目.如果所有等级都是0,1,4或5分配给最近的那些.我尝试了以下,但这不起作用:

getRating <- function(x){
  iszero <- x$Rating == 0 | x$Rating == 1 | x$Rating == 4 | x$Rating ==5
  if(all(iszero)){
    id <- which.max(x$Time)
  } else {
    id <- which.max((!iszero)*x$Time) 
            # This trick guarantees taking 0 into account
  }
  x[id,]
}
# Do this over the complete data frame
do.call(rbind,lapply(split(Data,Data$belongID),getRating)) 
     # edited per Tyler's suggestion'
Run Code Online (Sandbox Code Playgroud)

Pet*_*ine 3

这是一个使用 data.table 的解决方案,可以轻松过滤并getRecentRow为每个 单独执行我的功能belongID

library(data.table)

# Load the data from the example.
dat = structure(list(belongID = c(1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), 
          uniqID = 101:108, Time = c(5L, 4L, 4L, 3L, 2L, 4L, 5L, 5L),
          Rating = c(0L, 0L, 0L, 0L, 5L, 2L, 0L, 1L)), 
          .Names = c("belongID", "uniqID", "Time", "Rating"),
          row.names = c(NA, -8L), class = c("data.table", "data.frame"))

dat = data.table(dat) # Convert to data table.

# Function to get the row for a given belongID
getRecentRow <- function(data) {
    # Filter by Rating, then order by time, then select first.
    row = data[Rating != 0][order(-Time)][1]

    if(!is.na(row$uniqID)) {
        # A row was found with Rating != 0, return it.
        return(row)
     } else {
          # The row was blank, so filter again without restricting. rating.
          return(data[order(-Time)][1])
        }  
}

# Run getRecentRow on each chunk of dat with a given belongID
result = dat[,getRecentRow(.SD), by=belongID]

     belongID uniqID Time Rating
[1,]        1    101    5      0
[2,]        2    105    2      5
[3,]        3    108    5      1
Run Code Online (Sandbox Code Playgroud)