Применить соответствие и заменить функцию по ряду строк в кадре данных в порядке

Запуск файла данных

data_start <- data.frame(marker = c("yes","yes","no","yes","no"),
                         id_out = c(5,3,1,1,7), 
                         id_new = c(6,8,9,4,2))

> data_start
  marker id_out id_new
1    yes      5      6
2    yes      3      8
3     no      1      9
4    yes      1      4
5     no      7      2

Добавьте три заголовка столбца с пустыми столбцами ниже. Прикрепите начальные значения var1:var3.

data_start[,c("var1", "var2", "var3")] <- NA
vars <- c(5,3,1)
data_start[1, 4:6] <- vars

> data_start
  marker id_out id_new var1 var2 var3
1    yes      5      6    5    3    1
2    yes      3      8   NA   NA   NA
3     no      1      9   NA   NA   NA
4    yes      1      4   NA   NA   NA
5     no      7      2   NA   NA   NA

Я хотел бы обновить столбцы var1:var3, применив функцию к каждой строке, где IF marker= yes AND id_out соответствует ЛЮБОЙ из var1:var3, замените любой из var1:var3 на id_new. Я нашел это решение, но работает для одной строки кода и по-прежнему требует обновления каждой новой var1:var3 части строки.

data_start[1, 4:6][data_start[1, 4:6] == data_start[1,"id_out"]] <- data_start[1,"id_new"]

Каждая строка также зависит от использования значений из указанной строки, прежде чем снова применить эту функцию.

Окончательный результат будет выглядеть так, когда строки остаются неизменными, когда маркер = no и каждая строка впоследствии обновляется.

> data_final
  marker id_out id_new var1 var2 var3
1    yes      5      6    6    3    1
2    yes      3      8    6    8    1
3     no      1      9    6    8    1
4    yes      1      4    6    8    4
5     no      7      2    6    8    4

Ответ 1

Это можно использовать с любым количеством столбцов и работает с базой R:

cols <- c("var1", "var2", "var3")

for(j in 1:length(cols)) {
  var <- cols[j]
  for(i in 1:nrow(data_start)){
    if(i > 1) {
      data_start[i, var] <- data_start[i-1, var]
    }
    if(data_start[i, "marker"] == "yes" & data_start[i, var] == data_start[i,"id_out"]) {
      data_start[i,var] <- data_start[i, "id_new"]
    } 
  }
}

Ответ 2

Это очень грубо, потому что я должен работать, но это должно работать.

data_start <- data.frame(marker = c("yes","yes","no","yes","no"),
                         id_out = c(5,3,1,1,7), 
                         id_new = c(6,8,9,4,2))

data_start[,c("var1", "var2", "var3")] <- NA
vars <- c(5,3,1)
data_start[1, 4:6] <- vars

onVars <- c("var1", "var2", "var3")

for (i in 2:nrow(data_start)) {

  print(i)

  for (var in onVars) {

    if (data_start$marker[i] == "yes" & data_start$id_out[i] == data_start[i - 1, var]) {

      data_start[i, var] <- data_start$id_new[i]

    } else {

      data_start[i, var] <- data_start[i - 1, var]

    }

  }

}

data_start - ваш выход.

Упс, похоже, я, возможно, не оценил первую строку, но надеюсь, что теперь вы сможете справиться с этим самим.

Ответ 3

Вот фрагмент, который позволит вам выполнить этот расчет, даже если у вас более трех столбцов:

library(data.table)
dt <- data.table(marker = c("yes","yes","no","yes","no"),
                         id_out = c(5,3,1,1,7), 
                         id_new = c(6,8,9,4,2))

dt[, change := cumsum(marker == "yes")]

ref.new <- dt[marker == "yes", id_new] # Reference to values where marker is "yes"
ref.out <- dt[marker == "yes", id_out]
for (x in 1:length(ref.new)) {
  dt[, paste("var", x, sep="") := ifelse(change >= x, ref.new[x] , ref.out[x])]
}
head(dt)
#     marker id_out id_new change var1 var2 var3
#1:    yes      5      6      1    6    3    1
#2:    yes      3      8      2    6    8    1
#3:     no      1      9      2    6    8    1
#4:    yes      1      4      3    6    8    4
#5:     no      7      2      3    6    8    4

Ответ 4

Кажется, трудно найти решение без цикла, и если, так оно и есть. Я попытался изменить исходные значения на другой набор, например c(1,3,1), и коды работают нормально. Мы также можем добавить столбцы переменных, если это необходимо.

# Re-create the data
dt <- data.table(marker = c("yes","yes","no","yes","no"),
                 id_out = c(5,3,1,1,7),
                 id_new = c(6,8,9,4,2))
var.col <- paste0("var", 1:3)
dt[1, (var.col) := .(5,3,1)]

# Processing
for(i in 1:nrow(dt)) {
  if(i > 1) dt[i, (var.col) := as.list(dt[i-1, var.col, with = F])]
  var.i <- dt[i, var.col, with = F] %in% dt[i, id_out]
  if(dt[i]$marker == 'yes' & sum(var.i) != 0) {
    dt[i, (var.col[var.i]) := dt[i, id_new]]
  }
}