7 Dados em strings (texto)

Neste capítulo, usaremos estes pacotes:

library(stringr)
library(literaturaBR) # remotes::install_github("sillasgonzaga/literaturaBR")

Manipulação de texto também é algo importante em ciência de dados, pois nem tudo são números, existem variáveis categóricas que são baseadas em texto. Mais uma vez, esse tipo de manipulação depende do tipo de arquivo que você receber.

a <- 'texto 1'
b <- 'texto 2'
c <- 'texto 3'
paste(a, b, c)
## [1] "texto 1 texto 2 texto 3"

O paste() é a função mais básica para manipulação de textos usando o R base. Ela concatena todas as variáveis textuais que você informar. Existe um parâmetro extra (sep) cujo valor padrão é espaço .

paste(a, b, c, sep = '-')
## [1] "texto 1-texto 2-texto 3"
paste(a, b, c, sep = ';')
## [1] "texto 1;texto 2;texto 3"
paste(a, b, c, sep = '---%---')
## [1] "texto 1---%---texto 2---%---texto 3"

7.1 Pacote stringr

Texto no R é sempre do tipo character. No universo da computação, também se referem a texto como string. E é daí que vem o nome desse pacote, também criado por Hadley Wickham. Por acaso, este pacote não está incluído no tidyverse.

library(stringr)
?stringr

Referências: Site do pacote stringr

7.1.1 Extrair parte de uma string

Começaremos pela função str_sub(), que extrai apenas parte de um texto.

cnae.texto <- c('10 Fabricação de produtos alimentícios', '11 Fabricação de bebidas',
                '12 Fabricação de produtos do fumo', '13 Fabricação de produtos têxteis',
                '14 Confecção de artigos do vestuário e acessórios',
                '15 Preparação de couros e fabricação de artefatos de couro, artigos para viagem e calçados',
                '16 Fabricação de produtos de madeira',
                '17 Fabricação de celulose, papel e produtos de papel')
cnae <- str_sub(cnae.texto, 0, 2)
texto <- str_sub(cnae.texto, 4)

cnae
## [1] "10" "11" "12" "13" "14" "15" "16" "17"
texto
## [1] "Fabricação de produtos alimentícios"                                                    
## [2] "Fabricação de bebidas"                                                                  
## [3] "Fabricação de produtos do fumo"                                                         
## [4] "Fabricação de produtos têxteis"                                                         
## [5] "Confecção de artigos do vestuário e acessórios"                                         
## [6] "Preparação de couros e fabricação de artefatos de couro, artigos para viagem e calçados"
## [7] "Fabricação de produtos de madeira"                                                      
## [8] "Fabricação de celulose, papel e produtos de papel"

7.1.2 Substituir caracteres em um string

Temos também a função str_replace() e str_replace_all(), que substituem determinados caracteres por outros. Tal como no exemplo a seguir:

telefones <- c('9931-9572', '8591-5772', '8562-1923')
str_replace(telefones, '-', '')
## [1] "99319572" "85915772" "85621923"
cnpj <- c('19.702.231/9999-98', '19.498.482/9999-05', '19.499.583/9999-50', '19.500.999/9999-46', '19.501.139/9999-90')
str_replace_all(cnpj, '\\.|/|-', '')
## [1] "19702231999998" "19498482999905" "19499583999950" "19500999999946" "19501139999990"

O que são esses símbolos no segundo exemplo? São símbolos especiais utilizados em funções textuais para reconhecimento de padrão. Esses símbolos são conhecidos como Expressões Regulares ou o famoso Regex, que veremos logo a seguir.

Uma função mais generalizada que str_replace() é a str_glue():

meu_nome <- "Fulano"

x <- c("Prazer, sou o {meu_nome}")
print(x)
## [1] "Prazer, sou o {meu_nome}"
str_glue(x)
## Prazer, sou o Fulano

7.1.3 Buscar correspondências em um string

A função str_count() pode ser usada para esse objetivo:

str_count(telefones, "7")
## [1] 1 2 0

Para saber se um string contem um determinado padrão, basta usar str_detect():

str_detect(telefones, "7")
## [1]  TRUE  TRUE FALSE
# isso é equivalente a 
str_count(telefones, "7") > 0
## [1]  TRUE  TRUE FALSE

Para correspondências mais específicas, como no início ou no final, pode-se usar as funções str_starts() e str_ends():

telefones
## [1] "9931-9572" "8591-5772" "8562-1923"
str_starts(telefones, "9")
## [1]  TRUE FALSE FALSE
str_ends(telefones, "0")
## [1] FALSE FALSE FALSE

7.1.4 Complementar uma string

Isso é essencialmente útil para transformar números em string sem perder a ordem alfabética. str_pad() adicionar um determinado character no início (ou no final, isso pode ser especificado pelo usuário) até que um string atinja uma determinada quantidade de caracteres.

