【问题标题】:Behavior of function "identical" with factors函数的行为与因子“相同”
【发布时间】:2016-06-03 00:23:23
【问题描述】:

R 将因子存储为整数。因此,当使用相同的函数时,如果两个因子具有不同的级别,则无法找到它们何时同名。

这是一个 MWE:

y <- structure(list(portfolio_date = structure(c(1L, 1L, 1L, 2L, 2L, 
2L), .Label = c("2000-10-31", "2001-04-30"), class = "factor"), 
security = structure(c(2L, 2L, 1L, 3L, 2L, 4L), .Label = c("Currency Australia (Fwd)", 
"Currency Euro (Fwd)", "Currency Japan (Fwd)", "Currency United Kingdom (Fwd)"
), class = "factor")), .Names = c("portfolio_date", "security"
), row.names = c(10414L, 10417L, 10424L, 21770L, 21771L, 21774L
), class = "data.frame")

x <- structure(list(portfolio_date = structure(1L, .Label = "2000-10-31", class = "factor"), 
security = structure(1L, .Label = "Currency Euro (Fwd)", class = "factor")),
 .Names = c("portfolio_date", "security"), row.names = 10414L, class = "data.frame")

identical(y[1,], x)

返回FALSE

但是如果我们查看对象,它们看起来与用户相同

y[1,]
portfolio_date            security
10414     2000-10-31 Currency Euro (Fwd)

x
portfolio_date            security
10414     2000-10-31 Currency Euro (Fwd)

最终我希望能够执行以下操作:

apply(y, 1, identical, x)
10414 10417 10424 21770 21771 21774 
TRUE TRUE FALSE FALSE FALSE FALSE 
which(apply(y, 1, identical, x))
1 2

关于如何实现这一点的任何建议?谢谢。

【问题讨论】:

  • identical(droplevels(y[1,]), droplevels(x)) 或者all.equal(y[1,], x, check.attributes=F)
  • 感谢您的尝试,但使用相同的 droplevels 仍然返回 FALSE。此外,apply(y, 1, function(z) all.equal(z, x, check.attributes=F)) 有一些奇怪的输出。
  • 您必须将列转换为字符。这是一个使用基数 R 的一行中的解决方案:apply(apply(y, 2, as.character), 1, same, apply(x, 2, as.character))
  • 谢谢@Dave2e,你能把它列为答案以便我接受吗?
  • identical(droplevels(y[1,]), droplevels(x)) 返回 TRUE。请再次检查:)

标签: r


【解决方案1】:

一种选择是使用dplyr 中的rowwise 逐行检查;如果您需要同时比较row.names,则需要为两者创建一个id 列,否则它将返回前两行的TRUE

library(dplyr)
x$id <- row.names(x)
y$id <- row.names(y)
rowwise(y) %>% do(check = isTRUE(all.equal(., x, check.attributes = F))) %>% data.frame

  check
1  TRUE
2 FALSE
3 FALSE
4 FALSE
5 FALSE
6 FALSE

