Identificando e criando nova variável por uma expressão regular

Prezados, Preciso de uma ajuda para resolver a seguinte questão: Possuo uma lista de nomes de medicamentos. Preciso identificar seus nomes em um vetor em que há informações de medicamentos preescritos. Para isso estou usando a função grep(). Após identificar, quero incluir no data frame uma nova coluna contendo o nome do medicamento da primeira lista. Segue um código reproduzível ##### Lista de medicamentos que guardei em um objeto chamado patterns patterns <- structure(c(1L, 2L, 3L, 4L, 6L, 7L, 5L, 8L, 9L, 10L, 11L), .Label = c("Oritavancina", "Oxacilina", "Pefloxacino", "Penicilina", "Pexiganan", "Piperacilina", "Piperacilina-tazobactam", "Pirazinamida", "Plazomicina", "Polimixina B", "Posilozid"), class = "factor") ### Amostra do Data frame em que preciso encontrar os nomes da lista acima df <- structure(list(nome = structure(c(9L, 11L, 3L, 3L, 7L, 2L, 4L, 5L, 8L, 6L, 10L, 1L), .Label = c("CLORETO DE POTASSIO DRAGEA 600MG", "CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML", "CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML", "HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL" ), class = "factor"), ID = c(13750598L, 13797248L, 13797248L, 13797248L, 13727853L, 13727853L, 13922033L, 13922033L, 13923030L, 13923030L, 13923030L, 13877978L), date = structure(c(1L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 5L, 6L), .Label = c("2021-01-01 00:08:14", "2021-01-01 00:20:39", "2021-01-01 00:22:18", "2021-01-31 23:53:48", "2021-01-31 23:58:50", "2021-01-31 23:59:47"), class = "factor")), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 583867L, 583868L, 583869L, 583870L, 583871L, 583872L), class = "data.frame") ### Usei esse código para identificar os medicamentos matches <- unlist(sapply(patterns, function(p) grep(p, df$nome, value = FALSE, ignore.case = TRUE) ) ) encontrados <- df[matches,] Porém além de identificar, quero incluir no df uma nova variável identificando o nome do medicamento que consta na lista (patterns) - como segue exemplo Abaixo: dados nome 1 ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML 2 PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL 3 CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML 4 CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML 5 FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML 6 CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML 583867 CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @ 583868 CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @ 583869 HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG 583870 DipiRONA SOLUCAO INJETAVEL 500MGML 2ML 583871 Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI 583872 CLORETO DE POTASSIO DRAGEA 600MG ID date Medicamento 1 13750598 2021-01-01 00:08:14 Não consta na lista 2 13797248 2021-01-01 00:20:39 *Piperacilina* 3 13797248 2021-01-01 00:20:39 Não consta na lista 4 13797248 2021-01-01 00:20:39 Não consta na lista 5 13727853 2021-01-01 00:22:18 Não consta na lista 6 13727853 2021-01-01 00:22:18 Não consta na lista 583867 13922033 2021-01-31 23:53:48 Não consta na lista 583868 13922033 2021-01-31 23:53:48 Não consta na lista 583869 13923030 2021-01-31 23:58:50 Não consta na lista 583870 13923030 2021-01-31 23:58:50 Não consta na lista 583871 13923030 2021-01-31 23:58:50 *Penicilina* 583872 13877978 2021-01-31 23:59:47 Outro medicamento

