Неожиданное поведение таблицы функций со значениями "NaN"

Недавно я столкнулся с поведением в функции table, которая не была тем, что я ожидал:

Например, возьмем следующий вектор:

ex_vec <- c("Non", "Non", "Nan", "Oui", "NaN", NA)

Если я проверяю значения NA в моем векторе, "NaN" не считается одним (как ожидалось):

is.na(ex_vec)
# [1] FALSE FALSE FALSE FALSE FALSE  TRUE

Но если я попытался получить разные значения частот:

table(ex_vec)
#ex_vec
#Nan Non Oui 
#  1   2   1

"NaN" не отображается в таблице.

Однако, если я "спрошу" table, чтобы показать значения NA, я получаю следующее:

table(ex_vec, useNA="ifany")
#ex_vec
# Nan  NaN  Non  Oui <NA> 
#   1    1    2    1    1

Итак, символьные строки "NaN" рассматриваются как значение NA внутри вызова table, а обрабатываются в выводе как значение не NA.

Я знаю (было бы лучше и) я мог бы решить свою проблему, преобразовывая свой вектор в factor, но, тем не менее, мне бы очень хотелось узнать, что происходит здесь. У кого-нибудь есть идея?

Ответы

Ответ 1

Когда factor соответствует уровням для вектора, он преобразует свой список exclude в тот же тип, что и входной вектор:

exclude <- as.vector(exclude, typeof(x))

поэтому, если ваш список исключений имеет NaN, и ваш вектор является символом, это происходит:

as.vector(exclude, typeof(letters))
[1] NA    "NaN"

Боже мой. Теперь будут исключены реальные строки "NaN".

Чтобы исправить, используйте exclude=NA в tablefactor, если вы делаете факторы, которые могут повлиять на это).

Мне нравится это в документах для factor:

 There are some anomalies associated with factors that have ‘NA’ as
 a level.  It is suggested to use them sparingly, e.g., only for
 tabulation purposes.

Успокаивает...

Ответ 2

Первой идеей, на мой взгляд, было взглянуть на определение table, которое начинается с:

> table
function (..., exclude = if (useNA == "no") c(NA, NaN), useNA = c("no", 
    "ifany", "always"), dnn = list.names(...), deparse.level = 1) 
{

Звучит логично, по умолчанию таблица исключает NA и NaN.

Копаем в код таблицы, мы видим, что если x не является фактором, он принуждает его к фактору (ничего нового здесь, он сказал в документе).

    else {
        a <- factor(a, exclude = exclude)

Я не нашел ничего другого, что могло повлиять на вход для принудительного вложения "NaN" в значения NA.

Итак, посмотрим на фактор, чтобы понять причину:

> factor
function (x = character(), levels, labels = levels, exclude = NA, 
    ordered = is.ordered(x), nmax = NA) 
{
 [...] # Snipped for brievety
    exclude <- as.vector(exclude, typeof(x))
    x <- as.character(x)
    levels <- levels[is.na(match(levels, exclude))] # defined in the snipped part above, is the sorted unique values of input vector, coerced to char.
    f <- match(x, levels)
 [...]
    f
}

Здесь мы получили его, параметр exclude, даже будучи NA значениями, принуждаются к символьному вектору.

Итак, что происходит:

> ex_vec <- c("Non", "Non", "Nan", "Oui", "NaN", NA)
> excludes<-c(NA,NaN)
> as.vector(excludes,"character")
[1] NA    "NaN"
> match(ex_vec,as.vector(excludes,"character"))
[1] NA NA NA NA  2  1

Мы сопоставляем символ "NaN" как вектор исключения, который был принужден к символу перед сравнением.