Должен ли я использовать data.frame или матрицу?

152

Когда следует использовать data.frame, а когда лучше использовать matrix?

Оба хранят данные в прямоугольном формате, поэтому иногда это неясно.

Существуют ли общие правила, когда следует использовать какой тип данных?

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

Ответы:

176

Часть ответа уже содержится в вашем вопросе: вы используете фреймы данных, если можно ожидать, что столбцы (переменные) будут разных типов (числовые / символьные / логические и т. Д.). Матрицы предназначены для данных одного типа.

Следовательно, выбор 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

Матрицы необходимы, если вы планируете выполнять операции типа линейной алгебры.

Фреймы данных более удобны, если вы часто ссылаетесь на их столбцы по имени (через компактный оператор $).

Фреймы данных также ИМХО лучше подходят для представления (печати) табличной информации, поскольку вы можете применять форматирование к каждому столбцу отдельно.

Михал
источник
5
К этому ответу я хотел бы добавить одну вещь: если вы планируете использовать пакет ggplot2 для создания графиков, ggplot2 работает только с data.frames, а не с матрицами. Просто то, что нужно знать!
Байч,
77

@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

Я почти всегда использую фрейм данных для своих задач анализа данных, поскольку у меня часто есть больше, чем просто числовые переменные. Когда я кодирую функции для пакетов, я почти всегда приводю к матрице, а затем форматирую результаты как фрейм данных. Это потому, что фреймы данных удобны.

Гэвин Симпсон
источник
Мне было интересно, разница между data.matrix () и as.matrix () тоже. Спасибо, чтобы уточнить их и ваши советы по программированию.
микроб
Спасибо, что поделились @Gavin Simpson! Не могли бы вы рассказать немного больше о том, как вернуться от 1-6 к аф?
YJZ
1
@YZhang Вам нужно хранить метки для каждого фактора и логический вектор, указывающий, какие столбцы матрицы были факторами. Тогда было бы относительно тривиально преобразовать только те столбцы, которые были факторами, в факторы с правильными метками. Комментарии не являются хорошими местами для кода, поэтому посмотрите, не был ли задан вопрос и дан ответ раньше, и если нет, задайте новый вопрос.
Гэвин Симпсон,
47

@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
petrelharp
источник
Аргумент об эффективности памяти на самом деле о data.framesбольшей гибкости по сравнению с типами столбцов. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))будет намного меньше (в 6 раз по моим быстрым расчетам) в памяти, чем matrixверсия из-за приведения типов.
MichaelChirico
9

Матрица на самом деле является вектором с дополнительными методами. пока data.frame - это список. Разница заключается в том, что вектор против списка. для эффективности вычислений придерживайтесь матрицы. Использование data.frame, если вам нужно.

user8341
источник
3
Хм, матрица - это вектор с измерениями, я не понимаю, откуда к ней приходят методы?
Гэвин Симпсон
0

Матрицы и фреймы данных представляют собой прямоугольные двумерные массивы и могут быть неоднородными по строкам и столбцам . Они разделяют некоторые методы и свойства, но не все.

Примеры:

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
Trisquel
источник
0

Я не могу больше подчеркнуть разницу в эффективности между ними! Хотя это правда, что 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, или потому что вы делаете не очень важно, так как код разовый и т. д.).

Но в целом всегда помните об этой эффективности как о приоритете.

Вадим
источник