我認爲這可以用多一點澄清。
考慮設置:
name <- c("Bob", "Lauren", "Joe", "Chris")
age <- c(45, 34, 54, 12)
df <- data.frame(name, age)
現在看看會發生什麼,當我們這樣做:
debugonce(`$<-.data.frame`)
> df$x[1] <- "a"
debugging in: `$<-.data.frame`(`*tmp*`, "x", value = "a")
debug: {
cl <- oldClass(x)
class(x) <- NULL
nrows <- .row_names_info(x, 2L)
if (!is.null(value)) {
N <- NROW(value)
if (N > nrows)
stop(sprintf(ngettext(N, "replacement has %d row, data has %d",
"replacement has %d rows, data has %d"), N, nrows),
domain = NA)
if (N < nrows)
if (N > 0L && (nrows%%N == 0L) && length(dim(value)) <=
1L)
value <- rep(value, length.out = nrows)
else stop(sprintf(ngettext(N, "replacement has %d row, data has %d",
"replacement has %d rows, data has %d"), N, nrows),
domain = NA)
if (is.atomic(value) && !is.null(names(value)))
names(value) <- NULL
}
x[[name]] <- value
class(x) <- cl
return(x)
}
注意,這被稱爲與value = "a"
,最終我們將只需運行x[[name]] <- value
,所以「a」沿着每一行被回收。
這看起來很簡單,但是當我們發生了什麼(請確保每個它們之間全殲列x
!):
debugonce(`$<-.data.frame`)
> df$x[2] <- "a"
debugging in: `$<-.data.frame`(`*tmp*`, "x", value = c(NA, "a"))
#Rest snipped...
啊哈!這一次,它被稱爲與value = c(NA,"a")
,所以違背RobertH的回答中,我們發現,回收實際上收益率:
> df
name age x
1 Bob 45 <NA>
2 Lauren 34 a
3 Joe 54 <NA>
4 Chris 12 a
困惑?如果我們嘗試:
debugonce(`$<-.data.frame`)
> df$x[3] <- "a"
debugging in: `$<-.data.frame`(`*tmp*`, "x", value = c(NA, NA, "a"))
嗯。由於回收失敗,此錯誤結束。
完成:
debugonce(`$<-.data.frame`)
> df$x[4] <- "a"
debugging in: `$<-.data.frame`(`*tmp*`, "x", value = c(NA, NA, NA, "a"))
而在這一個結果:
> df
name age x
1 Bob 45 <NA>
2 Lauren 34 <NA>
3 Joe 54 <NA>
4 Chris 12 a
所以這是怎麼回事呢?那麼請記住,數據框中不存在的列(或列表中不存在的元素)被視爲NULL
。所以我們引用NULL
的第一,第二等元素。
現在運行:
> `[<-`(NULL,1,1)
[1] 1
> `[<-`(NULL,2,1)
[1] NA 1
> `[<-`(NULL,3,1)
[1] NA NA 1
> `[<-`(NULL,4,1)
[1] NA NA NA 1
,你可以開始看到各種調用是如何被拼湊起來。
我想如果你在乾淨的會議中運行你的最後一個例子,你可能會發現它不會像OP期望的那樣工作_quite_。 – joran
謝謝@RobertH。我像你推薦的'df $職業< - NA'那樣初始化了新的專欄,並且做了這個訣竅。我沒有在'data.frame()'函數中包含佔位矢量,但它仍然有效。 – heyydrien