我认为这最终源于 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 中提到的 names 和 row.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)