Tho*_*ing 13 merge r dataframe
我有一个非空数据框 df1
df1 <- structure(list(V1 = 1:4, V2 = 5:8), class = "data.frame", row.names = c(NA,
-4L))
> df1
V1 V2
1 1 5
2 2 6
3 3 7
4 4 8
Run Code Online (Sandbox Code Playgroud)
和两个空的数据帧df2.a和df2.b,即
df2.a <- structure(list(V1 = integer(0), V2 = integer(0), V3 = integer(0), V4 = integer(0)), row.names = integer(0), class = "data.frame")
df2.b <- structure(list(V1 = NULL, V2 = NULL, V3 = NULL, V4 = NULL), row.names = c(NA, 0L), class = "data.frame")
Run Code Online (Sandbox Code Playgroud)
where df2.aanddf2.b看起来几乎没有区别(唯一的区别是使用dput(df2.a)and时显示的dput(df2.b))
> df2.a
[1] V1 V2 V3 V4
<0 rows> (or 0-length row.names)
> df2.b
[1] V1 V2 V3 V4
<0 rows> (or 0-length row.names)
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试df1与df2.aor合并时df2.b,发生了一些奇怪的事情
> merge(df1,df2.a,all = TRUE)
V1 V2 V3 V4
1 1 5 NA NA
2 2 6 NA NA
3 3 7 NA NA
4 4 8 NA NA
> merge(df1,df2.b,all = TRUE)
V1 V2 V4
1 1 5 NA
2 2 6 NA
3 3 7 NA
4 4 8 NA
Run Code Online (Sandbox Code Playgroud)
如您所见,V3在df1与合并时被丢弃df2.b,而所需的应该是类似于merge(df1,df2.a,all = TRUE).
有人可以解释一下吗?感谢您在使用mergeoverdf1和df2.b.
All*_*ron 13
这是一个复杂的问题。错误步骤发生在以下行中base::merge:
y <- y[c(m$yi, if (all.x) rep.int(1L, nxx), if (all.y) m$y.alone),
-by.y, drop = FALSE]
Run Code Online (Sandbox Code Playgroud)
当您将参数df2.b作为y参数传递给 时merge,这一行实际上会生成一个无效的数据框,正如您在浏览器中所看到的:
Browse[2]> y
#> V4
#> NA NULL
#> NA.1 <NA>
#> NA.2 <NA>
#> NA.3 <NA>
#> Warning message:
#> In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
#> corrupt data frame: columns will be truncated or padded with NAs
Run Code Online (Sandbox Code Playgroud)
如果我们通过跟踪逻辑,我们可以看到我们可以通过调用在调试器之外重现错误:
Browse[2]> y
#> V4
#> NA NULL
#> NA.1 <NA>
#> NA.2 <NA>
#> NA.3 <NA>
#> Warning message:
#> In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
#> corrupt data frame: columns will be truncated or padded with NAs
Run Code Online (Sandbox Code Playgroud)
然而,我们没有遇到这个问题db2.a:
df2.b[c(1, 1, 1, 1), -c(1:2), drop = FALSE]
#> V4
#> NA NULL
#> NA.1 <NA>
#> NA.2 <NA>
#> NA.3 <NA>
#> Warning message:
#> In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
#> corrupt data frame: columns will be truncated or padded with NAs
Run Code Online (Sandbox Code Playgroud)
那么这是为什么呢?尽管打印数据框时df2.a和df2.b看起来相同,但它们并不相同。空的数字向量与NULL. 主要区别(导致问题的那个)是索引一个空的数字向量给你一个非零长度的NA值,而 NULL 给你一个单一的NULL值。
df2.a[c(1, 1, 1, 1), -c(1:2), drop = FALSE]
#> V3 V4
#> NA NA NA
#> NA.1 NA NA
#> NA.2 NA NA
#> NA.3 NA NA
Run Code Online (Sandbox Code Playgroud)
所以我想这是预期的行为。问题是 R 完全允许NULL作为数据框列。我很惊讶这种事情不会经常发生。
我跟踪了这个问题的原因,发现这个错误出现在以下部分merge.data.frame:
y <- y[c(m$yi, if (all.x) rep.int(1L, nxx), if (all.y) m$y.alone),
-by.y, drop = FALSE]
Run Code Online (Sandbox Code Playgroud)
要显示问题,请尝试以下代码:
df2.b[rep(1, 4), -(1:2), drop = FALSE]
# V4
# NA NULL
# NA.1 <NA>
# NA.2 <NA>
# NA.3 <NA>
# Warning message:
# In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
# corrupt data frame: columns will be truncated or padded with NAs
df2.a[rep(1, 4), -(1:2), drop = FALSE]
# V3 V4
# 1: NA NA
# 2: NA NA
# 3: NA NA
# 4: NA NA
Run Code Online (Sandbox Code Playgroud)
因此,此问题是由[.data.frame. 源代码的一部分[.data.frame是:
for (j in seq_along(x)) {
xj <- xx[[sxx[j]]]
x[[j]] <- if (length(dim(xj)) != 2L){
xj[i]
}else{ xj[i, , drop = FALSE]}
}
Run Code Online (Sandbox Code Playgroud)
在这里,x是要返回的结果 data.frame。它现在只有 V3 和 V4 列。xx是输入 data.frame 的副本(在我们的例子中是 df2.b)。此 for 循环将首先分配NULL给 的第1 列x。因此,V3在这一步被删除。接下来,for 循环分配NULL给 的第 2 列x。但是,随着 V3 消失,第 2 列没有了。因此,x 不会受到影响。这就是为什么我们会得到意想不到的结果。
如果我们将df1和设置df2.b为data.table,则合并它们将引发错误。似乎data.table::merge对这种情况处理得更严格。错误消息将帮助我们避免获得意外结果。