Tôi nên sử dụng data.frame hay ma trận?


152

Khi nào nên sử dụng a data.frame, và khi nào nên sử dụng a matrix?

Cả hai đều giữ dữ liệu ở định dạng hình chữ nhật, vì vậy đôi khi không rõ ràng.

Có bất kỳ quy tắc chung nào khi sử dụng loại dữ liệu nào không?


Thường thì một ma trận có thể phù hợp hơn với một loại dữ liệu cụ thể, nhưng nếu gói bạn muốn sử dụng để phân tích ma trận nói sẽ mong đợi một khung dữ liệu, bạn sẽ luôn phải chuyển đổi nó một cách không cần thiết. Tôi nghĩ rằng không có cách nào để tránh việc nhớ lại gói nào sử dụng.
xApple

Câu trả lời:


176

Một phần của câu trả lời đã có trong câu hỏi của bạn: Bạn sử dụng khung dữ liệu nếu các cột (biến) có thể được dự kiến ​​là các loại khác nhau (số / ký tự / logic, v.v.). Ma trận dành cho dữ liệu cùng loại.

Do đó, ma trận lựa chọn / data.frame chỉ có vấn đề nếu bạn có dữ liệu cùng loại.

Câu trả lời phụ thuộc vào những gì bạn sẽ làm với dữ liệu trong data.frame / matrix. Nếu nó sẽ được chuyển đến các hàm khác thì loại đối số dự kiến ​​của các hàm này sẽ xác định lựa chọn.

Cũng thế:

Ma trận hiệu quả hơn về bộ nhớ:

m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes

Ma trận là một điều cần thiết nếu bạn có kế hoạch thực hiện bất kỳ loại phép toán đại số tuyến tính nào.

Khung dữ liệu sẽ thuận tiện hơn nếu bạn thường xuyên tham khảo các cột của nó theo tên (thông qua toán tử $ compact).

Khung dữ liệu cũng IMHO tốt hơn để báo cáo (in) thông tin dạng bảng vì bạn có thể áp dụng định dạng cho từng cột riêng biệt.


5
Một điều tôi muốn thêm vào câu trả lời này là nếu bạn dự định sử dụng gói ggplot2 để tạo đồ thị, ggplot2 chỉ hoạt động với data.frames chứ không phải ma trận. Chỉ cần một cái gì đó để nhận thức!
Bajcz

77

Một điều không được @Michal đề cập là không chỉ là một ma trận nhỏ hơn khung dữ liệu tương đương, sử dụng ma trận có thể làm cho mã của bạn hiệu quả hơn nhiều so với sử dụng khung dữ liệu, thường là rất đáng kể. Đó là một lý do tại sao trong nội bộ, rất nhiều hàm R sẽ ép buộc ma trận dữ liệu trong các khung dữ liệu.

Khung dữ liệu thường thuận tiện hơn nhiều; người ta không phải lúc nào cũng có những khối dữ liệu nguyên tử nằm xung quanh.

Lưu ý rằng bạn có thể có một ma trận ký tự; bạn không cần phải có dữ liệu số để xây dựng ma trận trong R.

Khi chuyển đổi khung dữ liệu thành ma trận, lưu ý rằng có một data.matrix()hàm xử lý các yếu tố một cách thích hợp bằng cách chuyển đổi chúng thành các giá trị số dựa trên các mức bên trong. Việc ép buộc as.matrix()sẽ dẫn đến một ma trận ký tự nếu bất kỳ nhãn yếu tố nào không phải là số. Đối chiếu:

> 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

Tôi hầu như luôn sử dụng khung dữ liệu cho các nhiệm vụ phân tích dữ liệu của mình vì tôi thường có nhiều hơn chỉ là các biến số. Khi tôi mã hóa các hàm cho các gói, tôi hầu như luôn ép buộc vào ma trận và sau đó định dạng lại kết quả dưới dạng khung dữ liệu. Điều này là do khung dữ liệu thuận tiện.


Tôi cũng đã tự hỏi sự khác biệt giữa data.matrix () và as.matrix (). Nhờ làm rõ chúng và lời khuyên của bạn trong lập trình.
microbe

Cảm ơn đã chia sẻ @Gavin Simpson! Bạn có thể giới thiệu thêm một chút về cách quay lại từ 1-6 đến af không?
YJZ

1
@YZhang Bạn cần lưu trữ nhãn cho từng yếu tố và vectơ logic cho biết cột nào của ma trận là yếu tố. Sau đó, sẽ là tương đối tầm thường khi chuyển đổi chỉ những cột có yếu tố trở lại thành yếu tố với nhãn chính xác. Nhận xét không phải là nơi tốt cho mã, vì vậy hãy xem Q đã được hỏi & trả lời trước chưa và nếu không hỏi một câu hỏi mới.
Gavin Simpson

47

@Michal: Ma trận không thực sự hiệu quả hơn về bộ nhớ:

m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes

... Trừ khi bạn có một số lượng lớn các cột:

m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes

đối số hiệu quả bộ nhớ thực sự là về việc data.framescung cấp linh hoạt hơn các loại cột. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))sẽ nhỏ hơn nhiều (6 lần theo tính toán nhanh của tôi) trong bộ nhớ so với matrixphiên bản vì kiểu ép buộc.
MichaelChirico

9

Ma trận thực sự là một vector với các phương thức bổ sung. trong khi data.frame là một danh sách. Sự khác biệt là xuống vector so với danh sách. cho hiệu quả tính toán, gắn bó với ma trận. Sử dụng data.frame nếu bạn phải.


