【问题标题】:Is there a way to set variable labels of data frame using the map family?有没有办法使用地图系列设置数据框的变量标签?
【发布时间】:2021-11-04 11:23:26
【问题描述】:

我有一个数据集和随附的数据字典。我想使用数据字典来设置数据集的变量标签。我尝试使用显式的for loop,但它似乎很慢。有没有办法使用 tidyverse 的 map 家族来实现相同的目标?

library(tidyverse)

mydata <- tibble(
  a_1 = c(20,22, 13,14,44),
  a_2 = c(42, 13, 32, 31, 14),
  b = c("male", "female", "male", "female", "male"),
  c = c("Primary", "secondary", "Tertiary", "Primary", "Secondary")
)

dictionary <- tibble(
  variable = c("a", "b", "c"),
  label = c("Age", "Gender", "Education"),
  type = c("mselect", "select", "select")

)


variables <- names(mydata)


for (var in variables){

  vm <- unique(str_remove_all(var, "_.*")) # Take care of the variables with _

  varlbl <- filter(dictionary, variable == vm) %>%
    select(label) %>% pull


    attr(mydata[[var]], "label") <- varlbl
}


#---- Map the variable labels using map
#

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    基础 R

    mydata[] <- Map(
      function(x, lbl) if (!is.na(lbl)) `attr<-`(x, "label", lbl) else x, 
      mydata, dictionary$label[ match(gsub("_.*", "", names(mydata)),
      dictionary$variable) ])
    str(mydata)
    # tibble [5 x 4] (S3: tbl_df/tbl/data.frame)
    #  $ a_1: num [1:5] 20 22 13 14 44
    #   ..- attr(*, "label")= chr "Age"
    #  $ a_2: num [1:5] 42 13 32 31 14
    #   ..- attr(*, "label")= chr "Age"
    #  $ b  : chr [1:5] "male" "female" "male" "female" ...
    #   ..- attr(*, "label")= chr "Gender"
    #  $ c  : chr [1:5] "Primary" "secondary" "Tertiary" "Primary" ...
    #   ..- attr(*, "label")= chr "Education"
    

    mydata[] &lt;- 的重新分配是有意的,并且是一个小技巧:如果我们执行 mydata &lt;-(没有括号),那么 Map 返回一个 list 并且“框架”属性会丢失。但是,mydata[] &lt;- 用新数据重新分配 contents(列),替换以列表/框架的形式出现,mydata 类似框架的属性被保留。

    当我想(例如)将列的子集转换为其他内容时,我经常使用它。我可能会做somedata[3:6] &lt;- lapply(somedata[3:6], as.numeric),我认为它比其他方法更具可读性来获得相同的效果。

    咕噜声

    library(dplyr) # just for %>% here
    library(purrr)
    mydata <- map2_dfc(
      mydata,
      dictionary$label[ match(gsub("_.*", "", names(mydata)), dictionary$variable) ],
      ~ `attr<-`(.x, "label", .y))
    

    对于两者,我使用的是“作弊”快捷方式:这两者是等价的:

    {
      attr(x, "label") <- "something"
      x
    }
    
    ## is equivalent to
    
    {
      `attr<-`(x, "label", "something")
    }
    

    因为它们都返回更新后的x。这有点像代码高尔夫,有点美感(减少对分号和大括号的要求),但如果您愿意,可以轻松转换为更传统的(第一种)方法。

    【讨论】:

    • 天才!这正是我想要的。我会做一个基准测试以达到峰值
    【解决方案2】:

    labelVector 包是另一种选择,虽然不如Map 快,但在视觉上更容易一些(至少我是这么认为的):

    library(labelVector)
    
    idx <- match(gsub("_.*", "", names(mydata)), dictionary$variable)
    var_label <- dictionary$label[idx]
    names(var_label) <- names(mydata)
    
    mydata <- set_label(mydata, .dots = var_label)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-27
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多