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?
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?
Câu trả lời:
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.
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.
@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
data.frames
cung 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 matrix
phiên bản vì kiểu ép buộc.
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.
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
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.