3
Hmm, một ma trận là một vectơ có kích thước, tôi không thấy các phương thức đi vào đâu?
Gavin Simpson

0

Ma trận và khung dữ liệu là các mảng 2D hình chữ nhật và có thể không đồng nhất bởi các hàng và cột . Họ chia sẻ một số phương pháp và tính chất, nhưng không phải tất cả.

Ví dụ:

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

Tôi không thể nhấn mạnh thêm sự khác biệt hiệu quả giữa hai! Mặc dù đúng là DF thuận tiện hơn trong một số trường hợp phân tích dữ liệu đặc biệt, chúng cũng cho phép dữ liệu không đồng nhất và một số thư viện chỉ chấp nhận chúng, tất cả đều thực sự là thứ yếu trừ khi bạn viết mã một lần cho một tác vụ cụ thể.

Tôi sẽ cho bạn một ví dụ. Có một hàm sẽ tính toán đường dẫn 2D của phương thức MCMC. Về cơ bản, điều này có nghĩa là chúng ta lấy một điểm ban đầu (x, y) và lặp lại một thuật toán nhất định để tìm một điểm mới (x, y) ở mỗi bước, xây dựng theo cách này cho toàn bộ đường dẫn. Thuật toán liên quan đến việc tính toán một hàm khá phức tạp và tạo ra một số biến ngẫu nhiên ở mỗi lần lặp, do đó, khi nó chạy trong 12 giây, tôi nghĩ rằng nó ổn khi đưa ra bao nhiêu thứ ở mỗi bước. Điều đó đang được nói, hàm đã thu thập tất cả các điểm trong đường dẫn được xây dựng cùng với giá trị của hàm mục tiêu trong data.frame 3 cột. Vì vậy, 3 cột không lớn và số bước cũng nhiều hơn 10.000 hợp lý (trong loại vấn đề này, các đường dẫn có độ dài 1.000.000 là điển hình, vì vậy 10.000 không là gì cả). Vì vậy, tôi nghĩ rằng một DF 10, 000x3 chắc chắn không phải là một vấn đề. Lý do một DF được sử dụng là đơn giản. Sau khi gọi hàm, ggplot () được gọi để vẽ đường dẫn kết quả (x, y). Và ggplot () không chấp nhận ma trận.

Sau đó, tại một số điểm vì tò mò, tôi quyết định thay đổi hàm để thu thập đường dẫn trong một ma trận. Rất vui là cú pháp của DF và ma trận là tương tự nhau, tất cả những gì tôi đã làm là thay đổi dòng chỉ định df dưới dạng data.frame thành một khởi tạo nó dưới dạng ma trận. Ở đây tôi cũng cần đề cập rằng trong mã ban đầu, DF được khởi tạo để có kích thước cuối cùng, vì vậy sau đó trong mã của hàm, chỉ có các giá trị mới được ghi vào các không gian đã được phân bổ và không có chi phí thêm hàng mới vào DF. Điều này làm cho sự so sánh thậm chí công bằng hơn, và nó cũng làm cho công việc của tôi đơn giản hơn vì tôi không cần phải viết lại bất cứ điều gì thêm trong hàm. Chỉ cần một dòng thay đổi từ phân bổ ban đầu của data.frame có kích thước yêu cầu sang ma trận có cùng kích thước. Để điều chỉnh phiên bản mới của hàm thành ggplot (), tôi đã chuyển đổi ma trận bây giờ được trả về thành dữ liệu.

Sau khi tôi chạy lại mã, tôi không thể tin được kết quả. Mã chạy trong một phần của một giây! Thay vì khoảng 12 giây. Và một lần nữa, hàm trong 10.000 lần lặp chỉ đọc và ghi giá trị vào các không gian đã được phân bổ trong DF (và bây giờ trong ma trận). Và sự khác biệt này cũng dành cho kích thước hợp lý (hoặc khá nhỏ) 10000x3.

Vì vậy, nếu lý do duy nhất của bạn để sử dụng DF là làm cho nó tương thích với chức năng thư viện như ggplot (), bạn luôn có thể chuyển đổi nó thành DF vào phút cuối - làm việc với ma trận khi bạn cảm thấy thuận tiện. Mặt khác, nếu có một lý do đáng kể hơn để sử dụng DF, chẳng hạn như bạn sử dụng một số gói phân tích dữ liệu sẽ yêu cầu chuyển đổi liên tục từ ma trận sang DF và ngược lại, hoặc bạn không tự mình thực hiện bất kỳ tính toán chuyên sâu nào và chỉ sử dụng tiêu chuẩn các gói (nhiều trong số chúng thực sự biến đổi nội bộ DF thành ma trận, thực hiện công việc của chúng và sau đó chuyển đổi kết quả trở lại - để chúng thực hiện tất cả công việc hiệu quả cho bạn) hoặc thực hiện công việc một lần để bạn không quan tâm và cảm nhận thoải mái hơn với DF, sau đó bạn không nên lo lắng về hiệu quả.

Hoặc một quy tắc thực tế khác: nếu bạn có một câu hỏi như trong OP, hãy sử dụng ma trận, vì vậy bạn sẽ chỉ sử dụng DF khi bạn không có câu hỏi như vậy (vì bạn đã biết bạn phải sử dụng DF hoặc vì bạn đã làm không thực sự quan tâm vì mã là một lần, v.v.).

Nhưng nói chung, giữ cho điểm hiệu quả này luôn luôn được ưu tiên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.