2014-04-01 22 views
6

Tôi đang cập nhật một tập hợp các hàm trước đây chỉ chấp nhận data.frame đối tượng để làm việc với các đối số data.table.Bản sao có được thực hiện khi chức năng trả về dữ liệu.

Tôi quyết định triển khai hàm bằng cách sử dụng công cụ phương thức của R để mã cũ sử dụng data.frame s sẽ vẫn hoạt động với các chức năng được cập nhật. Trong một trong các chức năng của tôi, tôi lấy một số data.frame làm đầu vào, sửa đổi nó, và sau đó trả về sửa đổi data.frame. Tôi cũng đã tạo một triển khai data.table. Ví dụ:

# The functions 
foo <- function(d) { 
    UseMethod("foo") 
} 

foo.data.frame <- function(d) { 
    <Do Something> 
    return(d) 
} 

foo.data.table <- function(d) { 
    <Do Something> 
    return(d) 
} 

Tôi biết rằng data.table công trình bằng cách thay đổi mà không cần sao chép, và tôi thực hiện foo.data.table trong khi vẫn giữ ý nghĩ đó. Tuy nhiên, tôi trả về đối tượng data.table ở cuối hàm vì tôi muốn các tập lệnh cũ của tôi làm việc với các đối tượng data.table mới. Điều này có tạo một bản sao của data.table không? Làm thế nào tôi có thể kiểm tra? Theo tài liệu, người ta phải rất rõ ràng để tạo một bản sao của một data.table, nhưng tôi không chắc chắn trong trường hợp này.

Lý do tôi muốn trở lại một cái gì đó khi tôi không phải với data.tables:

kịch bản cũ của tôi trông như thế này

someData <- read.table(...) 
... 
someData <- foo(someData) 

Tôi muốn các kịch bản để có thể chạy với data.table s bởi chỉ thay đổi dòng nhập dữ liệu. Nói cách khác, tôi muốn tập lệnh hoạt động bằng cách chỉ thay đổi someData <- read.table(...) thành someData <- fread(...).

+1

Chỉ các hàm ': =' và 'set *' sửa đổi 'dữ liệu.table' bằng tham chiếu. Vì vậy, nếu bạn đang sử dụng ': =' hoặc bất kỳ hàm 'set *' nào trong hàm của mình, bạn có thể cần phải làm việc trên 'copy (d)' nếu bạn không muốn 'd' được sửa đổi bằng tham chiếu . Ví dụ: nếu bạn làm: 'ans <- d [, lapply (.SD, sum), by = cols]', thì không có gì thay đổi theo tham chiếu ở đây. – Arun

+0

@Arun Xin lỗi nếu câu hỏi của tôi không rõ ràng. Tôi muốn 'd' được sửa đổi bởi tham chiếu, vì vậy tôi đã sử dụng các hàm': = 'và' set * 'để sửa đổi' data.table' trong hàm 'foo.data.table' của tôi. Nếu tôi sửa đổi 'd' trong hàm bằng tham chiếu, thì' return (d) 'trả về một bản sao của' d'? – ialm

+1

không có nó không .. bạn có thể sử dụng 'tracemem' để kiểm tra những điều này nói chung. Ví dụ: 'foo <- function (x) {x [, bar: = 1L]; return (x)}; x = data.table (a = 1: 5, b = 6: 10); tracemem (x); foo (x) '. Nó sẽ dẫn đến một số chi tiết sau 'foo (x)' nếu bất kỳ bản sao nào được tạo ra. Ngoài ra, bạn có thể sử dụng hàm 'address()' để kiểm tra xem các cột của 'x' có cùng địa chỉ trước và sau hàm hay không và nếu không, sẽ không có bản sao nào được tạo. – Arun

Trả lời

5

Nhờ Arun cho câu trả lời của mình trong các ý kiến. Tôi sẽ sử dụng ví dụ của anh ấy trong các bình luận của anh ấy để trả lời câu hỏi.

Người ta có thể kiểm tra xem bản đang được thực hiện bằng cách sử dụng các chức năng tracemem để theo dõi một đối tượng trong R. Từ các tập tin giúp đỡ của các chức năng, ?tracemem, mô tả nói:

Chức năng này đánh dấu một đối tượng để rằng một tin nhắn được in bất cứ khi nào mã nội bộ sao chép đối tượng. Đó là một nguyên nhân chính gây khó dự đoán sử dụng bộ nhớ trong R.

Ví dụ:

