【问题标题】:How Can I Confirm that Two R objects have the same structure?如何确认两个 R 对象具有相同的结构?
【发布时间】:2015-09-04 13:52:26
【问题描述】:

我下面的测试不起作用。任何人都可以提出不同的方法吗?

===不同的内容,相同的结构,想要“true”进行比较

> x<-c(1,2,3)
> y<-x
> identical(str(x),str(y))
 num [1:3] 1 2 3
 num [1:3] 1 2 3
[1] TRUE
> y[3]<-999
> identical(str(x),str(y))
 num [1:3] 1 2 3
 num [1:3] 1 2 999
[1] TRUE
> str(x)
 num [1:3] 1 2 3
> str(y)
 num [1:3] 1 2 999
> 

但这种方法是错误的,因为它说 x 和 z 具有相同的结构!

> z<-list("a","b")
> identical(str(x),str(z))
 num [1:3] 1 2 3
List of 2
 $ : chr "a"
 $ : chr "b"
[1] TRUE

我正在尝试这个,因为我需要一种方法来确认我构造的 R 对象与 R 包示例中提供的类型完全相同。

【问题讨论】:

  • str 返回NULL(你看到的只是打印出来的,没有返回),所以你总是在比较两个相同的空值。只需使用identical(x,y)
  • 您正在比较来自 str 的对象而不是元素本身...
  • 问题措辞不是最清楚的,但我读到它是在询问如何测试两个对象是否具有相同的结构,即使它们的内容可能不同,这是一个相当困难的问题。
  • > x y 相同(x, y) [1] 真 > y[3] 相同(x, y) [1] 假
  • @A.韦伯 我知道我已经晚了四年,但请看我的回答stackoverflow.com/a/59340383/8436923

标签: r object compare structure


【解决方案1】:

问这个问题已经有一段时间了,但我一直在解决类似的问题。

想出了这个功能作为解决方案:

CompareStructure <-
  function(x, y) {
    # function to recursively compare a nested list of structure annotations
    # using pairwise comparisons
    TypeCompare <-
      function(xSTR, ySTR) {
        if (length(xSTR) == length(ySTR)) {
          all(mapply(
            xSTR,
            ySTR,
            FUN = function(xValue, yValue) {
              if (is.list(xValue) && is.list(yValue)) {
                all(TypeCompare(xValue, yValue))
              } else if (is.list(xValue) == is.list(yValue)) {
                identical(xValue, yValue)
              } else {
                FALSE
              }
            }
          ))
        } else {
          FALSE
        }
      }

    # if both inputs are lists
    if (is.list(x) && is.list(y)) {
      # use Rapply to recursively apply function down list
      xSTR <-
        rapply(
          x,
          f = function(values) {
            c(mode(values), length(values))
          },
          how = "list"
        )

      # use Rapply to recursively apply function down list
      ySTR <-
        rapply(
          y,
          f = function(values) {
            c(mode(values), length(values))
          },
          how = "list"
        )

      # call the compare function on both structure annotations
      return(TypeCompare(xSTR, ySTR))

    } else {
      # if inputs are not same class == automatic not same structure
      if (class(x) != class(y)) {
        FALSE
      } else {
        # get dimensions of the x input, if null get length
        xSTR <-
          if (is.null((dimsX <- dim(x)))) {
            length(x)
          } else {
            dimsX
          }

        # get dimensions of the y input, if null get length
        ySTR <-
          if (is.null((dimsY <- dim(y)))) {
            length(y)
          } else {
            dimsY
          }

        # call the compare function on both structure annotations
        return(TypeCompare(xSTR, ySTR))
      }
    }
  }

比较嵌套列表中元素的模式和长度以及非列表对象的类和维度

【讨论】:

    【解决方案2】:

    这个答案很晚,但可以帮助面临同样问题的访问者。

    我需要一种方法来确认我构造的 R 对象与 [...] 具有完全相同的类型

    对于这种特定情况,请考虑typeof()但是,这可能不是您想要的。

    要检查 data.frame 中的向量类型是否匹配,请查看sapply(df, typeof)

    对于更通用的解决方案,我建议自己构建检查,因为对于每个用例,“结构”可能有不同的含义。它只是关于类型吗?您想区分doubleinteger 吗?或者也检查 data.frame 的名称?还是它的尺寸?如果除了一个因素的水平之外一切都相同怎么办?

    自己构建有一个很大的优势:你知道发生了什么。

    其他有用的函数还有dim()ncol()nrow()names()class()attributes()mode()

    【讨论】:

    • typeof非常广泛的,对于这个问题几乎没有用处。例如,如果两个 S3 对象 AB 都是具有类属性的列表,则 typeof(A) == typeof(B) == "list"
    • 例如:typeof(lm(mpg ~ ., mtcars)) == typeof(rpart(mpg ~ ., mtcars))
    • 这就是为什么我说:“但是,这可能不是你想要的。”请阅读我的其余答案。
    【解决方案3】:

    我正在回答a comment中提出的这个问题的版本,即如何测试两个对象是否具有相同的类型、类、名称和其他属性,尽管可能有不同的数据。例如,您可能想要确认两个矩阵具有相同的维度、相同的行名和列名,并且属于相同的类型。

    SameStruc <- function(x, y) identical(`is.na<-`(x), `is.na<-`(y))
    

    我们可以在两个矩阵上进行测试:

    M1 <- matrix(1:30, 3, 10, dimnames=list(LETTERS[1:3], letters[1:10]))
    M2 <- M1
    M2[1:30] <- 129:100
    SameStruc(M1, M2)  # TRUE
                       # M1 and M2 are both integer matrices, 3 x 10, with the same dimnames but different data
    M3 <- M1
    M3[3,5] <- 1 * M3[3,5]
    all(M1 == M3)      # TRUE  (the numerical values of the contents of M1 and M3 are the same)
    SameStruc(M1, M3)  # FALSE (M3 has type "double" while M1 has type "integer")
    

    我没有在列表、数据框或除矩阵之外的任何对象上测试过此函数。不过,我认为它应该可以工作,但条件是在列表上它只会测试最外层的列表结构,而不是测试每对列表元素的结构。

    我还假设这个函数对于大型对象效率很低,因为它会为每个填充了 NA 的对象创建一个副本。

    【讨论】:

      【解决方案4】:

      现在我们在 quiver 中有一个名为 Waldo 的新选项,它可以更强大的方式解决您的问题。但是,我仍然认为您可能需要编写自己的比较函数,以便了解发生了什么。

      > library('waldo')
      > x <- c(1,2,3)
      > y <- x
      > compare(x, y)
      ✓ No differences
      > y[3] <- 999
      > compare(x, y)
      `old`: 1 2   3
      `new`: 1 2 999
      

      【讨论】:

        【解决方案5】:

        函数 dput() 用于结构。

        x <- c(1, 2, 3)
        y <- x
        identical(dput(x), dput(y))
        # c(1, 2, 3)
        # c(1, 2, 3)
        # [1] TRUE
        
        z <- list("a", "b")
        identical(dput(x), dput(z))
        # c(1, 2, 3)
        # list("a", "b")
        # [1] FALSE
        

        【讨论】:

        • 不幸的是,内容也是如此! > x y 相同(dput(x), dput(y)) c(1, 2, 3) c(1, 2, 3) [1] 真> > y[3] 相同(dput(x), dput(y)) c(1, 2, 3) c(1, 2, 999) [1] FALSE
        猜你喜欢
        • 2017-04-25
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        • 2018-03-23
        • 2019-07-14
        • 1970-01-01
        • 2017-02-11
        • 1970-01-01
        相关资源
        最近更新 更多