Вменить недостающие значения в данные частичного ранга?

#r #rank #imputation

Вопрос:

У меня есть некоторые данные о рангах с пропущенными значениями. Элементу с наивысшим рейтингом было присвоено значение «1». Значения » NA » возникают, когда элемент не был ранжирован.

 # sample data
df <- data.frame(Item1 = c(1,2, NA, 2, 3), Item2 = c(3,1,NA, NA, 1), Item3 = c(2,NA, 1, 1, 2))

> df
  Item1 Item2 Item3
1     1     3     2
2     2     1    NA
3    NA    NA     1
4     2    NA     1
5     3     1     2
 

Я хотел бы случайным образом сопоставить значения » NA » в каждой строке с соответствующими значениями без рангов. Одним из решений, которое соответствовало бы моей цели, было бы следующее:

 > solution1
  Item1 Item2 Item3
1     1     3     2
2     2     1     3
3     3     2     1
4     2     3     1
5     3     1     2
 

Этот код содержит список возможных значений замены для каждой строки.

 # set max possible rank in data
max_val <- 3 

# calculate row max
df$row_max <- apply(df, 1, max, na.rm= T) 

# calculate number of missing values in each row
df$num_na <- max_val - df$row_max 

# set a sample vector
samp_vec <- 1:max_val # set a sample vector

# set an empty list
replacements <- vector(mode = "list", length = nrow(df))
 
# generate a list of replacements for each row
for(i in 1:nrow(df)){
  
  if(df$num_na[i] > 0){
    replacements[[i]] <- sample(samp_vec[samp_vec > df$row_max[i] ], df$num_na[i])
  } else {
    replacements[[i]] <- NULL
  }
  
}
 

Теперь ломаю голову над тем, как я могу присвоить значения в моем списке отсутствующим значениям в каждой строке моего data.frame. (Мои фактические данные содержат 1000 строк.)

Есть ли чистый способ сделать это?

Ответ №1:

Базовый вариант R с использованием apply

 set.seed(123)

df[] <- t(apply(df, 1, function(x) {
  #Get values which are not present in the row
  val <- setdiff(seq_along(x), x)
  #If only 1 missing value replace with the one which is not missing
  if(length(val) == 1) x[is.na(x)] <- val
  #If more than 1 missing replace randomly
  else if(length(val) > 1) x[is.na(x)] <- sample(val)
  #If no missing replace the row as it is
  x
}))
df

#  Item1 Item2 Item3
#1     1     3     2
#2     2     1     3
#3     2     3     1
#4     2     3     1
#5     3     1     2