【问题标题】:Why does indexing with a single character index work on a data frame but not a matrix?为什么使用单个字符索引的索引适用于数据框而不适用于矩阵?
【发布时间】:2021-12-04 06:28:41
【问题描述】:

在数据帧中,[-indexing 可以使用单个字符执行。例如。 mtcars["mpg"].

另一方面,在矩阵上尝试相同的结果会得到NA,例如

m = cbind(A = 1:5, B = 1:5)
m["A"]
# NA

...暗示这是对矩阵进行子集化的一种无效方式。

这是正常的 R 行为吗?如果有,记录在哪里?

【问题讨论】:

  • 参见 Advanced R 的 subsetting。这一段解释了你在寻找什么
  • @Elia 这似乎不是指向特定段落的链接。如果您想引用相关部分并将其作为答案提交,那么我很乐意阅读。它可能不会回答我的“它在哪里记录”的问题,但它仍然会很好。
  • 对不起,我的意思是章节而不是段落。但是,Hadley 的 Advanced R 是从其基础学习 R 的最佳资源之一。我想在本章中你会发现很多关于向量、矩阵和列表子集的有用信息,它解释了三种不同子集运算符之间的区别。 @Gregor Thomas 的回答触及了其中一些论点
  • ?Extract 矩阵条目说:“空索引(逗号分隔的空白)表示选择了该维度中的所有条目。”和“通过每维一列 ...的字符矩阵进行索引”。类似结构部分的列表有不同的规则

标签: r matrix subset


【解决方案1】:

cbind() 默认创建一个矩阵。 mtcars 是一个数据框。

class(cbind(A = 1:5, B = 1:5))
# [1] "matrix" "array"

class(mtcars)
# [1] "data.frame"

由于数据框是由lists 列构建的,dataframe["column_name"],使用[ 中的一个参数,默认将数据框视为list,允许您选择列,与dataframe[, "column_name"].

matrix 没有这样的list 基础,因此如果您将[ 与一个参数一起使用,它不会假定您需要列。使用matrix[, "column_name"] 从矩阵中选择列。

cbind 是从头开始创建数据帧的不好方法。您可以指定cbind.data.frame(A = 1:5, B = 1:5),但使用data.frame(A = 1:5, B = 1:5) 更简单明了。但是,如果您要向现有数据框添加多列,则 cbind(my_data_frame, A = 1:5, B = 1:5) 很好,只要其中一个参数已经是数据框,就会生成数据框。

【讨论】:

    【解决方案2】:

    此行为记录在?"[",“矩阵和数组”部分:

    矩阵和数组是具有维度属性的向量,因此 索引的所有向量形式都可以与单个索引一起使用。

    这意味着如果您只使用单个索引,子集的对象将被视为没有维度的对象,因此如果索引是字符向量,该方法将查找 names 属性,该属性在这种情况(在您的矩阵上尝试names(m) 进行检查)。你在问题中所做的完全等同于(c(1:5, 1:5))["A"]。如果您改用双索引,则该方法将搜索 dimnames 属性到子集。即使令人困惑,matrix 也可能同时具有 namesdimnames。考虑一下:

    m<-matrix(c(1:5,1:5), ncol = 2, dimnames = list(LETTERS[1:5], LETTERS[1:2]))
    names(m)<-LETTERS[1:10]
    #check whether the attributes are set
    str(m)
    # int [1:5, 1:2] 1 2 3 4 5 1 2 3 4 5
    # - attr(*, "dimnames")=List of 2
    #  ..$ : chr [1:5] "A" "B" "C" "D" ...
    #  ..$ : chr [1:2] "A" "B"
    # - attr(*, "names")= chr [1:10] "A" "B" "C" "D" ...
    

    我们设置了rownamescolnamesnames。让我们对其进行子集化:

    #a column
    m[,"A"]
    #A B C D E
    #1 2 3 4 5
    
    #a row
    m["A",]
    # A B 
    #1 1
    
    #an element
    m["A"]
    #A 
    #1
    

    【讨论】:

    • 这个答案可能会受益于显示m 的打印方式。当读者可以看到m 时,您对m 进行子集化可能更容易理解。
    • 使用str(m) 的输出编辑,我认为它比print(m) 提供更多信息。
    【解决方案3】:

    这里有两种情况,

    m = cbind(A = 1:5, B = 11:15)
    typeof(m)
    "integer"
    

    typeof(mtcars)
    "list"
    

    所以阅读是不同的。第一种情况需要逗号,

    cbind(A = 1:5, B = 11:15)[,"A"]
    [1] 1 2 3 4 5
    

    【讨论】:

    • 我不喜欢这里的typeof - x = c(A = 1L, B = 2L)integer 类型的向量,但x["A"] 不需要逗号即可工作。 "integer" 类型没有任何迹象表明您需要一个逗号来对其进行子集化。重要的是它是一个二维数组,也就是一个矩阵,而 OP 想要对第二维进行子集化。
    猜你喜欢
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 2017-04-19
    • 2019-03-06
    • 2011-10-20
    相关资源
    最近更新 更多