Разделете стойност в клетка и добавете към новосъздадения ред в R

Имам набор от данни, където трябва да оценя множество записи с един и същ идентификационен код и да разделя стойност на клетка в последния ред, ако е изпълнен набор от условни условия.

Condtionals = последният ред за този идентификатор има action=="l" & време >60.

Ако това условие е изпълнено, бих искал да променя действието на реда ‹- „e“ и времето ‹- 60. Времето, надвишаващо 60, трябва да бъде поставено в новоформиран ред по-долу. Съдържанието на колоната за новия ред трябва да е идентично с това на родителския ред, с изключение на action=="l" & time==оригинална стойност - 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

В крайна сметка ще имам по-сложни условни условия за оценка, но се опитвам да започна с прости и да си проправя път към по-сложните условни условия, необходими за масажиране на този набор от данни в работен ред. Благодаря.


person marcellt    schedule 01.04.2013    source източник


Отговори (2)


Бих написал функция, която работи с една група "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)
person flodel    schedule 01.04.2013
comment
Благодаря за отговора. Моята реална рамка с данни има 46 колони. Има ли начин да копирам всички стойности от предишния ред и да променя само действието и времето или ще трябва да добавя тези допълнителни имена на колони и как искам да бъдат попълнени във формулата? - person marcellt; 02.04.2013
comment
благодаря, че работиш по този въпрос. Мислех, че с това начало мога да модифицирам отговора ви и да работя в моите допълнителни условия, но имам някои проблеми. Сега трябва да оценя реда по-горе и да модифицирам само ако този ред action==d. Мислех, че мога да създам previous.action ‹- df$action_time[n-1] и да добавя друг & previous.action == d към условието, но не работи. Съвети? - person marcellt; 02.04.2013
comment
Както казахте, но трябва да е previous.action <- df$action[n-1]. Това също предполага, че всяка група има поне два реда, ако не е така, ще трябва да проверите това n > 1. - person flodel; 02.04.2013
comment
n се равнява на 1 в повече от няколко случая, трябва ли това да не се оценява на NA, поради което все още позволява функцията да се изпълнява, когато previous.action==NA? - person marcellt; 02.04.2013

Малко е намесено, но това трябва да го направи:

# 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
person Ricardo Saporta    schedule 01.04.2013