dplyr bind_rows 不保留变量标签

问题描述 投票:0回答:5

haven::read_dta
支持使用
label
属性将变量标签从Stata导入到R中。 Rstudio 还支持在“视图”窗格中显示这些标签。

但是,当使用

dplyr::bind_rows
(或
rbind_all
)绑定两个数据框时,不会保留标签。这是一个错误吗?

library(dplyr)
id <- 1:5
attr(id, "label") <- "unit id"

df1 <- tbl_df(data.frame(id)) # label is fine
df1$id
# [1] 1 2 3 4 5
# attr(,"label")
# [1] "unit id"

df2 <- tbl_df(data.frame(id)) # label is fine
df2$id
# [1] 1 2 3 4 5
# attr(,"label")
# [1] "unit id"

df_bound <- bind_rows(df1, df2) # label is gone
df_bound$id
# [1] 1 2 3 4 5 1 2 3 4 5
r dplyr r-haven
5个回答
2
投票

解决方法是使用

rbind
而不是
bind_rows
。然后,您必须确保列名称相同。

使用

setdiff(names(df1), names(df2))
获取位于
df1
中但不在
df2
中的列名称,
setdiff(names(df2), names(df1))
反之亦然。


2
投票

sjmisc::add_rows
dplyr::bind_rows
具有类似的语法,并保留变量和值标签属性。


1
投票

Daniel Lüdecke

sjlabelled 包是处理标记数据时出现的此类问题的一个很好的解决方案。我使用 copy_labels 函数来解决类似的问题:

library(dplyr) library(sjlabelled) id <- 1:5 attr(id, "label") <- "unit id" df1 <- tbl_df(data.frame(id)) str(df1) # tibble [5 × 1] (S3: tbl_df/tbl/data.frame) # $ id: int [1:5] 1 2 3 4 5 # ..- attr(*, "label")= chr "unit id" df2 <- tbl_df(data.frame(id)) # label is fine df_bound <- bind_rows(df1, df2) # label is gone str(df_bound) # tibble [10 × 1] (S3: tbl_df/tbl/data.frame) # $ id: int [1:10] 1 2 3 4 5 1 2 3 4 5 df_bound <- copy_labels(df_bound, df1) df_bound_labelled <- df_bound %>% mutate_at(vars(id), as_labelled) str(df_bound_labelled) # tibble [10 × 1] (S3: tbl_df/tbl/data.frame) # $ id: int [1:10] 1 2 3 4 5 1 2 3 4 5 # ..- attr(*, "label")= chr "unit id"



0
投票
labelled

包,特别是由 Daniel Ludecke (

sjlabelled
) 和 Hadley Wickham 撰写。
假设 

df.ls

,使用

haven::read_dta
导入的数据框列表,它们具有大量共同变量,但不是全部。在这种情况下,使用
dplyr::bind_rows
很方便,它不需要在所有数据框中具有相同的变量(列)。正如OP所提到的,问题在于它“删除”了标签。我要补充的是,这仅适用于列表数据帧通用的变量。当某些变量位于某些数据框中但不在其他数据框中时,它们会保留其标签。
我们可以使用

提取“丢失”的标签

common_col_names <- ## get the names of the columns common to all the dfs Reduce(intersect, lapply(df.ls,names)) library(labelled) labs.ls <- ## a list of lists lapply( df.ls, function(x) { labelled::var_label( x[, common_col_names], unlist = FALSE ) } )

假设给定变量在 
df.ls

的所有数据帧中保持相同的标签。使用

common_col_names
以及标签恒定的假设,意味着
labs.ls
的所有元素(列表)都是相同的。
设置

unlist = FALSE

(默认值)允许在列表中拥有不同的标签(而不是字符向量),这反过来又允许以下操作(来自

labelled
文档):``对于数据帧,如果值为命名列表,仅考虑名称与数据框的列匹配的元素。如果 value 是字符向量,标签的顺序应与 data.frame 的列的顺序相同。如果列表中所有数据帧的列/变量不相同,这会非常方便。
请注意,检查 

labs.ls

对于检查标签在数据帧中是否实际上保持相同非常有用。

然后您只需绑定列表中的不同数据框并分配提取的标签:

df <- dplyr::bind_rows(df.ls) labelled::var_label(df) <- labs.ls[[1]]

这里我们使用 
labs.ls[[1]]

,但由于我们只考虑所有数据帧共有的变量,并且我们假设这些变量的标签是恒定的,请注意,可以使用 2, 3, ...,

length(df.ls)
代替 1。
    


0
投票

我可以确认

rbind

不会
保留因子变量的变量标签,因此并不是适合所有人的解决方案。它适用于日期时间、数字和字符,但所有因子变量都会丢失其标签,即使变量名称绝对相等。

© www.soinside.com 2019 - 2024. All rights reserved.