2013-02-11 55 views
3

這裏有兩種不同的方式,其中一個工作和一種不分配一個例子:分配給一個data.frame用`with`

library(datasets) 
dat <- as.data.frame(ChickWeight) 
dat$test1 <- with(dat, Time + weight) 
with(dat, test2 <- Time + weight) 
> colnames(dat) 
[1] "weight" "Time" "Chick" "Diet" "test1" 

我已經習慣了這種行爲。也許更令人驚訝的是test2剛好消失(而不是在基礎環境清盤,因爲我預計):

> ls(pattern="test") 
character(0) 

注意的是一個相當簡單的^ H^H^H^H^H^^ h短功能:

function (data, expr, ...) 
eval(substitute(expr), data, enclos = parent.frame()) 

首先,讓我們用複製的功能:

eval(substitute(Time+weight), envir=dat, enclos=parent.frame()) 

現在用不同的機箱測試:

testEnv <- new.env() 
eval(substitute(test3 <- Time+weight), envir=dat, enclos=testEnv) 
ls(envir=testEnv) 

哪個仍然沒有分配到任何地方。這反駁了我的預感,認爲它與封閉的環境被拋棄有關,而是指向一些更基本的論點,而不是做我認爲它的做法。

我很好奇力學爲什麼這是怎麼回事,如果有一個替代允許轉讓。

+0

因爲'dat'不是環境你的最後一個例子不修改'dat'。最好它會通過'as.environment'強制轉換到一個環境,然後被修改,然後立即丟棄,因爲沒有其他引用,所以原來的'dat'保持不變。 – 2013-02-12 03:54:51

回答

4

變化with變爲withinwith僅用於使變量可用,而不會改變它們。

編輯:爲了詳細說明,我相信withwithin都會創建一個新環境,並使用給定的類列表對象(如數據框)填充它,然後評估該環境中給定的表達式。不同之處在於with返回表達式的結果並放棄環境,而within返回環境(轉換回原來的類,例如data.frame)。無論哪種方式,在表達式中進行的任何賦值大概都是在創建的環境中執行的,它被with丟棄。這解釋了爲什麼test2在做with(dat, test2 <- Time + weight)後無處可尋。

請注意,由於within返回修改的環境而不是就地編輯它(即按值呼叫語義),因此您需要執行dat <- within(dat, test2 <- Time + weight)

如果您想要一個函數來分配當前環境(或任何指定的環境),請查看assign

編輯2:現代答案是擁抱tidyverse和使用magrittr & dplyr:

library(datasets) 
library(dplyr) 
library(magrittr) 
dat <- as.data.frame(ChickWeight) 
dat %<>% mutate(test1 = Time + weight) 

最後一行相當於

dat <- dat %>% mutate(test1 = Time + weight) 

這又相當於

dat <- mutate(dat, test1 = Time + weight) 

使用最後3行中的哪一行最有意義你。

+0

有幫助,但「內部」比'with'要少得多,我很好奇爲什麼有必要爲它分配一個函數。具體而言,'within'通過'data [nl] < - l'分配給data.frame的特定列。沒有'內部'方法分配給環境,但我想你可以直接使用'eval'來達到這個目的? – 2013-02-11 19:19:36

+0

這個建議是錯誤的。 「內部」不會分配給其環境以外的列。你需要做:'dat $ test2 < - 帶(dat,時間+權重)'或'dat < - 帶(dat,test2 < - 時間+權重)' – 2013-02-11 20:07:09

+0

是的,你是對的。我在手機上寫下了我原來的答案,但無法充分闡述。 – 2013-02-11 20:14:08

1

的事實,在命令行下面的作品...

eval(substitute(test <- Time + weight, dat)) 

...我總結了以下,這似乎工作的啓發。

myWith <- function(DAT, expr) { 
    X <- call("eval", 
       call("substitute", substitute(expr), DAT)) 
    eval(X, parent.frame()) 
} 

## Trying it out 
dat <- as.data.frame(ChickWeight) 
myWith(dat, test <- Time + weight) 
head(test) 
# [1] 42 53 63 70 84 103 

(這個問題的複雜的方面是我們需要substitute()搜索符號一個環境(當前幀),而「外」 eval()分配成不同環境(父幀)。)

+1

我應該補充說*使用*一個執行非本地任務的函數,因爲這是一個非常糟糕的主意,在我看來。仍然有趣的是,它可以完成。 – 2013-02-11 20:59:06

1

我知道這樣做太複雜了。 withwithin都返回由數據框的命名列上的操作計算得出的值。如果您不將它們分配給任何內容,則該值將被垃圾收集。存儲tehn的常用方法是使用<-運算符將對象分配給指定對象或可能的對象組件。 within返回整個數據幀,而with只返回從列名稱上執行的任何操作計算出的向量。當然,您可以使用assign而不是<-,但我認爲過度使用該函數可能會混淆而不是澄清代碼。在使用中差別只是分配給一個數據幀entrire或只是一個欄:

dat <- within(dat, newcol <- oldcol1*oldcol2) 
dat$newcol <- with(dat, oldcol1*oldcol2)