A primeira modificação que faria no seu *script* seria mudar a chamada a grep passando value para TRUE. Depois tratar os casos conforme sua nova especificação, que me parece muda a ordem da impressão do medicamento e coloca a substância à direita. *caveat lector* : conceito não testado‼ HTH -- Cesar Rabak On Fri, Mar 5, 2021 at 5:46 PM Felipe Barletta por (R-br) < r-br@listas.c3sl.ufpr.br> wrote:
Prezados,
Preciso de uma ajuda para resolver a seguinte questão:
Possuo uma lista de nomes de medicamentos. Preciso identificar seus nomes em um vetor em que há informações de medicamentos preescritos. Para isso estou usando a função grep(). Após identificar, quero incluir no data frame uma nova coluna contendo o nome do medicamento da primeira lista. Segue um código reproduzível
##### Lista de medicamentos que guardei em um objeto chamado patterns patterns <- structure(c(1L, 2L, 3L, 4L, 6L, 7L, 5L, 8L, 9L, 10L, 11L), .Label = c("Oritavancina", "Oxacilina", "Pefloxacino", "Penicilina", "Pexiganan", "Piperacilina", "Piperacilina-tazobactam", "Pirazinamida", "Plazomicina", "Polimixina B", "Posilozid"), class = "factor")
### Amostra do Data frame em que preciso encontrar os nomes da lista acima
df <- structure(list(nome = structure(c(9L, 11L, 3L, 3L, 7L, 2L, 4L, 5L, 8L, 6L, 10L, 1L), .Label = c("CLORETO DE POTASSIO DRAGEA 600MG", "CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML", "CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML", "HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL" ), class = "factor"), ID = c(13750598L, 13797248L, 13797248L, 13797248L, 13727853L, 13727853L, 13922033L, 13922033L, 13923030L, 13923030L, 13923030L, 13877978L), date = structure(c(1L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 5L, 5L, 6L), .Label = c("2021-01-01 00:08:14", "2021-01-01 00:20:39", "2021-01-01 00:22:18", "2021-01-31 23:53:48", "2021-01-31 23:58:50", "2021-01-31 23:59:47"), class = "factor")), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 583867L, 583868L, 583869L, 583870L, 583871L, 583872L), class = "data.frame")
### Usei esse código para identificar os medicamentos matches <- unlist(sapply(patterns, function(p) grep(p, df$nome, value = FALSE, ignore.case = TRUE) ) ) encontrados <- df[matches,]
Porém além de identificar, quero incluir no df uma nova variável identificando o nome do medicamento que consta na lista (patterns) - como segue exemplo Abaixo: dados nome 1 ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML 2 PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL 3 CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML 4 CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML 5 FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML 6 CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML 583867 CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @ 583868 CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @ 583869 HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG 583870 DipiRONA SOLUCAO INJETAVEL 500MGML 2ML 583871 Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI 583872 CLORETO DE POTASSIO DRAGEA 600MG ID date Medicamento 1 13750598 2021-01-01 00:08:14 Não consta na lista 2 13797248 2021-01-01 00:20:39 *Piperacilina* 3 13797248 2021-01-01 00:20:39 Não consta na lista 4 13797248 2021-01-01 00:20:39 Não consta na lista 5 13727853 2021-01-01 00:22:18 Não consta na lista 6 13727853 2021-01-01 00:22:18 Não consta na lista 583867 13922033 2021-01-31 23:53:48 Não consta na lista 583868 13922033 2021-01-31 23:53:48 Não consta na lista 583869 13923030 2021-01-31 23:58:50 Não consta na lista 583870 13923030 2021-01-31 23:58:50 Não consta na lista 583871 13923030 2021-01-31 23:58:50 *Penicilina* 583872 13877978 2021-01-31 23:59:47 Outro medicamento
_______________________________________________ R-br mailing list R-br@listas.c3sl.ufpr.br https://listas.inf.ufpr.br/cgi-bin/mailman/listinfo/r-br Leia o guia de postagem (http://www.leg.ufpr.br/r-br-guia) e forneça código mínimo reproduzível.

Você pode combinar sapply, grepl e apply. # Lista de medicamentos que guardei em um objeto chamado patterns. patterns <- c("Oritavancina", "Oxacilina", "Pefloxacino", "Penicilina", "Pexiganan", "Piperacilina", "Piperacilina-tazobactam", "Pirazinamida", "Plazomicina", "Polimixina B", "Posilozid") # Amostra do Data frame em que preciso encontrar os nomes da lista acima. df <- data.frame(nome = c("CLORETO DE POTASSIO DRAGEA 600MG", "CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML", "CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML", "HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL")) u <- sapply(patterns, FUN = grepl, x = df$nome) df$medicamento <- apply(u, MARGIN = 1, FUN = function(x) { # Tá sendo assumido que apenas 1 match ocorre. index <- head(which(x), n = 1) ifelse(length(index), names(index), NA_character_) }) Atenção! Se você tiver que fazer isso para muitos itens e muitos medicamentos onde no máximo um match é esperado, esse código tá caro porque ele avalia o match de cada produto (p produtos) com cada item (n itens) e retorna uma matriz n * p de valores lógicos. Você pode escrever a instrução de forma condicional: quando encontrar o primeiro match, passar para o próximo item. Vai ter que fazer um benchmark porque as instruções vetorizadas são rápidas e colocar condicionais em loops é um pouco lento. Tudo vai depender do p e n do seu problema. Outra opção é verificar se não tem como usar um "inner join with approximate matching". Confere o que tem no {stringdist} e {fuzzyjoin}. À disposição. Walmes.

