Ответ 1
Вместо использования спецификации формулы используйте спецификацию символа:
acast(y, list(names(y)[1], names(y)[2]))
Я попытался использовать acast
из reshape2
в самозаписываемой функции, но имел проблему, что acast не нашел данные, которые я отправляю на него.
Вот мои данные:
library("reshape2")
x <- data.frame(1:3, rnorm(3), rnorm(3), rnorm(3))
colnames(x) <- c("id", "var1", "var2", "var3")
y <-melt(x, id = "id", measure = c("var1", "var2", "var3"))
y
выглядит следующим образом:
id variable value
1 1 var1 0.1560812
2 2 var1 1.0343844
3 3 var1 -1.4157728
4 1 var2 0.8808935
5 2 var2 0.1719239
6 3 var2 0.6723758
7 1 var3 -0.7589631
8 2 var3 1.1325995
9 3 var3 -1.5744876
теперь я могу вернуть его через acast
:
> acast(y,y[,1] ~ y[,2])
var1 var2 var3
1 0.1560812 0.8808935 -0.7589631
2 1.0343844 0.1719239 1.1325995
3 -1.4157728 0.6723758 -1.5744876
Однако при написании небольшой обертки для acast
, которая должна делать то же самое, я получаю глупые сообщения об ошибках:
wrap.acast <- function(dat, v1 = 1, v2 = 2) {
out <- acast(dat, dat[,v1] ~ dat[,v2])
return(out)
}
wrap.acast(y)
Error in eval(expr, envir, enclos) : object 'dat' not found
Проблема, очевидно, связана с чем-то вроде сред и глобальных/локальных переменных. Поскольку он предоставляет другие сообщения об ошибках после объявления dat
в глобальной среде (т.е. v1
и v2
не найден, если они не являются глобальными).
Я хотел бы использовать resahpe (особенно acast) внутри функции без необходимости объявления переменных вне функции. Какая уловка?
Спасибо.
Вместо использования спецификации формулы используйте спецификацию символа:
acast(y, list(names(y)[1], names(y)[2]))
Одна проблема заключается в том, что вы злоупотребляете нотной формулой в R. Вы не должны делать такие вещи, как
> acast(y, y[,1] ~ y[,2])
var1 var2 var3
1 2.1726117 0.6107264 0.291446236
2 0.4755095 -0.9340976 -0.443291873
3 -0.7099464 -1.2536334 0.001105352
поскольку биты 'y' являются избыточными, если предоставляется объект данных. Если вы ссылаетесь на переменные y по имени непосредственно в формуле, все работает хорошо
> acast(y, id ~ variable)
var1 var2 var3
1 2.1726117 0.6107264 0.291446236
2 0.4755095 -0.9340976 -0.443291873
3 -0.7099464 -1.2536334 0.001105352
и код гораздо читабельнее в этой второй версии.
Чтобы сделать то, что вы хотите с помощью оболочки acast
, будет связано с генерированием правильной формулы с помощью names
, как указывает Джорис, а решение Хэдли намного проще. Поэтому я хочу обратить внимание на то, как вы используете формулу спецификации в R. Вы сэкономите много проблем в долгосрочной перспективе (хотя не специально с этой конкретной проблемой), если вы правильно используете формулы.
Исправление: проблема не в том, что она не находит dat, но что она не находит dat [, v1] и dat [, v2] в указанной формуле. Acast принимает аргумент формулы типа и оценивается во временной среде, созданной вокруг вашего фрейма данных. Внутри этой среды он не находит объект "dat", когда функция завернута в другую.
Я не совсем понимаю, как это работает в глобальном режиме и не завершается, но если вы кормите acast формулой, он также работает и внутри функции.
wrap.acast <- function(dat, v1 = 1, v2 = 2) {
x1 <- names(dat)[v1]
x2 <- names(dat)[v2]
form <- as.formula(paste(x1,"~",x2))
out <- acast(dat,form)
return(out)
}
используя данные вашей игрушки:
> wrap.acast(y)
var1 var2 var3
1 0.04095337 0.4044572 -0.4532233
2 1.23905358 1.2493187 0.7083557
3 0.72798307 0.7868746 1.7144811
Я нашел довольно неэлегантный способ решить проблему с помощью супер назначений (<<-
).
Задание функции выполняется следующим образом. Но это довольно уродливо, так как он создает глобальные переменные, которые остаются.
wrap.acast <- function(dat, v1 = 1, v2 = 2) {
dat <<- dat
v1 <<- v1
v2 <<- v2
out <- acast(dat, dat[,v1] ~ dat[,v2])
return(out)
}
Я все еще очень заинтересован в других (менее засоряющих) решениях.
перед запуском функции:
> ls()
[1] "wrap.acast" "x" "y"
после запуска функции:
> ls()
[1] "dat" "v1" "v2" "wrap.acast" "x"
[6] "y"