2013-02-18 18 views
10

Tôi có một loạt dữ liệu trong một danh sách. Tôi muốn áp dụng unique() cho mỗi data.table trong danh sách của tôi, nhưng làm như vậy phá hủy tất cả các khóa data.table của tôi.Tại sao lapply() không giữ lại các khóa data.table của tôi?

Dưới đây là một ví dụ:

A <- data.table(a = rep(c("a","b"), each = 3), b = runif(6), key = "a") 
B <- data.table(x = runif(6), b = runif(6), key = "x") 

blah <- unique(A) 

Ở đây, blah vẫn có một chìa khóa, và mọi thứ đều đúng trên thế giới:

key(blah) 

# [1] "a" 

Nhưng nếu tôi thêm các data.tables vào một danh sách và sử dụng lapply(), các phím bị hủy:

dt.list <- list(A, B) 

unique.list <- lapply(dt.list, unique) # Keys destroyed here 

lapply(unique.list, key) 

# [[1]] 
# NULL 

# [[2]] 
# NULL 

Điều này có thể phải làm với tôi không thực sự hiểu những gì nó có nghĩa là cho các phím được chỉ định "bằng cách tham khảo," như tôi đã có vấn đề khác với các phím biến mất.

Vì vậy:

  • Tại sao lapply không giữ chìa khóa của tôi?
  • Điều gì có nghĩa là các phím được chỉ định "theo tham chiếu"?
  • Tôi có nên lưu trữ dữ liệu trong một danh sách không?
  • Làm cách nào để lưu trữ/thao tác dữ liệu một cách an toàn. Có thể không sợ mất khóa?

EDIT:

Đối với những gì nó có giá trị, sợ hãi for vòng lặp làm việc tốt, quá:

unique.list <- list() 

for (i in 1:length(dt.list)) { 
    unique.list[[i]] <- unique(dt.list[[i]]) 
} 

lapply(unique.list, key) 

# [[1]] 
# [1] "a" 

# [[2]] 
# [1] "x" 

Nhưng điều này là R, và for vòng là ác.

+1

thú vị, 'unique.list [[1]]! = Unique (A)'. Đoán của tôi, mặc dù chỉ đơn giản là một đoán, là có lẽ những gì đang nhận được gọi là trong tuyên bố lapply là '{base}' duy nhất và không phải là '{data.table}' 'unique'. –

+0

Tôi nghĩ bạn nói đúng. Tôi chỉ nhận thấy rằng - cùng với các phím bị phá hủy - 'unique' thậm chí không thực hiện công việc của mình khi chuyển qua 'lapply' –

+1

@PaulMurray +1 Câu hỏi hay, nhưng _destroy_ có vẻ hơi mạnh. Nó không _retain_ chúng trong trường hợp này. –

Trả lời

9

Điều thú vị là, hãy chú ý sự khác biệt giữa hai kết quả khác nhau

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 

Nếu bạn sử dụng sau này, kết quả là như bạn mong đợi.


Các hành vi có vẻ bất ngờ là do thực tế rằng tuyên bố đầu tiên lapply là gọi unique.data.frame (tức là từ {base}) trong khi thứ hai được gọi unique.data.table

+0

Wow, cảm ơn. Và * lạ *. Điều này làm việc như một giải pháp, nhưng tôi vẫn muốn biết những gì đang xảy ra. Tôi có phải là người duy nhất muốn lưu trữ data.tables trong danh sách? Tôi sẽ gửi báo cáo này dưới dạng [báo cáo lỗi] (https://r-forge.r-project.org/tracker/?atid=975&group_id=240&func=browse) - nghĩ đó là công bằng? –

+1

@Plmrry Tôi nghĩ rằng khi bạn lưu trữ 'data.table's như danh sách, bạn mất một lợi ích lớn của những gì data.table cung cấp, cụ thể là hiệu quả bộ nhớ bằng cách tránh trùng lặp không cần thiết. Cá nhân, tôi lưu trữ một danh sách các ** tên ** của data.tables của tôi và sau đó lấy chúng bằng 'get (' * name * ')'. Một chút mã xấu xí hơn, nhưng nhanh hơn. –

+0

@Plmrry như cho báo cáo lỗi, nó có thể không phải là một lỗi, nhưng chỉ là cách 'match.fun()' hoạt động. Tôi không thể nói mặc dù –

5

Tốt câu hỏi. Nó chỉ ra rằng đó là tài liệu trong ?lapply (xem phần Chú ý):

Vì lý do lịch sử, các cuộc gọi được tạo ra bởi lapply là unevaluated, và mã đã được viết (ví dụ bquote) mà dựa vào này. Điều này có nghĩa là cuộc gọi được ghi lại luôn có dạng FUN (X [[0L]], ...), với 0L được thay thế bằng chỉ số nguyên hiện tại. Đây không phải là vấn đề thường gặp ở số , nhưng có thể là nếu FUN sử dụng sys.call hoặc match.call hoặc nếu nó là một hàm nguyên thủy sử dụng cuộc gọi.Điều này có nghĩa là nó là thường an toàn hơn để gọi các hàm nguyên thủy với trình bao bọc, ví dụ: lapply (ll, chức năng (x) is.numeric (x)) được yêu cầu trong R 2.7.1 để đảm bảo rằng phương thức gửi cho is.numeric xảy ra chính xác.

+0

Cảm ơn! Tất nhiên nó nằm trong hướng dẫn tất cả cùng ... –

Các vấn đề liên quan