Возможно ли иметь меньший набор данных, чем при использовании факторов? - PullRequest
0 голосов
/ 07 декабря 2018

Я пытаюсь уменьшить объем памяти некоторых моих наборов данных, где у меня есть небольшой набор факторов на столбцы (повторяется большое количество раз).Есть ли лучшие способы минимизировать это?Для сравнения, это то, что я получаю, просто используя факторы:

library(pryr)

N <- 10 * 8
M <- 10

Исходные данные:

test <- data.frame(A = c(rep(strrep("A", M), N), rep(strrep("B", N), N)))
object_size(test)
# 1.95 kB

Используя факторы:

test2 <- as.factor(test$A)
object_size(test2)
# 1.33 kB

В стороне: я наивнопредположил, что они заменили строки на число, и был приятно удивлен, увидев test2 меньше test3.Может кто-нибудь указать мне материал о том, как оптимизировать представление факторов?

test3 <- data.frame(A = c(rep("1", N), rep("2", N)))
object_size(test3)
# 1.82 kB

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018

Боюсь, что разница минимальна.

Принцип будет достаточно простым: вместо (в вашем примере) 160 строк вы просто сохраните 2 вместе с 160 целыми числами (которые являются только4 байта).
За исключением того, что тип R хранит символы внутренне одинаково.

Каждый современный язык поддерживает строку (практически) неограниченной длины.Это создает проблему, заключающуюся в том, что вы не можете хранить вектор (или массив) строк как один непрерывный блок, поскольку любой элемент может быть сброшен на произвольную длину.Поэтому, если одному элементу назначено другое значение, которое оказалось несколько длиннее, это означало бы, что остальная часть массива должна быть смещена.Или ОС / язык должны резервировать большие объемы пространства для каждой строки.
Поэтому строки хранятся в любом удобном месте в памяти, а массивы (или векторы в R) сохраняются как блоки указателей к месту, где значение действительно есть.
В первые дни R каждый указатель указывал на другое место в памяти, даже если фактическое значение было таким же.Итак, в вашем примере 160 указателей на 160 ячеек памяти.Но это изменилось, в настоящее время он реализован в виде 160 указателей на 2 области памяти.Там могут быть некоторые небольшие различия, в основном потому, что фактор обычно может поддерживать только 2 ^ 31-1 уровней, то есть 32-битные целые числа достаточно для его хранения, в то время как персонаж в основном использует 64-битные указатели.Опять же, есть больше накладных расходов на факторы.
Как правило, может иметь некоторое преимущество в использовании фактора, если у вас действительно большой процент дубликатов, но если это не так, это может даже повредить использованию вашей памяти,

И приведенный вами пример не работает, поскольку вы сравниваете data.frame с фактором, а не с голым символом.
Еще сильнее: когда я воспроизводю ваш пример, я получаю тольковаши результаты, если я установлю stringsAsFactors на FALSE, так что вы сравниваете фактор с фактором в data.frame.
Сравнение результатов в противном случае дает намного меньшую разницу: 1568 для символа, 1328 для фактора.
И это работает только в том случае, если у вас много одинаковых значений, если вы посмотрите на это, вы увидите, что коэффициент может быть больше:

> object.size(factor(sample(letters)))
2224 bytes
> object.size(sample(letters))
1712 bytes

Так что, как правило, нет реального способасжимайте ваши данные, сохраняя при этом удобство работы, за исключением использования здравого смысла в том, что вы действительно хотите сохранить.

0 голосов
/ 14 декабря 2018

В R существует пакет с именем fst ( молниеносная сериализация фреймов данных для R) , в котором вы можете создавать сжатые fst объекты для вашего фрейма данных.Подробное объяснение можно найти в руководстве fst-package , но я кратко объясню, как его использовать и сколько места занимает объект fst.Во-первых, давайте немного увеличим ваш test фрейм данных, как показано ниже:

library(pryr)
N <- 1000 * 8
M <- 100
test <- data.frame(A = c(rep(strrep("A", M), N), rep(strrep("B", N), N)))
object_size(test)
# 73.3 kB

Теперь давайте преобразуем этот фрейм данных в объект fst следующим образом:

install.packages("fst") #install the package
library(fst) #load the package
path <- paste0(tempfile(), ".fst") #create a temporary '.fst' file
write_fst(test, path) #write the dataframe into the '.fst' file
test2 <- fst(path) #load the data as an fst object
object_size(test2)
# 2.14 kB

Дисковое пространство для созданного файла .fst: 434 bytes.Вы можете иметь дело с test2 как с обычным фреймом данных (насколько я пытался).

Надеюсь, это поможет.

0 голосов
/ 07 декабря 2018

У меня нет прямого ответа на ваш вопрос, но вот несколько сведений из книги "Advanced R" Хэдли Уикхема:

Факторы

Одним из важных применений атрибутов является определение факторов.Фактор - это вектор, который может содержать только предопределенные значения и используется для хранения категориальных данных.Факторы строятся поверх целочисленных векторов, используя два атрибута: класс, «фактор», который заставляет их вести себя иначе, чем обычные целочисленные векторы, и уровни, которые определяют набор допустимых значений.

Также:

"Хотя факторы выглядят (и часто ведут себя) как символьные векторы, они на самом деле являются целыми числами. Будьте осторожны при обращении с ними как со строками. Некоторые строковые методы (например, gsub () и grepl ())будет приводить факторы к строкам, в то время как другие (например, nchar ()) будут выдавать ошибку, а третьи (например, c ()) будут использовать базовые целочисленные значения. По этой причине обычно лучше явно преобразовать факторы в символьные векторы, есливам нужно поведение, похожее на строку. В ранних версиях R было преимущество использования памяти вместо векторов символов, но это уже не так. "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...