Обновление кадра данных с помощью функции не работает
У меня возникла небольшая проблема с использованием 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 действительно обновлять фрейм данных в функции?
Большое спасибо за любую помощь!
Ответы
Ответ 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
оценивается (т.е. Изменена) в этой локальной среде.
Вы можете преодолеть эту проблему, используя супер-назначение <<-
, , но это НЕ рекомендуется и приведет к ужасным непредвиденным проблемам (ваш компьютер ловит вирус, ваша девушка начинает обманывать вас,...).
Как правило, решение, данное Джошуа Ульрихом, - это путь к решению подобных проблем. Вы передаете исходный объект и возвращаете его. При вызове функции вы присваиваете результат исходному объекту.