3

我有一个数据集,我需要在其中评估具有相同 id 代码的多个条目,如果满足一组条件,则在最后一行中拆分一个单元格值。

条件 = 该 id 的最后一行具有 action=="l" & time >60。

如果满足此条件,我想更改行操作 <- “e”,并且时间 <- 60。超过 60 的时间量应放在下面新形成的行中。新行的列内容应与父行相同,除了 action=="l" & time==original value - 60)。

样本数据集

id <- c("12_1","12_1","12_1","12_2","12_2","12_2")
action <- c("l","d","l","l","d","l")
time <- c(15,45,90,20,30,61)
dtfrm <-data.frame(cbind(id,action,time))

测试数据框

    id action time
1 12_1      l   15
2 12_1      d   45
3 12_1      l   90
4 12_2      l   20
5 12_2      d   30
6 12_2      l   61

我希望转换后的数据框看起来像这样

    id action time
1 12_1      l   15
2 12_1      d   45
3 12_1      e   60
4 12_1      l   30
5 12_2      l   20
6 12_2      d   30
7 12_2      e   60
8 12_2      l    1

最终,我将有更复杂的条件来评估,但我试图从简单的开始,逐步提高将这个数据集调整为工作顺序所需的更复杂的条件。谢谢。

4

2 回答 2

3

我会编写一个对一组“id”进行操作的函数:

process.one <- function(df) {
  n <- nrow(df)
  last.action <- df$action[n]
  last.time   <- df$time[n]
  if (last.action == "l" & last.time > 60) {
    next.row <- df[n, ]
    next.row$action = "l"
    next.row$time   = last.time - 60
    df <- rbind(df, next.row)
    df$action[n] <- "e"
    df$time[n]   <- 60
  }
  df
}

然后使用分割/应用/组合plyr

ddply(dtfrm, "id", process.one)
#     id action time
# 1 12_1      l   15
# 2 12_1      d   45
# 3 12_1      e   60
# 4 12_1      l   30
# 5 12_2      l   20
# 6 12_2      d   30
# 7 12_2      e   60
# 8 12_2      l    1

还要确保您的 data.frame 没有因素,否则附加到它可能会出现问题。在顶部,它应该是:

dtfrm <- data.frame(id, action, time, stringsAsFactors = FALSE)
于 2013-04-01T22:35:30.677 回答
2

这有点涉及,但应该这样做:

# fix the time column, it should be numeric
dtfrm[, "time"] <- as.numeric(as.character(dtfrm[, "time"]))

library(data.table)
DT <- data.table(cbind(dtfrm, rowid=seq(nrow(dtfrm))), key="id")

# identify which rows need modification
DT[, needsMod := FALSE]
DT[unique(DT[, "id", with=FALSE])
   ,  needsMod := {L <- length(action); (action[L] == "l" && time[L] > 60)  }
   , by=id
   , mult="last"]

# append new rows
DT <- setkey(rbind(DT, 
       DT[c(needsMod), list(id, action, time=time-60, rowid=rowid+1e-2, needsMod=!needsMod)]), 
       id, rowid)

# modify the identified rows
DT[c(needsMod), c("action", "time") := list("e", 60)]

# optionally remove added columns, though personally, I would keep some form of rowid
DT[ , c("needsMod", "rowid") := NULL]
DT

#      id action time
# 1: 12_1      l   15
# 2: 12_1      d   45
# 3: 12_1      e   60
# 4: 12_1      l   30
# 5: 12_2      l   20
# 6: 12_2      d   30
# 7: 12_2      e   60
# 8: 12_2      l    1
于 2013-04-01T22:46:04.123 回答