没有列名的data.frames的奇怪行为

时间:2018-04-17 09:22:52

标签: r dataframe

没有列名的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.frame的结果不受支持(感谢@neilfws,@ Suren),但我也对发生这种情况的原因感兴趣。我试图找到实际的c(?)代码,使这个简单的例子制动。

2 个答案:

答案 0 :(得分:7)

data.frame的文档中,它说:

  

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

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

答案 1 :(得分:1)

我认为这最终来自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的{​​{1}}的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" 。请注意,它的工作方式完全相同,如果我们删除了class属性,可以将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 names属性以及此问题的答案,也会出现错误:

row.names