Суммирование или подстановка на основе условий - PullRequest
1 голос
/ 27 сентября 2019

У меня есть проблема с кодированием, и я не знаю, как это сделать.

Мой набор данных выглядит примерно так

df <- data.frame("id" = c("id1", "id1", "id1", "id1", "id2", "id2","id2","id2"), 
                 "time" = c(1,2,4,5,2,3,4,6),
                 "Treatmentid" = c("1", "2", "1a","3", "1", "4","4a","3"), 
                 "Val" = c(2,3,5,1,2,7,4,1))

Где «id» указывает на предмет, «Treatmentid» указывает на лечение, которое получает субъект, а «Val» - это значение лечения.

Как правило, лечение является постоянным во времени, поэтому я хотел бы суммировать их для каждого человека, чтобы рассчитать общее лечение, которое он получает в каждый момент времени.

Проблема заключается в том, что некоторые виды леченияобозначенные «а», фактически заменяют, а не добавляют к обработке без а.

Следовательно, я бы хотел, чтобы мой окончательный набор данных выглядел примерно так

final <- data.frame("id" = c("id1", "id1", "id1", "id1", "id2", "id2","id2","id2"), 
                 "time" = c(1,2,4,5,2,3,4,6),
                 "Treatmentid" = c("1", "2", "1a","3", "1", "4","4a","3"), 
                 "Val" = c(2,3,5,1,2,7,4,1),
                 "totVal" = c(2,5,8,9,2,9,6,7))

.значения суммируются для разных «Treatementid» (то есть для id1 в момент времени 2, totVal = 2 + 3 = 5).В то время как они заменяются, когда в обработку вносятся изменения (т.е. для id1 в момент времени 4, totVal = 5 + 3 = 8).Здесь значение «Treatmentid 1a» (5) заменило значение «Treatmentid 1» (2).

Надеюсь, это понятно.

Благодарю всех вас заранее заваша помощь

1 Ответ

1 голос
/ 27 сентября 2019

Это моя логика того, как добиться того, чего ты хочешь.Это довольно запутанно и может занять много времени на больших наборах данных.Если кто-то может улучшить мое решение, я с радостью обязуюсь.

library(dplyr) # for bind_rows function

Сначала мы разбиваем кадр данных на две группы по группам id в первом столбце.Это дает список двух фреймов данных.Затем мы собираемся перебрать этот список, чтобы получить суммы.

mylist <- split(df, f = df$id)

Далее мы инициируем переменные, необходимые в цикле for.Нам нужен список для отслеживания исходных идентификаторов, и нам нужен список для отслеживания суммы.Нам также нужен индексатор для извлечения значений, и нам нужен другой индексатор для списка фреймов данных, которые x и df_num соответственно.

ids <- list()
vals <- list()

x <- 1

df_num <- 1

В приведенном ниже коде вложенный цикл forиспользуется для расчета скользящей суммы Treatmentid.Цикл проходит через каждый элемент в mylist, затем есть вложенный цикл для прохождения каждого значения в столбце Treatmentid.

Для первой строки сумма равна значению.Поэтому здесь используется тест if, чтобы проверить, равна ли текущая итерация цикла for первому значению в столбце Treatmentid.Если это так, то первая сумма просто равна первому значению в my_df$Val.Затем идентификатор сохраняется, индексаторы for увеличиваются и цикл for переходит к следующей итерации.

После этого я использую grepl, чтобы проверить, не содержит ли значение в Treatmentid букву.Если тест оценивается как TRUE, то это означает, что в нем нет «а», следовательно, нет замены.Поэтому сумма продолжается как обычно.Если это FALSE, то в нем есть «а» и, следовательно, это замена.Часть 'a' удаляется, оставляя только номер, а затем мы ищем в списке идентификаторов, где число равно номеру идентификатора, получаем индекс и сохраняем его в a.Это будет индекс строки со значением для замены в исходных данных.Мы вычитаем это и добавляем значение подстановки.

Наконец, за пределами внутреннего цикла мы выводим значения в новый столбец с именем totval.Затем этот фрейм данных сохраняется в mylist.

for (my_df in mylist) {

  x <- 1

  for (j in my_df$Treatmentid) {

    if (j == my_df$Treatmentid[1]) {
      vals[[1]] <- my_df$Val[1]
      ids[[x]] <- j
      x <- x + 1
      next
    }
      if (grepl("^[[:digit:]]+$",j)==TRUE) {

      ids[[x]] <- j

      vals[[x]] <- vals[[x-1]] + my_df$Val[x]
      x <- x + 1

    } else {

      a <- which(sapply(ids, function(y) substr(j, 1, nchar(j)-1) %in% y))
      vals[[x]] <- vals[[x-1]] - my_df$Val[a] + my_df$Val[x]
      x <- x + 1

    }
  }

  my_df$totVal <- unlist(vals)
  mylist[[df_num]] <- my_df
  df_num <- df_num + 1
  }

После завершения цикла преобразуйте список фреймов данных в полный фрейм данных с помощью bind_rows() из dplyr.

Final <- bind_rows(mylist)

Я сохранил ваш желаемый вывод в final, и я проверяю, равен ли созданный в цикле кадр данных тому, что вы хотите, используя identical(), и результат равен TRUE.

identical(Final, final)
[1] TRUE
...