2
votes

R: créer une nouvelle colonne basée sur la chaîne correspondante dans plusieurs autres colonnes

J'ai un ensemble de données avec un très grand nombre de variables de colonne de chaîne représentant des codes de procédure. Il y a une autre colonne de variables qui représente le format de codage (certaines sont ICD9, d'autres sont d'autres formats plus obscurs). Chaque observation est un patient. Je dois:

  1. Rechercher dans chaque nom de variable avec un préfixe particulier
  2. Assurez-vous que le code utilisé est un code ICD9 (représenté par "02").
  3. Trouvez lequel de ces codes correspond aux 3 premiers caractères d'une chaîne particulière
  4. Créez une nouvelle variable de colonne = 1 si l'une des variables commence par ces trois caractères, et = 0 si aucune ne correspond

Il y a trop de variables pour qu'il soit trivial de créer une liste de chacune d'elles manuellement via c ("cd1", "cd2", ...), et j'ai potentiellement besoin de faire autant différentes fois, j'aimerais donc en faire une solution aussi générale que possible.

Voici un exemple simplifié, où les chaînes que je dois rechercher commencent par "231":

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"))

Le résultat que je voudrais est:

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))

(l'ID # 5 est mis à 0 car, même si le code cd1 est "231" , la variable type1 est "01" et donc pas dans le bon format de codage ")

J'ai quelque peu réussi à accomplir cela en utilisant mutate et case_when:

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


1 commentaires

C'est définitivement au-delà de mon package CRAN 'icd', et 'dplyr' est un bon outil pour le travail; juste un rappel que «icd» pourrait vous aider avec le prétraitement, la validation de code et les calculs de comorbidité plus compliqués dont vous pourriez avoir besoin.


3 Réponses :


1
votes

Cela peut répondre à la question ou avez-vous besoin de 0-1 comme valeurs de ligne?

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

Ou faites-le pour revenir au grand format d'origine

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


1 commentaires

Merci, cela semble être une méthode élégante. Vous pouvez voir à partir de votre exemple que cela ne renvoie pas les données inchangées. Les identifiants n ° 1 et n ° 4 ont désormais chacun deux observations lorsque les données sont renvoyées au format large. Le formulaire final de l'ensemble de données doit rester inchangé par rapport à la façon dont il a commencé, sauf avec l'ajout d'une nouvelle colonne. Est-ce possible avec votre méthode?



1
votes

Voici une autre solution:

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

Pour l'exemple mis à jour, puisque les colonnes cd et les colonnes type sont appariées, les éléments suivants le code devrait fonctionner:

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


1 commentaires

Merci beaucoup - cela fonctionne à merveille. J'ai réalisé qu'il y avait une autre faille dans mon ensemble de données, qui est qu'il y a une variable supplémentaire qui complique les choses (voir mon article original qui a été modifié).



1
votes

Nous pourrions parcourir les colonnes et faire une correspondance partielle avec grepl , Réduire la liste de vecteur s en un seul vecteur logique et contraindre les valeurs en données binaires

df <- structure(list(ID = c("1", "2", "3", "4"), cd1 = c("231", "222", 
"123", "145"), cd2 = c("219", "", "142", "521"), cd3 = c("1321", 
 "", "", "2313"), cd4 = c("2314", "", "", "122")), row.names = c(NA, 
 -4L), class = "data.frame")

df$flag_var <- +(Reduce(`|`, lapply(df[-1], grepl, pattern = '^231')))


0 commentaires