2012-02-17 33 views
31

Một tính năng thú vị của R liên quan đến tính chất vectơ vốn có của nó là quy tắc tái chế được mô tả trong An Introduction to R trong Phần 2.2.Thực hiện các quy tắc tái chế tiêu chuẩn

Vectơ xảy ra trong cùng một biểu thức không nhất thiết phải cùng chiều dài. Nếu không, giá trị của biểu thức là một vectơ có cùng độ dài với vectơ dài nhất xuất hiện trong biểu thức. Các vector ngắn hơn trong biểu thức là tái chế thường xuyên như cần (có lẽ là phân đoạn) cho đến khi chúng khớp với độ dài của vectơ dài nhất. Đặc biệt một hằng số được lặp lại đơn giản.

Hầu hết các chức năng tiêu chuẩn đều sử dụng mã này, nhưng mã được làm như vậy được chôn trong mã C cơ bản.

Có cách nào để thực thi quy tắc tái chế tiêu chuẩn cho một hàm hoàn toàn bằng mã R không? Đó là, cho một chức năng như

mock <- function(a, b, c) { 
    # turn a, b, and c into appropriate recycled versions 

    # do something with recycled a, b, and c in some appropriately vectorized way 
} 

nơi a, bc là vectơ, có thể có độ dài khác nhau và các loại/classes không rõ, là có một cách kinh điển để có được một bộ mới của vectơ đó được tái chế theo theo các quy tắc tái chế tiêu chuẩn? Đặc biệt, tôi không thể giả định rằng "làm một cái gì đó" bước sẽ làm việc tái chế thích hợp chính nó, vì vậy tôi cần phải làm điều đó bản thân mình trước.

Trả lời

20

Tôi đã sử dụng này trong quá khứ,

expand_args <- function(...){ 
    dots <- list(...) 
    max_length <- max(sapply(dots, length)) 
    lapply(dots, rep, length.out = max_length) 
} 
+0

+1 Ý tưởng của chúng tôi về bản chất giống hệt nhau, nhưng bạn thực hiện công việc tốt hơn để gọt nó xuống cốt lõi của nó. (Nhìn vào câu trả lời của bạn, bây giờ tôi nhận ra tôi có một chút mang đi với việc xây dựng ví dụ data.frame!) –

+0

khi tôi đăng câu trả lời ban đầu của bạn là khá khác nhau, họ bây giờ hầu như giống hệt với các tên – baptiste

+0

Vâng, tôi thấy điều đó. một vài phút của nhau. cả hai. –

7

Tôi có thể sử dụng đối số length.out của rep() để thực hiện hầu hết công việc thực tế.

Đây là ví dụ tạo ra hàm better.data.frame() (nó thực sự nên được gọi là "better".data.frame()), không đặt giới hạn về độ dài của vectơ mà nó được dùng làm đối số. Trong trường hợp này, tôi tái chế tất cả các vectơ theo chiều dài của cái dài nhất, nhưng rõ ràng là bạn có thể thích nghi với điều này để phục vụ nhu cầu tái chế của riêng bạn!

better.data.frame <- function(...) { 
    cols <- list(...) 
    names(cols) <- sapply(as.list(match.call()), deparse)[-1] 

    # Find the length of the longest vector 
    # and then recycle all columns to that length. 
    n <- max(sapply(cols, length)) 
    cols <- lapply(cols, rep, length.out = n) 

    as.data.frame(cols) 
} 

# Try it out 
a <- Sys.Date() + 0:9 
b <- 1:3 
c <- letters[1:4] 

data.frame(a,b,c) 
# Error in data.frame(a, b, c) : 
# arguments imply differing number of rows: 10, 3, 4 

better.data.frame(a,b,c) 
#    a b c 
# 1 2012-02-17 1 a 
# 2 2012-02-18 2 b 
# 3 2012-02-19 3 c 
# 4 2012-02-20 1 d 
# 5 2012-02-21 2 a 
# 6 2012-02-22 3 b 
# 7 2012-02-23 1 c 
# 8 2012-02-24 2 d 
# 9 2012-02-25 3 a 
# 10 2012-02-26 1 b 
+0

Bạn có thể thêm vào 'n <-' để xử lý trường hợp đối số dài nhất không phải là giá trị đầu tiên. 'n <- max (unlist (lapply (danh sách (a, b, c), length), max)' và thêm 'a <- rep (a, length.out = n)'. – Justin

+0

@Justin - Cảm ơn Tôi chỉ cần làm điều đó, và cũng tổng quát chức năng để có một số đối số tùy ý.Nếu bạn (hoặc bất kỳ ai khác) nhìn thấy một cách tốt hơn cho tôi để lấy ra tên của các đối số được cung cấp từ bên trong các cuộc gọi chức năng, xin vui lòng Hãy cho tôi biết. Đó chỉ là những gì tôi đã đưa ra trên bay ... –

0

Một tuyến đường ngắn và-bẩn cho các đối số số là dựa vào tái chế tự động cbind của. Ví dụ:

f.abc <- function(a,b,c) { 

    df.abc <- as.data.frame(suppressWarnings(cbind(a=a, b=b, c=c))) 

    #Then use, for example, with() to use a, b and c inside the data frame, 
    #or apply(df.abc,1, ...) 
} 

Tùy thuộc rất nhiều vào việc không có nguyên nhân chính đáng khác cho cảnh báo.

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