将列名整理成变量

Tidying column names into variables

我有一个来自调查的非常混乱的数据集,其中每个复选框都是一个指示变量。因此,不是将性别(或种族)作为以 M/F 作为条目的变量,而是 gender_m 和带有指示符的 gender_f 列。

简化示例:

df <- tribble(
  ~id, ~gender_m, ~gender_f,
  #--|----------|---------
  1L , 0        , 1,
  2L , 1        , 0,
  3L , 0        , 0,
  4L , 1        , 1
  )

我想要的输出是:

  result <- tribble(
    ~id, ~gender,
    #--|----------
  1L , 'f',
  2L , 'm',
  3L , 'Missing',
  4L , 'More than 1 selected'
)

对于只有 2 列的性别之类的东西,硬编码很容易,但我试图让它尽可能通用,因为种族(或您使用的编程语言)之类的东西有多种可能性。

我有近千列但实际变量不到20个。所有列的形式都是 <variable_name>_<potential_value>.

我确定我错过了执行此操作的一些整洁函数,但我的 googlefu 今天似乎很弱。

许多 tidy 函数在列中比在行中工作得更好,所以如果您转换为 long,这会变得更容易一些:

df_long = df %>%
    gather(Item, Response, starts_with("gender"))

cleaned = df_long %>%
    mutate(Item = str_match(Item, "(.*)_(.*)")[, 3]) %>%
    group_by(id) %>%
    summarize(RespCleaned = case_when(
        sum(Response) == 0 ~ "Missing",
        sum(Response) == 1 ~ Item[Response == 1][1],
        sum(Response) > 1 ~ "More than 1 selected"
    ))

df = df %>% left_join(cleaned, by = "id")

如果您有很多具有此类 0/1 响应指标的项目,则使用响应总和应该可以推广到具有 2 个以上选项的项目。您只需要将 starts_with("gender") 替换为另一个选择器,而不是选择相关列。

这是一个基本方法(stringr除外)。应该很好地推广到类似的情况,并且很容易放入一个函数中。按原样,它可以使用 1000 列中的 20 个变量对整个数据框进行操作。

library(stringr)
sep = "_"
vars = unique(na.omit(str_extract(names(df), ".*(?=_)")))

for (i in seq_along(vars)) {
    these_vars = names(df)[str_detect(names(df), paste0("^", vars[i]))]
    result = character(nrow(df))
    rs = rowSums(df[these_vars])
    result[rs == 0] = "mising"
    result[rs > 1] = "more than 1 selected"
    result[rs == 1] = these_vars[apply(df[rs == 1, these_vars] == 1, 1, which)]
    df[i] = result
}

df
# # A tibble: 4 x 4
#      id gender_m gender_f               gender
#   <int>    <dbl>    <dbl>                <chr>
# 1     1        0        1             gender_f
# 2     2        1        0             gender_m
# 3     3        0        0               mising
# 4     4        1        1 more than 1 selected