Evaluation Error when tidyverse is loaded after Hmisc

前端 未结 1 1924
死守一世寂寞
死守一世寂寞 2021-02-14 04:07

I am using r 3.3.3, dplyr 0.7.4, and Hmisc 4.1-1. I noticed that the order I load packages effects whether or not a dplyr::summaries function wold work or not. I understand that

相关标签:
1条回答
  • 2021-02-14 04:49

    UPDATE: As of haven version 2.0.0 this issue has been resolved, as the haven "labelled" class was renamed to "haven_labelled" to avoid conflicts with Hmisc.


    tl;dr: Order matters.

    For a more detailed answer, let's first reproduce the error:

    library(Hmisc)
    #> Loading required package: lattice
    #> Loading required package: survival
    #> Loading required package: Formula
    #> Loading required package: ggplot2
    #> 
    #> Attaching package: 'Hmisc'
    #> The following objects are masked from 'package:base':
    #> 
    #>     format.pval, units
    library(tidyverse)
    #> Warning: package 'forcats' was built under R version 3.4.4
    

    After removing elements piece by piece from the original summarise example, I managed to reduce reproducing the error to just these lines of code:

    Hmisc::label(iris$Petal.Width) <- "Petal Width"
    head(iris)
    #> Error: `x` and `labels` must be same type
    

    We can have a look at the traceback to see if we can locate a function that could be causing the error:

    traceback()
    #> 8: stop("`x` and `labels` must be same type", call. = FALSE)
    #> 7: labelled(NextMethod(), attr(x, "labels"))
    #> 6: `[.labelled`(xj, i)
    #> 5: xj[i]
    #> 4: `[.data.frame`(x, seq_len(n), , drop = FALSE)
    #> 3: x[seq_len(n), , drop = FALSE]
    #> 2: head.data.frame(iris)
    #> 1: head(iris)
    

    The [.labelled call looks suspicious. Why is it even called?

    lapply(iris, class)
    #> $Sepal.Length
    #> [1] "numeric"
    #> 
    #> $Sepal.Width
    #> [1] "numeric"
    #> 
    #> $Petal.Length
    #> [1] "numeric"
    #> 
    #> $Petal.Width
    #> [1] "labelled" "numeric" 
    #> 
    #> $Species
    #> [1] "factor"
    

    Ah, setting a label for Petal.Width with Hmisc::label also added the S3 class. We can inspect where the method is defined with getAnywhere:

    getAnywhere("[.labelled")
    #> 2 differing objects matching '[.labelled' were found
    #> in the following places
    #>   registered S3 method for [ from namespace haven
    #>   namespace:Hmisc
    #>   namespace:haven
    #> Use [] to view one of them
    

    Indeed, both haven and Hmisc define the method. And since haven is loaded after Hmisc, its definition is found first, and thus gets used:

    getAnywhere("[.labelled")[1]
    #> function (x, ...) 
    #> {
    #>     labelled(NextMethod(), attr(x, "labels"))
    #> }
    #> <environment: namespace:haven>
    

    haven expects labelled objects to have a labels attribute, which Hmisc::label doesn't create:

    attr(iris$Petal.Width, "labels")
    #> NULL
    

    And that's where the error comes from.


    But wait: why is haven even loaded? It's not attached with library(tidyverse). Turns out, that haven is listed as an imported package in tidyverse, which causes it to be loaded when the package is attached (see e.g. here). And loading a package, among other things, registers its S3 methods: which is where the conflict comes from.

    As it is, if you want to use both Hmisc and tidyverse, order matters. To address the issue further would likely require source level changes in the packages' use of the labelled S3 class.

    Created on 2018-03-21 by the reprex package (v0.2.0).

    0 讨论(0)
提交回复
热议问题