Dúvida sobre separação de texto em colunas

Olá, tenho um banco de dados com aproximadamente 18 mil tweets como esse:

image

Gostaria de separar o conteúdo do tweet em diferentes colunas, como por exemplo, data, hora, tipo de ocorrência, endereço etc.

Comecei a fazer isso no Google sheets usando a função SPLIT, mas não me parece uma forma muito inteligente. É um processo um pouco demorado, algumas vezes ele sobrescreve a coluna à direita e várias células ficam com erro. Além disso, o padrão de escrita desses tweets mudou ao longo do tempo. Acredito que existem uns 5 padrões diferentes que foram adotados pelo órgão.

Existe alguma técnica específica para fazer a separação deste texto em colunas que facilite o trabalho? Algum software ou biblioteca de python poderia facilitar minha vida?

1 Curtida

Existem diversas maneiras de estruturar textos com Python: você pode utilizar técnicas de manipulação de strings (semelhantes aos splits das planilhas) e também expressões regulares (que são mais poderosas, porém mais complexas). No caso do seu texto, me parece que as expressões regulares poderiam funcionar bem (dado que o formato não é tão complexo), mas isso depende de sua familiaridade com elas (não são tão simples de aprender).
De qualquer forma, como o padrão do texto muda ao longo do tempo, o ideal seria você fazer um código para cada padrão de texto e daí fazer uma série de if/elif/elifs no código para detectar o padrão em questão e então aplicar o código que extrai a estrutura para esse padrão. Enfim, lidar com extração de dados estruturados de textos não é algo sempre muito simples, depende da padronização (e da quantidade de padrões).

Fiz dois exemplos de código: um usando funções de manipulação de strings em Python e outro com expressões regulares. Ao final de ambos códigos um dicionário chamado dados é criado e mostrado na tela.

Código com manipulação simples de string:

from pprint import pprint

texto = "Ocorrência: 13/01 - 12h58 - Moto x Moto\nLocalização: Rua Pedro Lobo - Bairro: Centro"
dados = {}
# Primeiro, extrai dados baseado em suas posições:
linha_1, linha_2 = texto.splitlines()
dados["data"], dados["hora"], dados["descricao"] = linha_1.split(" - ")
dados["endereco"], dados["bairro"] = linha_2.split(" - ")

# Segundo, limpa dados:
dados["data"] = dados["data"].split(": ")[1]
dados["hora"] = dados["hora"].replace("h", ":")
dados["endereco"] = dados["endereco"].split(": ")[1]

pprint(dados)  # Mostra dados

Código com expressões regulares:

import re
from pprint import pprint

texto = "Ocorrência: 13/01 - 12h58 - Moto x Moto\nLocalização: Rua Pedro Lobo - Bairro: Centro"
regexp_data_hora_descricao = re.compile("Ocorrência: (.*) - (.*) - (.*)\n")
regexp_endereco_bairro = re.compile("Localização: (.*) - Bairro: (.*)")

dados = {}
dados["data"], dados["hora"], dados["descricao"] = regexp_data_hora_descricao.findall(texto)[0]                                          
dados["endereco"], dados["bairro"] = regexp_endereco_bairro.findall(texto)[0]                                                   
dados["hora"] = dados["hora"].replace("h", ":")                                                                                 
pprint(dados)

O resultado, em ambos casos, será:

{'bairro': 'Centro',
 'data': '13/01',
 'descricao': 'Moto x Moto',
 'endereco': 'Rua Pedro Lobo',
 'hora': '12:58'}

Nota 1: no código acima eu assumi que o tweet está em duas linhas (por isso o \n), dado que é o que parece pela imagem. Caso não esteja em duas linhas, você terá que mudar a expressão regular.

Nota 2: caso os caracteres delimitadores ("\n", “-”, “:”) apareçam em outras partes do tweet você precisará alterar os códigos.

Nota 3: você ainda precisará fazer um código que lê o CSV, identifica o padrão do texto e o código para extrair outros padrões.

6 Curtidas

Esse código em R deu conta das últimas 3.019 ocorrências.

library(rtweet)
library(dplyr)
library(purrr)
library(stringi)
library(tibble)

posts <-
  # Pega os posts
  get_timeline(user = "cbv_jlle", n = 3200) %>%
  
  # só os posts que são ocorrências
  filter(grepl("^Ocorrência", text)) %>%
  
  # Coloca o ano no texto
  mutate(ano = format(created_at, "%Y")) %>% 
  mutate(text = paste0(text, " - Ano: ", ano)) %>%
  
  # Coloca a `{variável}:` antes das horas e do caso
  mutate(text = gsub("(\\d+h\\d+\\s*-)", "Hora: \\1 Caso:", text)) %>%
  
  # muda a nova linha para traço
  mutate(text = gsub("\n", " - ", text)) %>%
  
  # joga o APH para o fim
  mutate(text  = gsub("(.*)APH\\s*-(.*)", "\\1 \\2 - APH: Sim", text)) %>%
  
  # puxa os textos dos posts
  pull(text) %>%
  
  # Para não dar problema com "- rodovia do arroz"
  # (tem 5 casos desses)
  gsub("- Rodovia do Arroz", "-Rodovia do Arroz", .) %>%
  
  # tem um caso que o endereço está como Rua SC - 301
  gsub("Rua SC - 301", "Rua SC-301", .) %>%
  
  # separa as strings nos traços
  strsplit("(\\s+-\\s+)") %>% 
  
  # para cada post cria uma tabela de uma linha
  # onde o nome da coluna é  o nome da variável 
  # e os valores estão na linha
  map(stri_split_fixed, pattern = ":", n = 2)   %>% 
  map(unlist) %>% 
  map(gsub, pattern = "^\\s+|\\s+$", replacement = "") %>% 
  map(matrix, ncol = 2, byrow = TRUE) %>% 
  map(as.data.frame, stringsAsFactors = FALSE) %>% 
  map(column_to_rownames, "V1") %>% 
  map(t) %>% 
  map(as.data.frame, stringsAsFactors = FALSE) %>%
  
  # Junta essas tabelas em uma só
  bind_rows() %>% 
  
  # transforma a data e horário em Posixct
  mutate(horario_posixct = paste0(Ocorrência, "/", Ano, " ", Hora))  %>% 
  mutate(horario_posixct = as.POSIXct(strptime(horario_posixct, 
                                               "%d/%m/%Y %Hh%M")))

write.csv(posts, "~/Desktop/cbv_jlle.csv", row.names = FALSE)

Aqui a tabela gerada https://docs.google.com/spreadsheets/d/1nbocypUW1SAcolpxzv0hNJE1w1TqQqrqPP0KbSc0tkg/edit?usp=sharing

2 Curtidas

Oi, Turicas

Acabei optando pelo método de manipulação das strings e usei regex em algumas partes que o código estava quebrando.

Obrigado pela resposta bem completa e explicativa. Me ajudou bastante!

1 Curtida

Valeu, Daniel!

Eu não tenho tanta fluência em R mas confesso que fique tentado vendo como você resolveu com poucas linhas. Mas ainda sim ver o seu raciocínio (como excluir Rodovia do Arroz) me ajudou também a resolver algumas questões!

2 Curtidas