Чи варто використовувати data.frame або матрицю?


152

Коли слід використовувати a data.frame, а коли краще використовувати a matrix?

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

Чи існують якісь загальні правила, коли потрібно використовувати тип даних?


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

Відповіді:


176

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

Отже, вибір матриці / 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

Матриці є необхідністю, якщо ви плануєте робити будь-які операції типу лінійної алгебри.

Кадри даних зручніше, якщо ви часто посилаєтесь на його стовпці по імені (через компактний оператор $).

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


5
Я хотів би додати цю відповідь, що якщо ви плануєте використовувати пакет ggplot2 для створення графіків, ggplot2 працює лише з data.frames, а не матрицями. Просто щось слід пам’ятати!
Bajcz

77

Щось, про що не згадує @Michal, полягає в тому, що не тільки матриця менша, ніж еквівалентний кадр даних, використання матриць може зробити ваш код набагато ефективнішим, ніж використання фреймів даних, часто значно. Це одна з причин, чому внутрішньо багато 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 в af?
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

аргумент ефективності пам’яті насправді полягає у data.framesнаданні більшої гнучкості щодо типів стовпців. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))буде значно меншим (6 разів за моїм швидким розрахунком) в пам'яті, ніж matrixверсія через примус типу.
MichaelChirico

9

Матриця насправді є вектором з додатковими методами. а data.frame - це список. Різниця знижується до вектора проти списку. для ефективності обчислень дотримуйтесь матрицю. Використання data.frame, якщо потрібно.


3
Гм, матриця - вектор з розмірами, я не бачу, куди до них приходять методи?
Гевін Сімпсон

0

Матриці та кадри даних є прямокутними 2D масивами і можуть бути неоднорідними за рядками та стовпцями . Вони поділяють деякі методи та властивості, але не всі.

Приклади:

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

0

Я не можу більше підкреслити різницю ефективності між ними! Незважаючи на те, що DF в деяких випадках, особливо для аналізу даних, зручніше, вони також дозволяють гетерогенні дані, і деякі бібліотеки приймають їх лише, але все це є дійсно вторинним, якщо ви не пишете одноразовий код для конкретного завдання.

Дозвольте навести вам приклад. Була функція, яка обчислила 2D шлях методу MCMC. В основному це означає, що ми беремо початкову точку (x, y) і ітератуємо певний алгоритм для пошуку нової точки (x, y) на кожному кроці, будуючи таким чином весь шлях. Алгоритм передбачає обчислення досить складної функції та генерацію деякої випадкової змінної при кожній ітерації, тому, коли вона працює протягом 12 секунд, я вважав, що це добре, враховуючи, скільки матеріалу вона робить на кожному кроці. При цьому функція збирала всі точки в побудованому шляху разом зі значенням цільової функції в 3-стовпковому фреймі data.frame. Отже, 3 стовпчики не настільки великі, і кількість кроків також було більш ніж розумною 10000 (для подібного роду проблем шляхи довжиною 1 000 000 є типовими, тому 10 000 - це нічого). Отже, я подумав, що DF 10, 000x3, безумовно, не є проблемою. Причина використання ДФ проста. Після виклику функції 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, то не варто турбуватися про ефективність.

Або інше більш практичне правило: якщо у вас є таке питання, як, наприклад, в ОП, використовуйте матриці, тож ви б використовували DF-файли лише тоді, коли у вас немає такого питання (тому що ви вже знаєте, що ви повинні використовувати DF, або тому, що ви робите не дуже важливо, оскільки код одноразовий тощо).

Але в цілому завжди пам’ятайте про цю ефективність як про пріоритет.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.