我有一个数据集,其中包含大量表示过程代码的字符串列变量。还有另一列代表编码格式的变量(有些是ICD9,有些是其他比较神秘的格式)。每个观察结果都是一个病人。我需要:
要通过c(“ cd1”,“ cd2”,...)手动创建每个变量的列表,它的变量太多了,我可能需要做很多次不同的事情,所以我希望将其作为一般解决方案。
这是一个简化的示例,我需要搜索的字符串以“ 231”开头:
ID cd1 type1 cd2 type2 cd3 type3 cd4 type4
1 "231" "02" "219" "02" "1321" "02" "2314" "02"
2 "222" "02"
3 "123" "142"
4 "145" "02" "521" "02" "2313" "02"
5 "231" "01"
我想要的输出是:
ID cd1 type1 cd2 type2 cd3 type3 cd4 type4 flag_var
1 "231" "02" "219" "02" "1321" "02" "2314" "02" 1
2 "222" "02" 0
3 "123" "142" 0
4 "145" "02" "521" "02" "2313" "02" 1
5 "231" "01" 0
(ID#5设置为0,因为即使cd1代码为“ 231”,type1变量也为“ 01”,因此格式不正确”)
在使用mutate和case_when时,我已经取得了一定的成功:
df <- df %>%
mutate(flag_var = case_when(
startsWith(cd1, "231") ~ 1,
startsWith(cd2, "231") ~ 1,
startsWith(cd3, "231") ~ 1,
startsWith(cd4, "231") ~ 1,
TRUE ~ 0))
就像我说的那样,实际的数据集具有太多的变量,并且可能对其进行潜在的搜索,因此无法以上述方式对其进行硬编码。我认为应该使用mutate_at或另一个dplyr函数来执行此操作,但是我还无法弄清楚。
我已经能够使用以下代码来获取一组等于1或0的新变量,但不能获得单个变量。然后,我可以使用rowSums对所有列求和,并检查该值是否为非零。但这很丑陋且费力:
df <- df %>% mutate_at(vars(starts_with("cd")),
funs(testvar = ifelse(startsWith(., "231"), 1, 0)))
test_names = df %>% select(ends_with("_testvar")) %>% names()
df <- df %>% mutate(flag_var = (rowSums(.[test_names]) == 1))
df <- df %>% select(-ends_with("_testvar"))
有人有更简单的想法吗?非常感谢!
编辑:我意识到我还必须合并编码类型变量。初始样本数据表已经过编辑以反映这一点。
答案 0 :(得分:1)
这可能会回答问题,还是您需要将0-1作为行值?
library(tidyverse)
dat <- tribble(~ID, ~cd1, ~cd2, ~cd3, ~cd4,
1, "231", "219", "1321", "2314",
2, "222", "" , "" , "",
3, "123", "142", "" , "",
4, "145", "521", "2313", "122")
dat %>%
gather("cd_type", "code", 2:5) %>%
mutate(flag_var = case_when(
startsWith(code, "231") ~ 1,
TRUE ~ 0
))
#> # A tibble: 16 x 4
#> ID cd_type code flag_var
#> <dbl> <chr> <chr> <dbl>
#> 1 1 cd1 231 1
#> 2 2 cd1 222 0
#> 3 3 cd1 123 0
#> 4 4 cd1 145 0
#> 5 1 cd2 219 0
#> 6 2 cd2 "" 0
#> 7 3 cd2 142 0
#> 8 4 cd2 521 0
#> 9 1 cd3 1321 0
#> 10 2 cd3 "" 0
#> 11 3 cd3 "" 0
#> 12 4 cd3 2313 1
#> 13 1 cd4 2314 1
#> 14 2 cd4 "" 0
#> 15 3 cd4 "" 0
#> 16 4 cd4 122 0
或者执行此操作以恢复原始的宽格式
dat %>%
gather("cd_type", "code", 2:5) %>%
mutate(flag_var = case_when(
startsWith(code, "231") ~ 1,
TRUE ~ 0
)) %>%
spread(cd_type, code) %>%
select(ID, cd1:cd4, flag_var)
#> # A tibble: 6 x 6
#> ID cd1 cd2 cd3 cd4 flag_var
#> <dbl> <chr> <chr> <chr> <chr> <dbl>
#> 1 1 <NA> 219 1321 <NA> 0
#> 2 1 231 <NA> <NA> 2314 1
#> 3 2 222 "" "" "" 0
#> 4 3 123 142 "" "" 0
#> 5 4 145 521 <NA> 122 0
#> 6 4 <NA> <NA> 2313 <NA> 1
由reprex package(v0.2.1)于2019-01-19创建
答案 1 :(得分:0)
这是另一种解决方案:
df$flag_var <- 1*(rowSums(substring(as.matrix(df[, 2:ncol(df)]), 1, 3) == '231') > 0)
# ID cd1 cd2 cd3 cd4 flag_var
# 1 1 231 219 1321 2314 1
# 2 2 222 0
# 3 3 123 142 0
# 4 4 145 521 2313 122 1
对于更新后的示例,由于cd
列和type
列是成对的,因此以下代码应该起作用:
cd.cols <- grepl('^cd', colnames(df))
type.cols <- grepl('^type', colnames(df))
flag <- substring(as.matrix(df[,cd.cols]), 1, 3) == '231' & df[,type.cols] == '02'
df$flag_var <- 1 * (rowSums(flag) > 0)
# > df
# ID cd1 type1 cd2 type2 cd3 type3 cd4 type4 flag_var
# 1 1 231 02 219 02 1321 02 2314 02 1
# 2 2 222 02 0
# 3 3 123 142 0
# 4 4 145 02 521 02 2313 02 1
# 5 5 231 01 0
答案 2 :(得分:0)
我们可以遍历各列,并与grepl
的{{1}},Reduce
和list
部分匹配到单个逻辑vector
并强制二进制值
vector
df$flag_var <- +(Reduce(`|`, lapply(df[-1], grepl, pattern = '^231')))