# Using a data.frame 
df <- data.frame(x=1:5, y=6:10) 
tracemem(df) 
## [1] "<0x32618220>" 
df$y[2L] <- 11L 
## tracemem[0x32618220 -> 0x32661a98]: 
## tracemem[0x32661a98 -> 0x32661b08]: $<-.data.frame $<- 
## tracemem[0x32661b08 -> 0x32661268]: $<-.data.frame $<- 
df 
## x y 
## 1 1 6 
## 2 2 11 
## 3 3 8 
## 4 4 9 
## 5 5 10 

# Using a data.table 
dt <- data.table(x=1:5, y=6:10) 
tracemem(dt) 
## [1] "<0x5fdab40>" 
set(dt, i=2L, j=2L, value=11L) # No memory output! 
address(dt) # Verify the address in memory is the same 
## [1] "0x5fdab40" 
dt 
## x y 
## 1: 1 6 
## 2: 2 11 
## 3: 3 8 
## 4: 4 9 
## 5: 5 10 

Dường như đối tượng data.frame được sao chép hai lần khi thay đổi một phần tử trong data.frame, trong khi data.table được sửa đổi tại chỗ mà không cần sao chép!

Từ câu hỏi của tôi, tôi chỉ có thể theo dõi data.table hoặc data.frame đối tượng, d, trước khi chuyển đến chức năng, foo, để kiểm tra nếu có bản sao được thực hiện.

+2

Tuyệt vời! Bạn cũng có thể kiểm tra 'address (dt $ x)'. – Arun

+0

cũng có thể muốn kiểm tra khi nào giá trị trả về được lưu trữ, vì vậy someData = foo (someData) –

3

Không chắc này cho biết thêm bất cứ điều gì, nhưng như một câu chuyện cảnh báo lưu ý các hành vi sau đây:

library(data.table) 
foo.data.table <- function(d) { 
    d[,A:=4] 
    d$B <- 1 
    d[,C:=1] 
    return(d) 
} 
set.seed(1) 
dt  <- data.table(A=rnorm(5),B=runif(5),C=rnorm(5)) 
dt 
#    A   B   C 
# 1: -0.6264538 0.2059746 -0.005767173 
# 2: 0.1836433 0.1765568 2.404653389 
# 3: -0.8356286 0.6870228 0.763593461 
# 4: 1.5952808 0.3841037 -0.799009249 
# 5: 0.3295078 0.7698414 -1.147657009 
result <- foo.data.table(dt) 
dt 
# A   B   C 
# 1: 4 0.2059746 -0.005767173 
# 2: 4 0.1765568 2.404653389 
# 3: 4 0.6870228 0.763593461 
# 4: 4 0.3841037 -0.799009249 
# 5: 4 0.7698414 -1.147657009 
result 
# A B C 
# 1: 4 1 1 
# 2: 4 1 1 
# 3: 4 1 1 
# 4: 4 1 1 
# 5: 4 1 1 

Vì vậy, rõ ràng, dt được thông qua tham khảo để foo.data.table(...) và báo cáo kết quả đầu tiên, d[,A:=4], sửa đổi nó bằng cách tham khảo, thay đổi cột A trong dt.

Câu lệnh thứ hai, d$B <- 1, buộc tạo bản sao d (cũng được đặt tên d) phạm vi bên trong cho hàm. Sau đó, nhấn vào câu lệnh thứ ba, d[,C:=1], sửa đổi rằng theo tham chiếu (nhưng không ảnh hưởng đến dt) và return(d) sau đó trả về bản sao.

Nếu bạn thay đổi thứ tự của câu lệnh thứ hai và thứ ba, hiệu quả của lệnh gọi hàm trên dt là khác nhau.

+2

Cách tôi hiểu câu hỏi là, giả định rằng hàm cho đến khi 'return (.)' - không kết quả một 'bản sao', chỉ là câu lệnh' return (.) 'vẫn còn trong một bản sao ... – Arun

+1

Tôi nghĩ bạn đã nêu ra một điểm quan trọng. Mã kết quả từ hàm của tôi hơi mơ hồ, vì tôi đang mã hóa với các tác dụng phụ và không yêu cầu toán tử '<-' vì tôi đang sửa đổi' d' tại chỗ (tức là 'foo (d)' là đủ, nhưng tôi đã sử dụng 'd <-foo (d)'). Tôi chỉ có một trường hợp đặc biệt muốn phù hợp với cơ sở mã cũ của tôi. Tôi đã cẩn thận sử dụng các hàm 'data.table' để sửa đổi các giá trị và tạo các cột trong hàm của tôi sao cho không có bản sao nào được tạo cho đến thời điểm' trả về'. Tôi đã không chắc chắn về hành vi của 'return'ing một đối tượng' data.table'. – ialm

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