Как выполнить RMSE с отсутствующими значениями?

У меня есть огромный набор данных с 679 строками и 16 столбцами с 30% пропущенных значений. Поэтому я решил оспаривать эти недостающие значения функцией impute.knn из пакета impute, и я получил набор данных с 679 строками и 16 столбцами, но без отсутствующих значений.

Но теперь я хочу проверить точность с помощью RMSE, и я попробовал 2 варианта:

  • загрузите пакет hydroGOF и примените функцию rmse
  • sqrt(mean (obs-sim)^2), na.rm=TRUE)

В двух ситуациях у меня есть ошибка: errors in sim .obs: non numeric argument to binary operator.

Это происходит потому, что исходный набор данных содержит значение NA (некоторые значения отсутствуют).

Как я могу вычислить RMSE, если я удалю отсутствующие значения? Тогда obs и sim будут иметь разные размеры.

Ответ 1

Как насчет просто...

sqrt( sum( (df$model - df$measure)^2 , na.rm = TRUE ) / nrow(df) )

Очевидно, что ваш файловый фрейм называется df, и вам нужно принять решение о N (т.е. nrow(df) содержит две строки с отсутствующими данными, вы хотите исключить их из N? Я бы предположил, да, поэтому вместо nrow(df) вы, вероятно, захотите использовать sum( !is.na(df$measure) )) или, следуя @Joshua просто

sqrt( mean( (df$model-df$measure)^2 , na.rm = TRUE ) )

Ответ 2

Функция rmse() в пакете R hydroGOF имеет параметр NA-remove:

# require(hydroGOF)
rmse(sim, obs, na.rm=TRUE, ...)

который, согласно документации, ожидает, когда na.rm имеет значение TRUE:

"Когда значение NA находится на i-й позиции в obs OR sim, i-е значение из obs AND sim удаляются перед вычислением. "

Без минимального воспроизводимого примера трудно сказать, почему это не сработало для вас.

Если вы хотите исключить недостающие значения перед вводом в функцию hydroGOF:: rmse(), вы можете сделать:

my.rmse <- rmse(df.sim[rownames(df.obs[!is.na(df.obs$col_with_missing_data),]),]
     , df.obs[!is.na(df.obs$col_with_missing_data),])

предполагая, что у вас есть "имитированные" (вмененные) и "наблюдаемые" (оригинальные) наборы данных в разных кадрах данных с именем df.sim и df.obs, соответственно, которые были созданы из одного и того же исходного фрейма данных, поэтому имеют одинаковые размеры и имена строк.

Вот канонический способ сделать то же самое, если у вас более одного столбца с отсутствующими данными:

rows.wout.missing.values <- with(df.obs, rownames(df.obs[!is.na(col_with_missing_data1) & !is.na(col_with_missing_data2) & !is.na(col_with_missing_data3),]))
my.rmse <- rmse(df.sim[rows.wout.missing.values,], df.obs[rows.wout.missing.values,])

Ответ 3

Вычисление RMSE в R даже с отсутствующими значениями:

Математические обозначения:

введите описание изображения здесь

Интуиция:

RMSE отвечает на вопрос: "Насколько похожи в среднем числа в списке d и список p"? Эти два списка должны иметь одинаковую длину. RMSE дает вам одно число, которое показывает, как далеко элементы d из элементов p.

Пример кода:

#    Element 1 has zero error
#       |     Element 2 small error
#       |      |     Element 3, large error
#       |      |     |      Has one missing value
#       |      |     |      |     Two missing values
#       v      v     v      v     v
#       
d = c(0.000, 0.166, 0.333, NA,   NA)
p = c(0.000, 0.254, 0.998, 0.31, NA)

rmse = function(predictions, targets){

    #Option 1 to handle missing values (preferred)
    #Wipe out both elements when either side has a 
    #missing value.  This is dangerous because if
    #you've got a lot of NA's, then the remaining
    #elements will have more influence:

    predictions[is.na(targets)]     <- 0
    targets[is.na(targets)]         <- 0
    targets[is.na(predictions)]     <- 0
    predictions[is.na(predictions)] <- 0 

    #alternatively you could just set the NA to some
    #default value, but this is dangerous since it 
    #injects a constant bias into the equation proportional
    #to how many NA are replaced.

    #predictions[is.na(predictions)]     <- 0
    #targets[is.na(targets)]             <- 0

    return(sqrt(mean(((targets - predictions) ** 2))))
}

rmse_val = rmse(d, p)
print("rms error is: ")
print(rmse_val)

Отпечатки:

[1] "rms error is: "
[1] 0.387285

Для большей интуиции о том, как и почему это работает:

См. мой другой канонический ответ на RMSE, написанный на Python: fooobar.com/info/101114/...