2014-09-26 19 views
12

Tôi đang viết một hàm, trong số những thứ khác, ép buộc đầu vào vào một data.table.Sử dụng setDT bên trong một hàm

library(data.table) 
df <- data.frame(id = 1:10) 
f <- function(df){setDT(df)} 
f(df) 
df[, temp := 1] 

Tuy nhiên, lệnh cuối cùng kết quả đầu ra cảnh báo sau đây:

nhắn

Cảnh báo: Trong [.data.table (df,, := (temp, 1)): không hợp lệ .internal.selfref phát hiện và cố định bằng lấy một bản sao của toàn bộ bảng để: = có thể thêm cột mới này bằng cách tham chiếu. Tại điểm trước đó, dữ liệu này có thể được sao chép bằng R (hoặc được tạo theo cách thủ công sử dụng cấu trúc() hoặc tương tự). Tránh khóa < -, tên < - và attr < - trong đó trong R hiện tại (và kỳ quặc) có thể sao chép toàn bộ dữ liệu. Thay vào đó, hãy sử dụng cú pháp * để tránh sao chép:? Set,? Setnames và? Setattr. Ngoài ra, trong R < = v3.0.2, danh sách (DT1, DT2) sao chép toàn bộ DT1 và DT2 (danh sách R() được sử dụng để sao chép các đối tượng có tên); hãy nâng cấp lên R> v3.0.2 nếu đó là cắn. Nếu thông báo này không hữu ích, vui lòng báo cáo cho datatable-help để nguyên nhân gốc có thể được khắc phục.

Tôi đang sử dụng v1.9.3 của dữ liệu.table và R 3.1.1. Có nghĩa là df được sao chép tại một số điểm? Làm thế nào để tránh cảnh báo này?

Chỉnh sửa: Mã số setDT thực sự sử dụng NSE. Vì vậy, điều này dường như làm việc:

df1 <- data.frame(id = 1:10) 
f <- function(df){eval(substitute(setDT(df)),parent.frame())} 
f(df1) 
df1[, temp := 1] 

Dường như tôi có thể làm chất liệu khác với df bên trong hàm f như

df1 <- data.frame(id = 1:10) 
f <- function(df){ 
     eval(substitute(setDT(df)),parent.frame()) 
     df[, temp := 1] 
     } 
f(df1) 

Đây có phải là đúng cách để làm điều đó?

Trả lời

16

Câu hỏi hay! Thông báo cảnh báo nên nói: ... và được sửa bằng cách chụp cạn bản sao của toàn bộ bảng .... Sẽ sửa lỗi này.

setDT thực hiện hai điều:

  • thiết lập các lớp để data.table từ data.frame/list
  • sử dụng alloc.col đến hơn phân bổ cột (để := có thể được sử dụng trực tiếp)

Và bước thứ hai yêu cầu bản sao nông, nếu đầu vào không phải là data.table rồi. Và đây là lý do tại sao chúng tôi gán giá trị trở lại biểu tượng trong môi trường của nó (khung chính của setDT). Nhưng khung chính cho setDT là chức năng của bạn f(). Do đó, setDT(df) trong chức năng của bạn đã được thực hiện trôi chảy, nhưng df nằm trong môi trường toàn cầu sẽ chỉ thay đổi lớp, chứ không phải phân bổ quá mức (vì bản sao cạn đã cắt đứt liên kết).

Và trong bước tiếp theo, := phát hiện và các bản sao nông một lần nữa để phân phối quá.

Ý tưởng cho đến thời điểm này là sử dụng setDT để chuyển đổi thành dữ liệu.tables trước khi cung cấp chức năng cho một chức năng. Nhưng tôi muốn những trường hợp này được giải quyết (sẽ xem xét).

Cảm ơn một nhóm!

+0

Cảm ơn. Nó có ý nghĩa để yêu cầu người dùng sử dụng setDT trước khi sử dụng chức năng anyway, ít nhất là trong trường hợp của tôi. – Matthew

+0

Thú vị. Vì vậy, cách 'data.table' có thể thêm các cột theo tham chiếu là bằng cách phân bổ một danh sách dài hơn và sau đó thêm các cột vào danh sách dài hơn? – stanekam

+0

@iShouldUseAName, phân bổ quá mức, vâng. Kiểm tra [bài đăng này] (http://stackoverflow.com/a/24476425/559784) (và liên kết ở đó) để có một * giải thích chi tiết hơn *. – Arun

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