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
解决方法是使用
rbind
而不是 bind_rows
。然后,您必须确保列名称相同。
使用
setdiff(names(df1), names(df2))
获取位于 df1
中但不在 df2
中的列名称,setdiff(names(df2), names(df1))
反之亦然。
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"
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。我可以确认
rbind
将
不会保留因子变量的变量标签,因此并不是适合所有人的解决方案。它适用于日期时间、数字和字符,但所有因子变量都会丢失其标签,即使变量名称绝对相等。