将列名整理成变量
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
我有一个来自调查的非常混乱的数据集,其中每个复选框都是一个指示变量。因此,不是将性别(或种族)作为以 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