将第一行添加到空data.frame时,行号不同(NA与1)

New*_*ser 6 r dataframe

我想了解为什么将这两个方法用于索引行号中的空data.frame结果NA分配给第一行:

方法1:

df <- data.frame(Number=numeric(), Text=character(), stringsAsFactors = FALSE)
df[1,]$Number <- 123456
df[1,]$Text <- "abcdef"
df[2,]$Number <- 456789
df[2,]$Text <- "abcdef"
Run Code Online (Sandbox Code Playgroud)

输出1:

> df
   Number   Text
NA 123456 abcdef
2  456789 abcdef
Run Code Online (Sandbox Code Playgroud)

方法2:

df <- data.frame(Number=numeric(), Text=character(), stringsAsFactors = FALSE)
df[1,1] <- 123456
df[1,2] <- "abcdef"
df[2,1] <- 456789
df[2,2] <- "abcdef"
Run Code Online (Sandbox Code Playgroud)

输出2:

> df
  Number   Text
1 123456 abcdef
2 456789 abcdef
Run Code Online (Sandbox Code Playgroud)

我看到的唯一区别是第一个方法访问data.frame使用列名而不是列号,但我没有看到为什么这导致NA行号被分配给第一个观察的原因,因为行号似乎从第二行开始按预期工作.

MrF*_*ick 4

好吧,这个答案最重要的部分是应该避免这样的代码。将数据逐行添加到 R 中的 data.frame 中的效率非常低(参见 R Inferno的 Circle 2 )。几乎总是有更好的方法来做到这一点,具体取决于您到底在做什么。

但要了解这里发生的事情。所有这些都归结为$.data.frame<-[.data.frame、 和[<-.data.frame函数。在第一种情况下,与

df[1,]$Number <- 123456
Run Code Online (Sandbox Code Playgroud)

您首先执行调用的子集[<-.data.frame。当您请求 data.frame 中不存在的行时,您会得到一堆所有内容的 NA 值(包括行名称)。现在您有一个空的 data.frame,列和行名称中包含 NA 值。现在您调用$<-.data.frame只是更新该Number列。您不更新行号。然后传递这个新值[<-.data.frame以将其合并回 data.frame 中。当此命令运行时,它会检查以确保不存在重复的行名称。对于第一行,由于只有一行并且其名称为 NA,因此保留该名称。但是,当存在重复名称时,该函数会将这些值替换为行号的索引。这就是为什么第一行得到 NA,但当它尝试添加下一行时,它再次尝试 NA,但发现这是重复的,因此必须选择一个新名称。df[1:2,]$Number <- 123456(看看当你尝试时会发生什么df[3,]$Number <- 456789

另一方面,当你这样做时

df[1,1] <- 123456
Run Code Online (Sandbox Code Playgroud)

这不会首先进行子集化来创建缺少行名称的行。你直接跳过作业,$.data.frame<-然后[.data.frame。在这种情况下,它不必合并到具有 NA 行名称的新行中,它可以立即创建该行并分配行名称。这只是调用赋值运算符的一个特殊属性,必须先进行提取。您可以打开调试器来debug(`[<-.data.frame`)查看到底是如何发生的。

因此,第一种方法基本上执行三个步骤:1) extact df[1,],2) 更改 number 列的值,然后 3) 将该新值合并回df[1,]。第二种方法跳过第一个步骤,只是直接将值合并到df[1,]. 真正的区别在于每个函数如何为尚不存在的行选择行名称。