Oi Walmes, Obrigado por postar sua solução. Achei bem interessante. Como disse tem um custo computacional alto, comparada a função fuzzyjoin::regex_left_join(): Apliquei ambas soluções em um conjunto de 583872 linhas: ################################################################################ system.time( u <- sapply(patterns, FUN = grepl, x = df$nome) ) + system.time( df$medicamento <- apply(u, MARGIN = 1, FUN = function(x) { # Tá sendo assumido que apenas 1 match ocorre. index <- head(which(x), n = 1) ifelse(length(index), names(index), NA_character_) }) ) usuário sistema decorrido 275.638 0.649 276.237
system.time( r <- fuzzyjoin::regex_left_join(df, Tabela_Antibiótico, by = "nome", ignore_case = TRUE) ) usuário sistema decorrido 2.579 0.000 2.578 dim(df) [1] 583872 11
Após aplicar ambas soluções notei que ainda há um problema quando o nome do medicamento é composto. Por exemplo, o Antibiótico de nome *PIPERACILINA-TAZOBACTAM* teve como resultado apenas o primeiro nome, veja a saída abaixo: [image: image.png] Tem alguma sugestão de como fazer o match quando o nome é composto? Em seg., 15 de mar. de 2021 às 11:00, Walmes Zeviani por (R-br) < r-br@listas.c3sl.ufpr.br> escreveu:
Você pode combinar sapply, grepl e apply.
# Lista de medicamentos que guardei em um objeto chamado patterns. patterns <- c("Oritavancina", "Oxacilina", "Pefloxacino", "Penicilina", "Pexiganan", "Piperacilina", "Piperacilina-tazobactam", "Pirazinamida", "Plazomicina", "Polimixina B", "Posilozid")
# Amostra do Data frame em que preciso encontrar os nomes da lista acima. df <- data.frame(nome = c("CLORETO DE POTASSIO DRAGEA 600MG", "CLORETO DE SODIO 0,9% SERINGA PREENCHIDA 5ML", "CLORETO DE SODIO SOLUCAO INJETAVEL 0,9% 10ML", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 10ML ISCMPA @", "CODEINA FOSFATO SOLUCAO ORAL 3MGML 5ML ISCMPA @", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "DipiRONA SOLUCAO INJETAVEL 500MGML 2ML", "FUROSEMIDA SOLUCAO INJETAVEL 10MGML 2ML", "HIDROCORTISONA SUCCINATO SODICO PO LIOFILO INJETAVEL 100MG", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "ONDANSETRONA CLORIDRATO SOLUCAO INJETAVEL 2MGML 4ML", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "Penicilina G BENZATINA PO LIOFILO INJETAVEL 1200000UI", "PIPERACILINA SODICA 4G + TAZOBACTAM SODICA 0,5G PO LIOFILO INJETAVEL"))
u <- sapply(patterns, FUN = grepl, x = df$nome) df$medicamento <- apply(u, MARGIN = 1, FUN = function(x) { # Tá sendo assumido que apenas 1 match ocorre. index <- head(which(x), n = 1) ifelse(length(index), names(index), NA_character_) })
Atenção! Se você tiver que fazer isso para muitos itens e muitos medicamentos onde no máximo um match é esperado, esse código tá caro porque ele avalia o match de cada produto (p produtos) com cada item (n itens) e retorna uma matriz n * p de valores lógicos. Você pode escrever a instrução de forma condicional: quando encontrar o primeiro match, passar para o próximo item. Vai ter que fazer um benchmark porque as instruções vetorizadas são rápidas e colocar condicionais em loops é um pouco lento. Tudo vai depender do p e n do seu problema.
Outra opção é verificar se não tem como usar um "inner join with approximate matching". Confere o que tem no {stringdist} e {fuzzyjoin}.
À disposição. Walmes.
_______________________________________________ R-br mailing list R-br@listas.c3sl.ufpr.br https://listas.inf.ufpr.br/cgi-bin/mailman/listinfo/r-br Leia o guia de postagem (http://www.leg.ufpr.br/r-br-guia) e forneça código mínimo reproduzível.
participantes (3)
-
Cesar Rabak
-
Felipe Barletta
-
Walmes Zeviani