Por exemplo, sabe-se que um CPF, contando apenas os algarismos, contem 11 caracteres. Contudo, o que fazer quando você recebe um dado numérico, sem zeros a esquerda? Veja o exemplo abaixo:

cpfs <- c(1234, 01833827570, 45614814570, 4, 4000001111)

Basta usar a função str_pad() para complementar a string acrescentando zeros a esquerda até cada string conter 11 caracteres:

str_pad(cpfs, width = 11, pad = "0")
## [1] "00000001234" "01833827570" "45614814570" "00000000004" "04000001111"

Veja que o terceiro elemento do vetor, que já continha 11 caracteres, não foi alterado.

7.1.5 Remover espaços em branco desnecessários

Quando se lida com texto, é comum recebermos dados com excesso de espaço em branco, como nestes exemplos:

x <- c("      inicio", "final      ", "      ambos      ", "    no       meio        ")
x
## [1] "      inicio"              "final      "               "      ambos      "         "    no       meio        "
# conferindo o tamanho dos strings
str_length(x)
## [1] 12 11 17 25

Para isso, existe a função str_trim(), que remove espaços em branco seguidos no início e no final do string:

x2 <-str_trim(x)
x2
## [1] "inicio"        "final"         "ambos"         "no       meio"
# conferindo o tamanho do vetor limp
str_length(x2)
## [1]  6  5  5 13

A função não limpou os espaços em branco seguidos no último elemento. Para isso, você pode usar uma função mais generalizada, chamada str_squish():

x2b <- str_squish(x)
x2b
## [1] "inicio"  "final"   "ambos"   "no meio"
str_length(x2b)
## [1] 6 5 5 7

7.2 Regex

Trata-se de um assunto bastante complexo e avançado. Não é fácil dominar regex e provavelmente você vai precisar sempre consultar e experimentar a montagem dos padrões de regex. Infelizmente não é possível aprender regex rápido e de um jeito fácil, só existe o jeito difícil: errando muito, com muita prática e experiências reais.

A seguir, uma lista dos principais mecanismos de regex:

regex correspondência
^ começa do string (ou uma negação)
. qualquer caractere
$ fim da linha
[maça] procura os caracteres m, a, ç
maça maça
[0-9] números
[A-Z] qualquer letra maiúscula
\\w uma palavra
\\W não é palavra
(pontuação, espaço etc.)
\\s um espaço (tab, newline, space)

Vamos então aplicar as regex acima em um conjunto de strings:

textos <- c("Fulano", "fulano", "abcdeF", "01584", 
            "abc456", "123def", "OI", "meuemail@gmail.com",
            "www.google.com", "Meu nome é Fulano")

# detectar strings que contem F maiusculo
str_detect(textos, "F")
##  [1]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
# detectar strings que começam com F maiúsculo
str_detect(textos, "^F")
##  [1]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# detectar strings que começam com F, independente se maiúsculo ou minúsculo
str_detect(textos, regex("^F", ignore_case = TRUE))
##  [1]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

str_subset() é uma generalização de str_detect() que filtra os elementos em que str_detect() retorna TRUE:

# filtrar strings que terminam com o
str_subset(textos, "o$")
## [1] "Fulano"            "fulano"            "Meu nome é Fulano"
# strings que contem um algarismo
str_subset(textos, "\\d")
## [1] "01584"  "abc456" "123def"
str_subset(textos, "[0-9]")
## [1] "01584"  "abc456" "123def"
# strings que terminam com um algarismo
str_subset(textos, "\\d$")
## [1] "01584"  "abc456"
# strings que nao contem algarismo
str_subset(textos, "\\d", negate = TRUE)
## [1] "Fulano"             "fulano"             "abcdeF"             "OI"                 "meuemail@gmail.com" "www.google.com"    
## [7] "Meu nome é Fulano"
# strings que contem um ponto
str_subset(textos, "\\.")
## [1] "meuemail@gmail.com" "www.google.com"
# strings que contem um espaço
str_subset(textos, "\\s")
## [1] "Meu nome é Fulano"

A seguir, alguns bons sites para aprender mais sobre regex. É um assunto interessante e bastante utilizado para tratamento textual.

http://turing.com.br/material/regex/introducao.html

https://regexone.com/

7.3 Exercícios

  1. Utilizando o dataframe abaixo, obtenha o resultado a seguir: Dica: separate(), str_replace_all(), str_trim(), str_sub()
cadastros <- data.frame(
  email = c('joaodasilva@gmail.com', 'rafael@hotmail.com', 'maria@uol.com.br', 'juliana.morais@outlook.com'),
  telefone = c('(61)99831-9482', '32 8976 2913', '62-9661-1234', '15-40192.5812')
)

