【问题标题】:Strange behaviour for data.frames without column names没有列名的 data.frames 的奇怪行为
【发布时间】:2018-09-27 04:47:49
【问题描述】:

没有列名的 data.frames 存在意外行为。以下按预期工作:

df <- data.frame(a = 1:5, b = 5:9)
df + 1
##   a  b
## 1 2  6
## 2 3  7
## 3 4  8

但是如果我们删除列名,那么行为就会很奇怪:

names(df) <- NULL
df + 1
## data frame with 0 columns and 0 rows

如果用unnamesetNames 删除名称,也会发生同样的情况。关于为什么会发生这种情况以及它(出于某种原因)预期行为的任何想法?

编辑: 因此,据记录,无名 data.frames 的结果不受支持(感谢 @neilfws,@Suren),但我也对为什么会发生这种情况感兴趣。我尝试找到使这个简单示例停止运行的实际 c (?) 代码。

【问题讨论】:

  • 我现在能提供的最好的来自?data.frame:“列名应该是非空的,并且尝试使用空名将得到不受支持的结果。”所以从某种意义上说,这是意料之中的,但不知道数据帧如何工作的详细内部结构。
  • @Suren 当然可以,例如names(df) &lt;- letters[c(1,1)];df+1
  • “没有列名的 data.frames 出现了意外的行为。” 你期待什么?
  • 您可以在Ops.data.frame 中找到具体代码——0 长度的“名称”用于遍历列,从而生成0 列data.frame

标签: r dataframe


【解决方案1】:

data.frame 的文档中,它说:

列名应该是非空的,并且尝试使用空名将产生不受支持的结果。

因此,如果列名为空,则预期结果可能不是预期的。

【讨论】:

  • OP虽然没有空名,但根本没有名字
  • @Moody_Mudskipper 不是一回事吗?
  • 我的错,实际上,支持将两列命名为"",所以看起来它们的意思是NULL
  • @Suren 名称 可以 相同,这按预期工作:` data.frame(a = 1:5, a = 5:9, check.names =假)+ 1`
  • @alko989 是的,不知道为什么我什至没有检查。谢谢修复。
【解决方案2】:

我认为这最终源于 R 将data.frame 对象视为具有特定属性的列表:

## A list with no attributes
list_no_attr1 <- list(c(1,2,3), c(3,2,1))

## The attributes and class of the list
attributes(list_no_attr1)
#> NULL
class(list_no_attr1)
#> "list"

然后我们可以手动添加所有data.frame 属性而不改变list 的结构:

## Adding the names to the list (not in the attributes)
list2 <- list_no_attr1
attr(list2, "names") <- c("A", "B")

## The attributes and class of the list
attributes(list2)
#> $names
#> [1] "A" "B"
class(list2)
#> "list"

## Adding the "row.names" attributes
list3 <- list2
attr(list3, "row.names") <- c("1", "2", "3")

## The attributes and class of the list
attributes(list3)
#> $names
#> [1] "A" "B"
#> $row.names
#> [1] "1" "2" "3"

class(list3)
#> "list"

这仍然是一个列表。现在,当我们将对象的类更改为"data.frame" 时,它将使用data.frame 的S3 方法print 和所有其他相关函数

## Adding a data.frame class attribute
list_data_frame <- list3
attr(list_data_frame, "class") <- "data.frame"

## The attributes and class of the list
attributes(list_data_frame)
#> $names
#> [1] "A" "B"
#> $row.names
#> [1] "1" "2" "3"
#> $class
#> [1] "data.frame"

class(list_data_frame)
#> "data.frame"

这现在将打印为正确的data.frame。请注意,它的工作方式完全相同,如果我们删除类属性,它可以将data.frame 转换回list

## The dataframe
data_frame <-  data.frame("A" = c(1,2,3), "B" = c(3,2,1))
## The attributes and class of the list
attributes(data_frame)
#> $names
#> [1] "A" "B"
#> $row.names
#> [1] "1" "2" "3"
#> $class
#> [1] "data.frame"

class(data_frame)
#> "data.frame"

## "Converting" into a list
attr(data_frame, "class") <- NULL

attributes(data_frame)
#> $names
#> [1] "A" "B"
#> $row.names
#> [1] "1" "2" "3"

class(data_frame)
#> "list"

当然,它只有在列表中的元素长度相同时才有效:

## Creating an unequal list with data.frame attributes
wrong_list <- list(c(1,2,3), c(3,2,1,0))
attr(wrong_list, "names") <- c("A", "B")
attr(wrong_list, "row.names") <- c("1", "2", "3")
attr(wrong_list, "class") <- "data.frame"

wrong_list
#>   A B
#> 1 1 3
#> 2 2 2
#> 3 3 1
#> Warning message:
#> In format.data.frame(x, digits = digits, na.encode = FALSE) :
#>   corrupt data frame: columns will be truncated or padded with NAs

当省略其他 cmets 中提到的 namesrow.names 属性时,它也会出现错误并回答此问题:

## A list coerced into a data.frame without the right attributes
wrong_list <- list(c(1,2,3), c(3,2,1))
attr(wrong_list, "class") <- "data.frame"
wrong_list
#> NULL
#> <0 rows> (or 0-length row.names)

【讨论】:

  • 这是对 data.frames 如何成为幕后列表的详尽解释。但它并没有真正回答它为什么会中断的问题。该文档明确指出不支持无名 data.frames,但我想知道原因。我想得到一个警告,或者 R 会在内部暂时放置名称,然后在返回之前将其删除。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
相关资源
最近更新 更多