簡體   English   中英

使用`with`分配到data.frame

[英]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論證沒有做我認為它做的事情。

我很好奇為什么會發生這種情況的機制 ,以及是否存在允許分配的替代方案

更改withwithin with僅用於使變量可用,而不是更改它們。

編輯:為了詳細說明,我相信withwithin創建一個新環境並用給定的類似列表的對象(例如數據框)填充它,然后在該環境中評估給定的表達式。 不同的是, 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()分配到不同的環境(父幀)。)

我覺得這太復雜了。 withwithin由數據幀的命名列上的操作計算的返回值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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM