Подтвердить что ты не робот

Являются ли факторы более эффективными в таблицах данных, чем символы?

Я, хотя я где-то читал (не могу вспомнить, где), что факторы не были на самом деле более эффективными, чем символьные векторы в data.table. Это правда? Я обсуждал, продолжать ли использовать факторы для хранения различных векторов в data.table. Примерный тест с object.size, как представляется, указывает на другое.

chars <- data.table(a = sample(letters, 1e5, TRUE))           # chars (not really)
string <- data.table(a = sample(state.name, 1e5, TRUE))       # strings
fact <- data.table(a = factor(sample(letters, 1e5, TRUE)))    # factor
int <- data.table(a = sample(1:26, 1e5, TRUE))                # int

mbs <- function(...) {
    ns <- sapply(match.call(expand.dots=TRUE)[-1L], deparse)
    vals <- mget(ns, .GlobalEnv)
    cat('Sizes:\n',
        paste('\t', ns, ':', round(sapply(vals, object.size)/1024/1024, 3), 'MB\n'))
}

## Get approximate sizes?
mbs(chars, string, fact, int)
# Sizes:
#    chars : 0.765 MB
#    string : 0.766 MB
#    fact : 0.384 MB
#    int : 0.382 MB
4b9b3361

Ответ 1

Возможно, вы помните data.table FAQ 2.17, который содержит:

stringsAsFactors по умолчанию TRUE в data.frame, но FALSE в data.table, для эффективности. Поскольку к R добавлен глобальный кеш строк, элементы символов являются указателями на одну кешированную строку, и больше нет преимущества для преобразования в коэффициент.

(Эта часть была добавлена ​​в FAQ в v1.8.2 в июле 2012 года.)

Использование символа, а не фактора помогает в таких задачах, как укладка (rbindlist). Так как a c() двух символьных векторов - это просто конкатенация, тогда как a c() двух столбцов факторов необходимо пересечь и объединить два уровня факторов, которые сложнее кодировать и выполнять больше времени.

Что вы заметили, это разница в потреблении ОЗУ на 64-битных машинах. Факторы хранятся в виде векторного поиска integer элементов на уровнях. Тип integer - 32 бит, даже на 64-битных платформах. Но указатели (какой вектор character) являются 64-битными на 64-битных машинах. Таким образом, столбец символов будет использовать вдвое больше оперативной памяти, чем столбцы факторов на 64-битной машине. Нет разницы на 32 бит. Однако обычно эта стоимость будет перевешиваться более быстрыми и более быстрыми инструкциями по символьному вектору. [Кроме того, поскольку факторы integer, они не могут содержать более 2 миллиардов уникальных строк. Столбцы character не имеют этого ограничения.]

Это зависит от того, что вы делаете, но операции оптимизированы для character в data.table и так, что мы советуем. В основном это экономит прыжок (до уровней), и мы можем сравнивать два столбца символов в разных таблицах, просто сравнивая значения указателя без скачкообразного перехода даже в глобальный кеш.

Это зависит от мощности столбца. Скажем, столбец составляет 1 миллион строк и содержит 1 миллион уникальных строк. Для хранения в качестве фактора потребуется 1 миллион векторных символов для уровней плюс 1 миллион целых векторов, указывающих на элементы уровня. Это (4 + 8) * 1e6 байт. С другой стороны, для символьного вектора не нужны уровни, а всего 8 * 1e6 байт. В обоих случаях глобальный кеш хранит 1 миллион уникальных строк таким же образом, чтобы это происходило в любом случае. В этом случае столбец символов будет использовать меньше ОЗУ, чем если бы он был фактором. Будьте осторожны, чтобы проверить, что инструмент памяти, используемый для вычисления использования ОЗУ, вычисляет это соответствующим образом.