Обновление фрейма данных с помощью функции не работает - PullRequest
27 голосов
/ 19 октября 2010

Я столкнулся с небольшой проблемой, используя R…

В следующем фрейме данных

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

Я хочу изменить значения для v2 в строках, где v1 равно 1.

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

работает просто отлично.

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

Однако мне нужно сделать это в функции.

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)
  v1 v2
1  1 10
2  1 10
3  1 10
4  2  0
5  2  0
6  2  0

Однако, когда я сейчас смотрю на тест:

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

это не сработало. Есть ли команда, которая говорит R действительно обновить фрейм данных в функции? Большое спасибо за любую помощь!

Ответы [ 5 ]

45 голосов
/ 19 октября 2010

test в вашей функции является копией объекта из вашей глобальной среды (я предполагаю, что именно там он определен). Назначение происходит в текущей среде, если не указано иное, поэтому вы должны указать R, что вы хотите назначить локальную копию test для test в .GlobalEnv.

И хорошо бы передать все необходимые объекты в качестве аргументов функции.

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

Лично я бы return(test) и сделал бы назначение вне функции, но я не уверен, сможете ли вы сделать это в вашей реальной ситуации.

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
24 голосов
/ 06 марта 2015

Изменение <- </strong> на << - </strong> в вашей функции также помогает, см. Руководство R .Цитата с этой страницы:

Операторы << - и - >> обычно используются только в функциях и вызывают поиск в родительских средах для существующего определения присваиваемой переменной.Если такая переменная найдена (и ее привязка не заблокирована), то ее значение переопределяется, в противном случае присваивание происходит в глобальной среде.

Ваш код должен быть:

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)
8 голосов
/ 19 октября 2010

Рекомендуется не изменять глобальные переменные в функциях, поскольку это может иметь нежелательные побочные эффекты .Чтобы избежать этого в R, любые изменения в объектах внутри функции фактически изменяют только копии, локальные для этой функции environment.

Если вы действительно хотите изменить тест, вы должны присвоить возвращаемое значениетестируемую функцию (лучше написать функцию с более явным возвращаемым значением,

 test <- test.fun(1)

или выбрать глобальную среду для назначения в пределах test.fun,

test.fun <- function (x) {             
    test[test$v1==x,"v2"] <- 10             
    print(test)
    assign("test",test,.GlobalEnv)           
} 
2 голосов
/ 19 октября 2010

Вы можете написать функцию замены. Это функция с именем, оканчивающимся на «<-», и, по сути, заключает его в: </p>

foo = bar (foo)

обертка. Итак, в вашем случае:

> "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

Обратите внимание, что вы должны указывать имя функции при создании, иначе R запутается.

2 голосов
/ 19 октября 2010

Я думаю, что это происходит из-за различных environments, которые оцениваются.Ваша функция копирует test из глобальной среды во временную локальную среду (которая создается при вызове функции), а затем test оценивается (то есть изменяется) только в этой локальной среде.

Вы можетепреодолеть эту проблему с помощью супер-задания <<-, , но это НЕ рекомендуется и приведет к ужасным непредвиденным проблемам (ваш компьютер ловит вирус, ваша девушка начинает вам изменять, ...).

Как правило, решение, данное Джошуа Ульрихом, является способом решения подобных проблем.Вы передаете оригинальный объект и возвращаете его.При вызове функции вы присваиваете результат исходному объекту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...