Evaluation Error when tidyverse is loaded after Hmisc

本小妞迷上赌 提交于 2019-12-03 11:27:14

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).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!