Когда следует использовать data.frame
, а когда лучше использовать matrix
?
Оба хранят данные в прямоугольном формате, поэтому иногда это неясно.
Существуют ли общие правила, когда следует использовать какой тип данных?
Когда следует использовать data.frame
, а когда лучше использовать matrix
?
Оба хранят данные в прямоугольном формате, поэтому иногда это неясно.
Существуют ли общие правила, когда следует использовать какой тип данных?
Ответы:
Часть ответа уже содержится в вашем вопросе: вы используете фреймы данных, если можно ожидать, что столбцы (переменные) будут разных типов (числовые / символьные / логические и т. Д.). Матрицы предназначены для данных одного типа.
Следовательно, выбор matrix / data.frame проблематичен только в том случае, если у вас есть данные одного типа.
Ответ зависит от того, что вы собираетесь делать с данными в data.frame / matrix. Если оно будет передано другим функциям, то ожидаемый тип аргументов этих функций определяет выбор.
Также:
Матрицы более эффективны по памяти:
m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes
Матрицы необходимы, если вы планируете выполнять операции типа линейной алгебры.
Фреймы данных более удобны, если вы часто ссылаетесь на их столбцы по имени (через компактный оператор $).
Фреймы данных также ИМХО лучше подходят для представления (печати) табличной информации, поскольку вы можете применять форматирование к каждому столбцу отдельно.
@Michal не упомянул о том, что матрица не только меньше, чем эквивалентный фрейм данных, но использование матриц может сделать ваш код намного более эффективным, чем использование фреймов данных, часто значительно. Это одна из причин, почему внутренне многие функции R будут приводить к данным матриц, которые находятся во фреймах данных.
Фреймы данных часто намного удобнее; не всегда есть только атомарные порции данных.
Обратите внимание, что у вас может быть матрица символов; Вам не нужно просто иметь числовые данные для построения матрицы в R.
При преобразовании фрейма данных в матрицу обратите внимание, что есть data.matrix()
функция, которая обрабатывает факторы соответствующим образом, преобразовывая их в числовые значения на основе внутренних уровней. Принуждение через as.matrix()
приведет к матрице символов, если любая из меток фактора не является числовой. Для сравнения:
> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
a B
[1,] "a" "A"
[2,] "b" "B"
[3,] "c" "C"
[4,] "d" "D"
[5,] "e" "E"
[6,] "f" "F"
> head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
a B
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
[5,] 5 5
[6,] 6 6
Я почти всегда использую фрейм данных для своих задач анализа данных, поскольку у меня часто есть больше, чем просто числовые переменные. Когда я кодирую функции для пакетов, я почти всегда приводю к матрице, а затем форматирую результаты как фрейм данных. Это потому, что фреймы данных удобны.
@Michal: матрицы на самом деле не более эффективны для памяти:
m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes
... если у вас нет большого количества столбцов:
m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes
data.frames
большей гибкости по сравнению с типами столбцов. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))
будет намного меньше (в 6 раз по моим быстрым расчетам) в памяти, чем matrix
версия из-за приведения типов.
Матрица на самом деле является вектором с дополнительными методами. пока data.frame - это список. Разница заключается в том, что вектор против списка. для эффективности вычислений придерживайтесь матрицы. Использование data.frame, если вам нужно.
Матрицы и фреймы данных представляют собой прямоугольные двумерные массивы и могут быть неоднородными по строкам и столбцам . Они разделяют некоторые методы и свойства, но не все.
Примеры:
M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i) # a list
dim(M) <- c(2,3) # set dimensions
print(M) # print result
# [,1] [,2] [,3]
# [1,] 3.14 5 "dog"
# [2,] TRUE Numeric,3 0+1i
DF <- data.frame(M) # a data frame
print(DF) # print result
# X1 X2 X3
# 1 3.14 5 dog
# 2 TRUE 2, 3, 5 0+1i
M <- matrix(c(1,1,1,1,2,3,1,3,6),3) # a numeric matrix
DF <- data.frame(M) # a all numeric data frame
solve(M) # obtains inverse matrix
solve(DF) # obtains inverse matrix
det(M) # obtains determinant
det(DF) # error
Я не могу больше подчеркнуть разницу в эффективности между ними! Хотя это правда, что DF более удобны в некоторых случаях анализа данных, они также допускают разнородные данные, и некоторые библиотеки принимают их только, но все это действительно вторично, если вы не пишете одноразовый код для конкретной задачи.
Позвольте привести пример. Была функция, которая рассчитывала бы 2D путь метода MCMC. По сути, это означает, что мы берем начальную точку (x, y) и повторяем определенный алгоритм, чтобы найти новую точку (x, y) на каждом шаге, таким образом создавая весь путь. Алгоритм включает в себя вычисление довольно сложной функции и генерацию некоторой случайной величины на каждой итерации, поэтому, когда она запускалась в течение 12 секунд, я думала, что это хорошо, учитывая, сколько вещей она делает на каждом шаге. При этом функция собрала все точки в построенном пути вместе со значением целевой функции в data-frame из трех столбцов. Таким образом, 3 столбца не так уж велики, и количество шагов также было более чем разумным 10000 (в этом типе проблем типичны пути длиной 1 000 000, поэтому 10 000 - это ничто). Итак, я подумал, DF 10, 000x3 определенно не проблема. Причина использования DF проста. После вызова функции был вызван ggplot (), чтобы нарисовать результирующий путь (x, y). И ggplot () не принимает матрицу.
Затем в какой-то момент из любопытства я решил изменить функцию, чтобы собирать путь в матрице. С радостью синтаксис DF и матриц схож, все, что я сделал, это изменил строку, указав df как data.frame, на строку, инициализировав ее как матрицу. Здесь я также должен упомянуть, что в исходном коде DF был инициализирован, чтобы иметь окончательный размер, поэтому позже в коде функции были записаны только новые значения в уже выделенные пробелы, и не было никаких затрат на добавление новых строк в DF. Это делает сравнение еще более справедливым, а также упрощает мою работу, поскольку мне не нужно было ничего переписывать в функции. Изменение только одной строки от первоначального размещения data.frame требуемого размера к матрице того же размера. Чтобы адаптировать новую версию функции к ggplot (), я преобразовал теперь возвращенную матрицу в данные.
После повторного запуска кода я не мог поверить в результат. Код запускается за доли секунды! Вместо примерно 12 секунд. И снова, функция в течение 10 000 итераций считывает и записывает значения только в уже выделенные пространства в DF (и теперь в матрице). И эта разница также для разумного (или скорее небольшого) размера 10000x3.
Итак, если ваша единственная причина использовать DF - сделать его совместимым с библиотечной функцией, такой как ggplot (), вы всегда можете преобразовать ее в DF в последний момент - работайте с матрицами, насколько вам удобно. Если, с другой стороны, есть более существенная причина для использования DF, например, вы используете какой-то пакет анализа данных, который в противном случае потребовал бы постоянного преобразования из матриц в DF и обратно, или вы не выполняете интенсивные вычисления самостоятельно и используете только стандартные пакеты (многие из них на самом деле внутренне преобразуют DF в матрицу, выполняют свою работу, а затем преобразуют результат обратно - так, что они выполняют всю эффективную работу за вас), или выполняют разовую работу, чтобы вам было все равно удобнее с DF, тогда вам не стоит беспокоиться об эффективности.
Или другое более практичное правило: если у вас есть вопрос, такой как в OP, используйте матрицы, поэтому вы будете использовать DF только тогда, когда у вас нет такого вопроса (потому что вы уже знаете, что должны использовать DF, или потому что вы делаете не очень важно, так как код разовый и т. д.).
Но в целом всегда помните об этой эффективности как о приоритете.