2010-10-19 25 views
21

Tôi chạy vào một vấn đề nhỏ sử dụng R ...Cập nhật khung dữ liệu thông qua chức năng không hoạt động

Trong khung dữ liệu sau

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 

Tôi muốn thay đổi giá trị cho v2 trong hàng nơi v1 là 1.

test[test$v1==1,"v2"] <- 10 

chỉ hoạt động tốt.

test 
    v1 v2 
1 1 10 
2 1 10 
3 1 10 
4 2 0 
5 2 0 
6 2 0 

Tuy nhiên, tôi cần làm điều đó trong một hàm.

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 

test.fun <- function (x) { 
    test[test$v1==x,"v2"] <- 10 
    print(test) 
} 

Gọi hàm dường như hoạt động.

test.fun(1) 
    v1 v2 
1 1 10 
2 1 10 
3 1 10 
4 2 0 
5 2 0 
6 2 0 

Tuy nhiên, khi tôi bây giờ nhìn vào kiểm tra:

test 
    v1 v2 
1 1 0 
2 1 0 
3 1 0 
4 2 0 
5 2 0 
6 2 0 

nó đã không làm việc. Có lệnh nào yêu cầu R thực sự cập nhật khung dữ liệu trong hàm không? Cảm ơn bạn rất nhiều vì đã giúp đỡ!

Trả lời

37

test trong chức năng của bạn là sao chép đối tượng từ môi trường toàn cầu của bạn (tôi giả định đó là nơi được xác định). Chuyển nhượng xảy ra trong môi trường hiện tại trừ khi được quy định khác, vì vậy bạn cần phải nói với R rằng bạn muốn gán bản sao cục bộ test vào test trong .GlobalEnv.

Và đó là hình thức tốt để truyền tất cả các đối tượng cần thiết làm đối số cho hàm.

test.fun <- function (x, test) { 
    test[test$v1==x,"v2"] <- 10 
    assign('test',test,envir=.GlobalEnv) 
    #test <<- test # This also works, but the above is more explicit. 
} 
(test.fun(1, test)) 
# v1 v2 
#1 1 10 
#2 1 10 
#3 1 10 
#4 2 0 
#5 2 0 
#6 2 0 

Cá nhân, tôi sẽ return(test) và làm nhiệm vụ bên ngoài của hàm, nhưng tôi không chắc chắn nếu bạn có thể làm điều này trong tình hình thực tế của bạn.

test.fun <- function (x, test) { 
    test[test$v1==x,"v2"] <- 10 
    return(test) 
} 
test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 
(test <- test.fun(1, test)) 
# v1 v2 
#1 1 10 
#2 1 10 
#3 1 10 
#4 2 0 
#5 2 0 
#6 2 0 
+0

Perfect! Cảm ơn rất nhiều, điều đó sẽ không thể để tôi tìm ra một mình ...;) – donodarazao

5

Thực tiễn tốt là không thay đổi biến toàn cục trong hàm, vì điều này có thể không mong muốn side effects. Để tránh điều này trong R, bất kỳ thay đổi nào đối với các đối tượng bên trong một hàm thực sự chỉ thay đổi các bản sao cục bộ cho hàm đó là environment.

Nếu bạn thực sự muốn thay đổi kiểm tra, bạn phải gán giá trị trả về của hàm để kiểm tra (nó sẽ là tốt hơn để viết các hàm có giá trị trả lại rõ ràng hơn,

test <- test.fun(1) 

Hoặc chọn môi trường toàn cầu để gán cho trong test.fun,

test.fun <- function (x) {    
    test[test$v1==x,"v2"] <- 10    
    print(test) 
    assign("test",test,.GlobalEnv)   
} 
1

tôi nghĩ rằng điều này xảy ra do sự khác nhau environments được đánh giá. bản chức năng của bạn test từ môi trường toàn cầu vào một tạm thời địa phương môi trường (được tạo trên cuộc gọi chức năng) và sau đó test chỉ được đánh giá (tức là, đã thay đổi) trong môi trường cục bộ này.

Bạn có thể khắc phục sự cố này bằng cách sử dụng siêu nhiệm vụ <<-, nhưng điều này KHÔNG được đề xuất và sẽ dẫn đến các sự cố không lường trước được (máy tính của bạn bắt vi-rút, bạn gái bắt đầu lừa bạn, ...).

Nói chung giải pháp được đưa ra bởi Joshua Ulrich là cách để đi vào những loại vấn đề này. Bạn vượt qua đối tượng ban đầu và trả lại nó. Khi gọi hàm, bạn gán kết quả cho đối tượng ban đầu của mình.

2

Bạn có thể viết chức năng thay thế. Đây là một chức năng với một tên kết thúc bằng '< -' và về cơ bản kết thúc tốt đẹp nó trong một:

foo = bar (foo)

wrapper. Vì vậy, trong trường hợp của bạn:

> "setV2<-" = function (x,value,m){x[x$v1==m,"v2"]=value;return(x)} 
> test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 
> setV2(test,1)=10 
> test 
    v1 v2 
1 1 10 
2 1 10 
3 1 10 
4 2 0 
5 2 0 
6 2 0 
> setV2(test,2)=99 
> test 
    v1 v2 
1 1 10 
2 1 10 
3 1 10 
4 2 99 
5 2 99 
6 2 99 

Lưu ý bạn phải báo giá tên hàm khi tạo hoặc R bị nhầm lẫn.

15

Thay đổi <- để < <- trong chức năng của bạn, không lừa là tốt, thấy R-manual. Trích từ trang đó:

Các nhà khai thác < < - và - >> thường chỉ được sử dụng trong các chức năng, và gây ra một tìm kiếm để thực hiện thông qua các môi trường cha mẹ cho một định nghĩa hiện của biến được giao. Nếu như một biến được tìm thấy (và ràng buộc của nó không bị khóa) thì giá trị của nó được định nghĩa lại, nếu không việc gán sẽ diễn ra trong môi trường toàn cục. sau đó

Mã của bạn nên là:

test <- data.frame(v1=c(rep(1,3),rep(2,3)),v2=0) 

test.fun <- function (x) { 
    test[test$v1==x,"v2"] <<- 10 
    print(test) 
} 

test.fun(1) 
Các vấn đề liên quan