cadastros
##                        email       telefone
## 1      joaodasilva@gmail.com (61)99831-9482
## 2         rafael@hotmail.com   32 8976 2913
## 3           maria@uol.com.br   62-9661-1234
## 4 juliana.morais@outlook.com  15-40192.5812
##            login dominio   telefone dd
## 1    joaodasilva   gmail 99831-9482 61
## 2         rafael hotmail  8976-2913 32
## 3          maria     uol  9661-1234 62
## 4 juliana.morais outlook 40192-5812 15
  1. Baixe o pacote literaturaBR. Como ele não está no CRAN, é necessário usar outra função:
remotes::install_github("sillasgonzaga/literaturaBR")

Importe o dataframe com os livros:

library(literaturaBR)
df_livros <- literaturaBR::load_all_books()
head(df_livros)
##               book_name chapter_name                                          url paragraph_number
## alienista.1 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                1
## alienista.2 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                2
## alienista.3 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                3
## alienista.4 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                4
## alienista.5 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                5
## alienista.6 O Alienista   Capítulo I https://pt.wikisource.org/wiki/O_Alienista/I                6
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       text
## alienista.1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             As crônicas da vila de Itaguaí dizem que em tempos remotos vivera ali um certo médico, o Dr. Simão Bacamarte, filho da nobreza da terra e o maior dos médicos do Brasil, de Portugal e das Espanhas. Estudara em Coimbra e Pádua. Aos trinta e quatro anos regressou ao Brasil, não podendo el-rei alcançar dele que ficasse em Coimbra, regendo a universidade, ou em Lisboa, expedindo os negócios da monarquia.
## alienista.2                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        —A ciência, disse ele a Sua Majestade, é o meu emprego único; Itaguaí é o meu universo.
## alienista.3 Dito isso, meteu-se em Itaguaí, e entregou-se de corpo e alma ao estudo da ciência, alternando as curas com as leituras, e demonstrando os teoremas com cataplasmas. Aos quarenta anos casou com D. Evarista da Costa e Mascarenhas, senhora de vinte e cinco anos, viúva de um juiz de fora, e não bonita nem simpática. Um dos tios dele, caçador de pacas perante o Eterno, e não menos franco, admirou-se de semelhante escolha e disse-lho. Simão Bacamarte explicou-lhe que D. Evarista reunia condições fisiológicas e anatômicas de primeira ordem, digeria com facilidade, dormia regularmente, tinha bom pulso e excelente vista; estava assim apta para dar-lhe filhos robustos, sãos e inteligentes. Se além dessas prendas,—únicas dignas da preocupação de um sábio, —D. Evarista era mal composta de feições, longe de lastimá-lo, agradecia-o a Deus, porquanto não corria o risco de preterir os interesses da ciência na contemplação exclusiva, miúda e vulgar da consorte.
## alienista.4                                                                                                                                                                                                                                                                                                  D. Evarista mentiu às esperanças do Dr. Bacamarte, não lhe deu filhos robustos nem mofinos. A índole natural da ciência é a longanimidade; o nosso médico esperou três anos, depois quatro, depois cinco. Ao cabo desse tempo fez um estudo profundo da matéria, releu todos os escritores árabes e outros, que trouxera para Itaguaí, enviou consultas às universidades italianas e alemãs, e acabou por aconselhar à mulher um regímen alimentício especial. A ilustre dama, nutrida exclusivamente com a bela carne de porco de Itaguaí, não atendeu às admoestações do esposo; e à sua resistência,—explicável, mas inqualificável,— devemos a total extinção da dinastia dos Bacamartes.
## alienista.5                                                                                                                                                                                                                                                                                                                                      Mas a ciência tem o inefável dom de curar todas as mágoas; o nosso médico mergulhou inteiramente no estudo e na prática da medicina. Foi então que um dos recantos desta lhe chamou especialmente a atenção,—o recanto psíquico, o exame de patologia cerebral. Não havia na colônia, e ainda no reino, uma só autoridade em semelhante matéria, mal explorada, ou quase inexplorada. Simão Bacamarte compreendeu que a ciência lusitana, e particularmente a brasileira, podia cobrir-se de "louros imarcescíveis", — expressão usada por ele mesmo, mas em um arroubo de intimidade doméstica; exteriormente era modesto, segundo convém aos sabedores.
## alienista.6                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               —A saúde da alma, bradou ele, é a ocupação mais digna do médico.
  1. Quebre cada linha da coluna text em varias, tendo uma palavra por linha, usando separate_rows(), e filtre as linhas da nova coluna que contem apenas letras. Salve em um novo dataframe chamado df_livros_sep.

  2. Calcule o numero de palavras distintas em proporção à quantidade total de palavras por livro

  3. Calcule a proporção de palavras que contem a letra a por livro.