Подтвердить что ты не робот

Обновление кадра данных с помощью функции не работает

У меня возникла небольшая проблема с использованием 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 действительно обновлять фрейм данных в функции? Большое спасибо за любую помощь!

4b9b3361

Ответ 1

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

Ответ 2

Изменение < - на < - в вашей функции также делает трюк, см. R-manual. Цитата с этой страницы:

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

Затем ваш код должен быть:

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)

Ответ 3

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

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

 test <- test.fun(1)

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

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

Ответ 4

Вы можете написать функцию замены. Это функция с именем, которое заканчивается на '< -' и по существу обертывает его в:

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 путается.

Ответ 5

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

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

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