[英]Assignment to a data.frame with `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 )
哪個仍然沒有指定任何地方。 這反駁了我的預感,它與被拋棄的封閉環境有關,而是指向一些更基本的東西,enclos
論證沒有做我認為它做的事情。
我很好奇為什么會發生這種情況的機制 ,以及是否存在允許分配的替代方案 。
更改with
到within
。 with
僅用於使變量可用,而不是更改它們。
編輯:為了詳細說明,我相信with
和within
創建一個新環境並用給定的類似列表的對象(例如數據框)填充它,然后在該環境中評估給定的表達式。 不同的是, with
返回表達式的結果,並丟棄環境,同時within
返回環境(轉換回任何類它最初是,例如data.frame)。 無論哪種方式,表達之內,所作的任何分配所創建的環境,這是由丟棄內側推測執行with
。 這解釋了為什么test2
在使用后無法找到with(dat, test2 <- Time + weight)
。
請注意,由於within
返回修改后的環境而不是在適當位置編輯它(即按值調用語義),因此需要dat <- within(dat, test2 <- Time + weight)
執行dat <- within(dat, test2 <- Time + weight)
。
如果希望函數對當前環境(或任何指定環境)進行assign
,請查看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行中最合適的一行。
靈感來自命令行的以下工作......
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()
分配到不同的環境(父幀)。)
我覺得這太復雜了。 with
和within
由數據幀的命名列上的操作計算的返回值within
。 如果您不將它們分配給任何東西,該值將被垃圾收集。 存儲tehn的常用方法是使用<-
運算符分配給命名對象或可能是對象的組件。 within
返回整個數據幀,而with
該從對列名進行任何操作計算只返回載體。 當然,您可以使用assign
而不是<-
,但我認為過度使用該函數可能會混淆而不是澄清代碼。 使用上的差異只是分配給一個委托數據幀或只是一列:
dat <- within(dat, newcol <- oldcol1*oldcol2)
dat$newcol <- with(dat, oldcol1*oldcol2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.