【讨论】:

    【解决方案2】:

    为了进行比较,需要将因子转换为字符对象。 在这里单独使用基础 R 是一个解决方案:

    apply(apply(y, 2, as.character), 1, identical, apply(x, 2, as.character))
    

    内部应用循环将源数据帧和目标数据帧中的每一列转换为字符对象,外部应用循环遍历行。 如果 x 数据框超过一行,实际行为可能与预期不同。

    【讨论】:

      【解决方案3】:

      使用“比较”包。

      library(compare)
      result <- NULL
      for (i in 1:NROW(y)){ 
      one <- compare(y[i,], x, dropLevels=T)
      two <- one$detailedResult[1]==T & one$detailedResult[2]==T
      result <- c(result, two)
      }
      as.character(result)#TRUE  TRUE FALSE FALSE FALSE FALSE
      

      【讨论】:

        【解决方案4】:

        OP 中发布数据的解决方案

        OP 中发布的示例可以使用droplevels() 轻松处理。

        我们先看看为什么比较identical(y[1,], x)会返回FALSE

        str(y[1,]) 
        #'data.frame':  1 obs. of  2 variables:  
        #$ portfolio_date: Factor w/ 2 levels "2000-10-31","2001-04-30": 1  
        #$ security      : Factor w/ 4 levels "Currency Australia (Fwd)",..: 2
        

        str(x)
        #'data.frame':  1 obs. of  2 variables:
        #$ portfolio_date: Factor w/ 1 level "2000-10-31": 1
        #$ security      : Factor w/ 1 level "Currency Euro (Fwd)": 1 
        

        所以区别在于因素,即使两个对象以相同的方式显示,如 OP 的问题所示。

        这是函数droplevels() 有用的地方:它删除了未使用的因素。通过将droplevels() 应用到y[1,] 及其冗余因子,我们得到:

        identical(droplevels(y[1,]), x)
        #[1] TRUE
        

        如果x 还包含未使用的因子,则也有必要将其包装到droplevels() 中。无论如何,它不会造成任何伤害:

        identical(droplevels(y[1,]), droplevels(x))
        #[1] TRUE
        

        一般解决方案

        如果实际数据比 OP 的“MWE”中发布的数据更复杂,则使用 droplevels() 可能不起作用。此类情况可能包括,例如,xy[1,] 中存储为不同因子水平的等效条目。此答案末尾的 data 部分给出了 droplevels() 失败的示例。

        以下解决方案代表了处理此类一般情况的有效可能性。它适用于 OP 中发布的数据以及下面发布的数据的更复杂情况。

        首先,创建两个仅包含每行字符的辅助向量。通过使用paste(),我们可以将每一行连接成一个字符串:

        temp_x <- apply(x, 1, paste, collapse=",")
        temp_y <- apply(y, 1, paste, collapse=",")
        

        使用这些向量,可以轻松地比较原始 data.frames 的行,即使条目最初存储为具有不同级别和编号的因子。

        要识别哪些行是相同的,我们可以使用%in% 运算符,在这种情况下,它比函数identical() 更合适,因为前者检查所有可能的行组合的相等性,而不仅仅是单个对.

        通过这些简单的修改,可以快速获得所需的输出,而无需进一步的循环:

        setNames(temp_y %in% temp_x, names(temp_y))
        #10414 10417 10424 21770 21771 21774 
        # TRUE  TRUE FALSE FALSE FALSE FALSE 
        which(temp_y %in% temp_x)
        #[1] 1 2
        y[temp_y %in% temp_x,]
        #      portfolio_date            security
        #10414     2000-10-31 Currency Euro (Fwd)
        #10417     2000-10-31 Currency Euro (Fwd)
        

        数据

        x <- structure(list(portfolio_date = structure(1:2, .Label = c("2000-05-15", 
                     "2000-10-31"), class = "factor"), security = structure(c(2L, 1L), 
                     .Label = c("Currency Euro (Fwd)", "Currency USD (Fwd)"), 
                     class = "factor")), .Names = c("portfolio_date", "security"), 
                     class = "data.frame", row.names = c("10234", "10414"))
        
        y <- structure(list(portfolio_date = structure(c(1L, 1L, 1L, 2L, 2L, 2L),
                      .Label = c("2000-10-31", "2001-04-30"), class = "factor"), 
                      security = structure(c(2L, 2L, 1L, 3L, 2L, 4L), 
                      .Label = c("Currency Australia (Fwd)", "Currency Euro (Fwd)", 
                      "Currency Japan (Fwd)", "Currency United Kingdom (Fwd)"), 
                      class = "factor")), .Names = c("portfolio_date", "security"), 
                      row.names = c(10414L, 10417L, 10424L, 21770L, 21771L, 21774L), 
                      class = "data.frame")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-09-09
          • 2019-08-02
          • 2018-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多