Как использовать acast (reshape2) внутри функции в R? - PullRequest
7 голосов
/ 22 сентября 2010

Я пытался использовать 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) внутри функции без необходимости объявления переменных вне функции.Что за хитрость?

Спасибо.

Ответы [ 4 ]

7 голосов
/ 22 сентября 2010

Вместо использования спецификации формулы используйте спецификацию символа:

acast(y, list(names(y)[1], names(y)[2]))
4 голосов
/ 22 сентября 2010

Одна проблема заключается в том, что вы злоупотребляете формулой в 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. Вы сэкономите много хлопот в долгосрочной перспективе (хотя не специально для этой конкретной проблемы), если будете правильно использовать формулы.

2 голосов
/ 22 сентября 2010

Исправление: проблема не в том, что он не находит 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
0 голосов
/ 22 сентября 2010

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

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" 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...