Nem sempre o auditor disporá dos dados necessários à realização de seus trabalhos armazenados em uma planilha eletrônica ou em arquivos nos quais possam, de pronto, serem importados pelo aplicativo que esteja utilizando para realizar a análise destes dados.
Às vezes, os dados estarão contidos em arquivos texto contendo a imagem de um relatório produzido pelo sistema contábil utilizado pela entidade na qual esteja realizando a auditoria.
Assim, o objetivo deste documento é apresentar algumas dicas de como os dados contidos nestes relatórios podem ser importados com o R. Para tanto, apresentaremos um passo a passo para a importação de seis relatórios com “layouts” distintos o que, acreditamos, dará ao leitor uma visão geral de como importar relatórios usando o R.
Os arquivos contendo os relatórios utilizados neste documento bem como outros cuja importação deixaremos a cargo do leitor como exercício, serão disponibilizados no arquivo Relatorios.zip.
Neste capítulo apresentaremos um passo a passo bem datalhado do processo de importação de relatórios com o R. É importante destacar que não existe uma regra rígida a ser seguida já que, como veremos, o processo de importação é extremamente dependente da estrutura/“layout” do relatório. Ainda assim, acreditamos que cinco etapas estarão presentes neste processo, as quais elencamos a seguir:
Para ilustrar cada uma destas etapas, utilizaremos o relatório contido no arquivo Relatorio1.txt cujo “layout” apresentamos a seguir:
__ SIAFEM2005-EXEORC,CONSULTAS,LISNE ( LISTA NOTA DE EMPENHO ) _______________
CONSULTA EM 05/01/2007 AS 10:37 USUARIO : MARCOS
UNIDADE GESTORA : 180100 - SECRETARIA DE ESTADO DE EDUCACAO
GESTAO : 00001 - TESOURO
LICITACAO: TODAS FONTE: TODAS EMPENHO: TODAS
NATUREZA : TODAS
NUMERO EVENTO CREDOR V A L O R
-------------------------------------------------------------------------------
2005NE00001 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 31.425,26
2005NE00002 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 3.560.659,03
2005NE00003 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 2.732.876,84
2005NE00004 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 21.711.652,87
2005NE00005 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 11.153.100,00
2005NE00006 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 15.839,20
2005NE00007 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 3.016,96
2005NE00008 EMPENHO CAIXA ECONOMICA FEDERAL 964,39
2005NE00009 EMPENHO CAIXA ECONOMICA FEDERAL 225,25
2005NE00010 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 22.575.629,00
2005NE00011 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 10.959,26
2005NE00012 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 370,36
2005NE00013 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 1.111,06
_______________________________________________________________________________
( 2005NE _____ ) PARA DETALHAR INFORME O NR. DO EMPENHO.
Este é o relatório dos empenhos emitidos produzido pelo SIAFEM1 com a transação >lisne e consiste de uma relação/listagem dos empenhos emitidos em determinado período por uma determinada Unidade Gestora.
De posse de um arquivo texto como o apresentado acima, como podemos extrair os dados de interesse usando o R?
De uma forma geral o “layout” de um relatório consiste de cabeçalho, rodapé e corpo. Usualmente é no corpo do relatório que estarão os dados que desejamos extrair.
No relatório apresentado acima, estas partes estão bem definidas: tudo o que está acima da linha pontilhada constitui o cabeçalho do relatório, contendo diversas informações sobre os dados apresentados; o que está abaixo da linha contínua é o rodapé, e tudo o que se encontra entre estas linhas é o corpo do relatório, onde se encontram os dados nos quais estamos interessados.
Como já mencionado anteriormente, a abordagem utilizada para a importação dos dados irá depender da estrutura do relatório, sendo certo que alguns relatórios, de estrutura mais simples, serão mais simples de importar do que outros, de estrutura mais complexa.
Embora o relatório que utilizaremos para ilustrar o procedimento de importação seja bem simples, as ideias básicas são as mesmas para a importação de relatórios mais complexos.
O relatório acima apresenta uma estrutura muito simples. Examinando um pouco mais o documento, vemos que o corpo do relatório encontra-se bem estruturado. Cada registro está contido em uma única linha do relatório e os campos estão bem delimitados2.
As linhas do arquivo que nos interessam e que constituem o corpo do relatório, são todas aquelas que iniciam com o número da nota de empenho. Todas as demais linhas podem ser desprezadas.
Para importar todo o arquivo, linha a linha, usamos a função readLines().
# Define o diretório de trabalho
setwd("C:\\Users\\Marcos\\OneDrive\\Marcos\\GitHubTutoriais\\Importacao de Relatorios")
# Importa o arquivo texto
r1 <- readLines("Relatorio1.txt")
# Examinar o tipo de dados
class(r1)## [1] "character"
Para inspecionar o conteúdo de r1:
r1## [1] "__ SIAFEM2005-EXEORC,CONSULTAS,LISNE ( LISTA NOTA DE EMPENHO ) _______________"
## [2] "CONSULTA EM 05/01/2007 AS 10:37 USUARIO : MARCOS"
## [3] "UNIDADE GESTORA : 180100 - SECRETARIA DE ESTADO DE EDUCACAO"
## [4] "GESTAO : 00001 - TESOURO"
## [5] "LICITACAO: TODAS FONTE: TODAS EMPENHO: TODAS"
## [6] "NATUREZA : TODAS"
## [7] "NUMERO EVENTO CREDOR V A L O R"
## [8] "-------------------------------------------------------------------------------"
## [9] "2005NE00001 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 31.425,26"
## [10] "2005NE00002 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 3.560.659,03"
## [11] "2005NE00003 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 2.732.876,84"
## [12] "2005NE00004 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 21.711.652,87"
## [13] "2005NE00005 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 11.153.100,00"
## [14] "2005NE00006 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 15.839,20"
## [15] "2005NE00007 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 3.016,96"
## [16] "2005NE00008 EMPENHO CAIXA ECONOMICA FEDERAL 964,39"
## [17] "2005NE00009 EMPENHO CAIXA ECONOMICA FEDERAL 225,25"
## [18] "2005NE00010 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 22.575.629,00"
## [19] "2005NE00011 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 10.959,26"
## [20] "2005NE00012 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 370,36"
## [21] "2005NE00013 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 1.111,06"
## [22] "_______________________________________________________________________________"
## [23] "( 2005NE _____ ) PARA DETALHAR INFORME O NR. DO EMPENHO."
## [24] ""
Como pode ser visto, r1 é um vetor de caracteres onde cada elemento do vetor contém uma string correspondente a cada linha do relatório a ser importado.
Esta etapa consiste em excluir do vetor r1 as linhas desnecessárias, deixando apenas aquelas que nos interessam.
A abordagem que utilizaremos para selecionar as linhas de interesse será com o uso de expressões regulares3.
Nesta abordagem, devemos elaborar uma expressão regular que “case” com algum dos dados contidos nas linhas que desejamos extrair.
No relatório que estamos examinando, as linhas que nos interessam são as que iniciam com o número da nota de empenho. Os números das notas de empenho tem uma estrutura fixa que consiste de quatro dígitos seguido da string “NE”" seguido de cinco dígitos, ou seja: ddddNEddddd.
Uma expressão regular que “casa” com estas linhas é a seguinte: "^\\d{4}NE\\d{5}".
No R, a função grep() retorna o indice no vetor de dados (r1) onde a linha “casou” com a expressão regular ou com o argumento value= definido como verdadeiro (TRUE), retorna a string casada.
r1 <- grep("^\\d{4}NE\\d{5}", r1, value=TRUE)
r1## [1] "2005NE00001 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 31.425,26"
## [2] "2005NE00002 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 3.560.659,03"
## [3] "2005NE00003 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 2.732.876,84"
## [4] "2005NE00004 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 21.711.652,87"
## [5] "2005NE00005 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 11.153.100,00"
## [6] "2005NE00006 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 15.839,20"
## [7] "2005NE00007 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL. 3.016,96"
## [8] "2005NE00008 EMPENHO CAIXA ECONOMICA FEDERAL 964,39"
## [9] "2005NE00009 EMPENHO CAIXA ECONOMICA FEDERAL 225,25"
## [10] "2005NE00010 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 22.575.629,00"
## [11] "2005NE00011 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 10.959,26"
## [12] "2005NE00012 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 370,36"
## [13] "2005NE00013 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO 1.111,06"
Como podemos ver, tudo que era desnecessário foi excluído, restando apenas o que nos interessa.
O relatório apresenta claramente 4 campos: número da nota de empenho, evento, credor e valor do empenho. A divisão das linhas selecionadas é feita com a função substr(), conforme mostrado a seguir:
NumNE <- substr(r1, 1, 11)
Evento <- substr(r1, 12, 22)
Credor <- substr(r1, 23, 60)
Valor <- substr(r1, 61, 79)NumNE## [1] "2005NE00001" "2005NE00002" "2005NE00003" "2005NE00004" "2005NE00005"
## [6] "2005NE00006" "2005NE00007" "2005NE00008" "2005NE00009" "2005NE00010"
## [11] "2005NE00011" "2005NE00012" "2005NE00013"
Evento## [1] " EMPENHO " " EMPENHO " " EMPENHO " " EMPENHO " " EMPENHO "
## [6] " EMPENHO " " EMPENHO " " EMPENHO " " EMPENHO " " EMPENHO "
## [11] " EMPENHO " " EMPENHO " " EMPENHO "
Credor## [1] " SECRETARIA DE ESTADO DE EDUCACAO "
## [2] " SECRETARIA DE ESTADO DE EDUCACAO "
## [3] " SECRETARIA DE ESTADO DE EDUCACAO "
## [4] " SECRETARIA DE ESTADO DE EDUCACAO "
## [5] " SECRETARIA DE ESTADO DE EDUCACAO "
## [6] " INSTITUTO NACIONAL DE SEGURO SOCIAL. "
## [7] " INSTITUTO NACIONAL DE SEGURO SOCIAL. "
## [8] " CAIXA ECONOMICA FEDERAL "
## [9] " CAIXA ECONOMICA FEDERAL "
## [10] " SECRETARIA DE ESTADO DE EDUCACAO "
## [11] " SECRETARIA DE ESTADO DE EDUCACAO "
## [12] " SECRETARIA DE ESTADO DE EDUCACAO "
## [13] " SECRETARIA DE ESTADO DE EDUCACAO "
Valor## [1] " 31.425,26" " 3.560.659,03" " 2.732.876,84"
## [4] " 21.711.652,87" " 11.153.100,00" " 15.839,20"
## [7] " 3.016,96" " 964,39" " 225,25"
## [10] " 22.575.629,00" " 10.959,26" " 370,36"
## [13] " 1.111,06"
Com este procedimento, repartimos cada elemento do vetor r1 em quatro novos vetores, cada um contendo informações relativa a um campo do registro.
Para separar os campos é necessário identificarmos onde se inicia e termina a informação relativa a cada campo. Assim, a informação relativa ao número do empenho inicia na posição 1 da linha e termina na posição 11, a informação relativa ao evento vai da posição 12 à 22 e assim sucessivamente para os demais campos.
Agora que temos 4 vetores (NumNE, Evento, Credor e Valor) cada um contendo informações acerca dos campos desejados, podemos reuní-los em um data frame da seguinte forma:
r1 <- data.frame(NumNE, Evento, Credor, Valor)
r1## NumNE Evento Credor
## 1 2005NE00001 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 2 2005NE00002 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 3 2005NE00003 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 4 2005NE00004 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 5 2005NE00005 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 6 2005NE00006 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL.
## 7 2005NE00007 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL.
## 8 2005NE00008 EMPENHO CAIXA ECONOMICA FEDERAL
## 9 2005NE00009 EMPENHO CAIXA ECONOMICA FEDERAL
## 10 2005NE00010 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 11 2005NE00011 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 12 2005NE00012 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 13 2005NE00013 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## Valor
## 1 31.425,26
## 2 3.560.659,03
## 3 2.732.876,84
## 4 21.711.652,87
## 5 11.153.100,00
## 6 15.839,20
## 7 3.016,96
## 8 964,39
## 9 225,25
## 10 22.575.629,00
## 11 10.959,26
## 12 370,36
## 13 1.111,06
A importação dos dados está quase completa, faltando apenas alguns retoques tais como: extrair os caracteres brancos dos dados e converter a coluna Valor para o formato numérico. Isto pode ser feito da seguinte forma:
# Remoção dos caracteres brancos do campo Credor
r1$Credor <- gsub("^ +", "", r1$Credor)
r1$Credor <- gsub(" +$", "", r1$Credor)O primeiro comando remove os caracteres brancos existentes no início dos dados e o segundo remove os caracteres brancos existentes no fim.
Ilustramos o procedimento apenas para a coluna Credor do data frame, mas o mesmo procedimento deve ser realizado em cada uma das 3 colunas restantes.
Para simplificar o procedimento, é conveniente definir uma função para remover os espaços em branco. Chamaremos esta função de removeBrancos() e a definiremos da seguinte forma:
removeBrancos <- function(x) gsub("^ +", "", gsub(" +$", "", x))Vejamos agora como converter o campo Valor para o formato numérico.
r1$Valor <- gsub("\\.", "", r1$Valor)
r1$Valor <- gsub(",", ".", r1$Valor)
r1$Valor <- as.numeric(r1$Valor)Os comandos acima fazem, respectivamente o seguinte: remove os pontos, substitui a vírgula por ponto e converte para o formato numérico.
Aqui também parece conveniente definirmos uma função para simplificar este procedimento. Vamos chamá-la de convNum() e a definiremos da seguinte forma:
convNum <- function(x) as.numeric(gsub(",", ".", gsub("\\.", "", x)))Após estes procedimentos os dados já estão prontos para análise. Vejamos:
str(r1)## 'data.frame': 13 obs. of 4 variables:
## $ NumNE : Factor w/ 13 levels "2005NE00001",..: 1 2 3 4 5 6 7 8 9 10 ...
## $ Evento: Factor w/ 1 level " EMPENHO ": 1 1 1 1 1 1 1 1 1 1 ...
## $ Credor: chr "SECRETARIA DE ESTADO DE EDUCACAO" "SECRETARIA DE ESTADO DE EDUCACAO" "SECRETARIA DE ESTADO DE EDUCACAO" "SECRETARIA DE ESTADO DE EDUCACAO" ...
## $ Valor : num 31425 3560659 2732877 21711653 11153100 ...
r1## NumNE Evento Credor
## 1 2005NE00001 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 2 2005NE00002 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 3 2005NE00003 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 4 2005NE00004 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 5 2005NE00005 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 6 2005NE00006 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL.
## 7 2005NE00007 EMPENHO INSTITUTO NACIONAL DE SEGURO SOCIAL.
## 8 2005NE00008 EMPENHO CAIXA ECONOMICA FEDERAL
## 9 2005NE00009 EMPENHO CAIXA ECONOMICA FEDERAL
## 10 2005NE00010 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 11 2005NE00011 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 12 2005NE00012 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## 13 2005NE00013 EMPENHO SECRETARIA DE ESTADO DE EDUCACAO
## Valor
## 1 31425.26
## 2 3560659.03
## 3 2732876.84
## 4 21711652.87
## 5 11153100.00
## 6 15839.20
## 7 3016.96
## 8 964.39
## 9 225.25
## 10 22575629.00
## 11 10959.26
## 12 370.36
## 13 1111.06
summary(r1$Valor)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 225 1111 15839 4753679 3560659 22575629
Em linhas gerais, estas são as etapas para a importação de relatórios.
Como no R uma mesma tarefa pode ser executada de diversas formas, não achamos que a metodologia aqui apresentada seja a mais elegante ou mesmo a mais eficiente. Apenas reflete nosso atual estágio de compreensão do ambiente R, sendo possível a existência de outras abordagens mais eficientes, elegantes ou mesmo mais simples.
Apenas para consolidar a metodologia apresentada, vamos realizar a importação de um outro relatório (Relatorio2.txt) cuja estrutura é similar à do relatório utilizado no exemplo anterior.
O layout do relatório é apresentado a seguir:
STOCK LEVEL REPORT
QUARTER 1 QUARTER 2 QUARTER 3 QUARTER 4
BEGINNING STOCK | 1075 400 500 550
REQUIRMENTS | 675 0 200 100
PLANNED RECEIPT | 0 100 250 0
ENDING STOCK | 400 500 550 450
Como pode ser visto, cada registro ocupa apenas uma linha, de forma que a abordagem apresentada anteriormente poderá ser aplicada.
## Passo 1 - Leitura do arquivo do dados
r2 <- readLines("Relatorio2.txt")## Warning in readLines("Relatorio2.txt"): linha final incompleta encontrada
## em 'Relatorio2.txt'
r2## [1] " STOCK LEVEL REPORT "
## [2] ""
## [3] " QUARTER 1 QUARTER 2 QUARTER 3 QUARTER 4"
## [4] "BEGINNING STOCK | 1075 400 500 550 "
## [5] "REQUIRMENTS | 675 0 200 100"
## [6] "PLANNED RECEIPT | 0 100 250 0 "
## [7] "ENDING STOCK | 400 500 550 450"
## Passo 2 - Identificar e extrair as linhas de interesse
r2 <- grep("^\\w", r2, value=TRUE)
r2## [1] "BEGINNING STOCK | 1075 400 500 550 "
## [2] "REQUIRMENTS | 675 0 200 100"
## [3] "PLANNED RECEIPT | 0 100 250 0 "
## [4] "ENDING STOCK | 400 500 550 450"
Agora vamos adotar uma variação do que foi feito anteriormente.
A parte do processo de importação relativa a dividr as linhas nos campos desejados e montar um data frame será comum à maioria dos formatos de relatórios com os quais um auditor possa se deparar. Assim, vamos definir uma pequena função para gerar um data frame a partir de um vetor de caracteres contendo as linhas com os dados de interesse. Esta funcão irá separar as linhas do relatório nos campos desejados. Chamaremos esta função de txt2df() e a definiremos da seguinte forma:
txt2df <- function(x, colunas, inicio, fim){
## x : vetor de caracteres contendo as linhas do arquivo
## colunas : vetor com os nomes dos campos
## inicio : vetor numérico contendo o número da coluna inicial do campo
## fim : vetor numérico contendo o número da coluna final do campo
df <- matrix(nr=length(x), nc=length(colunas))
for(k in colunas){
i <- which(colunas == k)
k <- substr(x, inicio[i], fim[i])
df[,i] <- k
}
df <- as.data.frame(df)
names(df) <- colunas
df
}Definida esta função, os passos 3 e 4 poderão ser reunidos em uma só etapa da seguinte forma:
## Passo 3 - Dividir as linhas nos campos desejados e
## Passo 4 - Juntas os campos em data frame
r2 <- txt2df(r2,
colunas=c("NomeLinha", "Q1", "Q2", "Q3", "Q4"),
inicio=c( 1, 19, 30, 43, 56),
fim=c(17, 29, 42, 55, 68))
r2## NomeLinha Q1 Q2 Q3 Q4
## 1 BEGINNING STOCK 1075 400 500 550
## 2 REQUIRMENTS 675 0 200 100
## 3 PLANNED RECEIPT 0 100 250 0
## 4 ENDING STOCK 400 500 550 450
Conforme pode ser visto dos argumentos fornecidos à função verifica-se que o campo NomeLinha inicia na coluna 1 e termina na coluna 17, o campo Q1 inicia na coluna 19 e termina na coluna 29 e assim sucessivamente para os demais campos.
A última etapa consiste em realizar a limpeza/tratamento dos dados. Devemos excluir os brancos e converter os valores dos campos Q1, Q2, Q3 e Q4 para o formato numérico.
## Passo 5 - Tratar os dados, se necessário
r2 <- as.data.frame(sapply(r2, removeBrancos), stringsAsFactors=FALSE)
r2[, 2:5] <- as.data.frame(sapply(r2[, 2:5], as.numeric))
r2## NomeLinha Q1 Q2 Q3 Q4
## 1 BEGINNING STOCK 1075 400 500 550
## 2 REQUIRMENTS 675 0 200 100
## 3 PLANNED RECEIPT 0 100 250 0
## 4 ENDING STOCK 400 500 550 450
Para que o conjunto de dados fique com uma aparência bem semelhante ao relatório, podemos atribuir às linhas do data frame os nomes contidos na coluna NomeLinha. Isto pode ser feito da seguinte forma:
rownames(r2) <- r2$NomeLinha
r2$NomeLinha <- NULL
str(r2)## 'data.frame': 4 obs. of 4 variables:
## $ Q1: num 1075 675 0 400
## $ Q2: num 400 0 100 500
## $ Q3: num 500 200 250 550
## $ Q4: num 550 100 0 450
r2## Q1 Q2 Q3 Q4
## BEGINNING STOCK 1075 400 500 550
## REQUIRMENTS 675 0 200 100
## PLANNED RECEIPT 0 100 250 0
## ENDING STOCK 400 500 550 450
Pronto. Os dados já se encontram prontos para análise. É oportuno lembrar que havendo a necessidade de se importar sempre os mesmos relatórios, todos estes passos podem ser “empacotados” em uma função que receberá o arquivo texto contendo o relatório como argumento e retornará um data frame com os dados prontos para análise.
Neste tópico, apresentaremos algumas dicas de como importar relatórios com “layout” um pouco mais complexos do que os apresentados anteriormente.
Nosso objetivo é, que observando as soluções apresentadas, o leitor possa adaptá-las ao seu caso específico.
O próximo relatório (Relatorio3.txt), cujo “layout” apresentamos a seguir, distingue-se do primeiro e do segundo pelo fato de que cada registro ocupa duas linhas do corpo do relatório.
==========================================================
Employee Hours Report Page: 1
Company: XYZ Company Date Printed:02/02/99
==========================================================
Employee Date Regular Hours/ Other Hours/
Overtime Code
----------------------------------------------------------
Doe, John 01/23/99 23.3 1.6
15.6 AC
----------------------------------------------------------
Wacks, Gene 02/01/99 1.6 0.0
0.0
----------------------------------------------------------
Peters, Kate 01/30/99 40.3 3.4
1.1 VA
----------------------------------------------------------
Em relatórios com esta característica, ou seja, nos quais cada registro ocupa uma quantidade fixa de linhas (2, 3, 4, etc.), será necessário estabelecer o que denominaremos de “linhas âncoras”, ou seja, linhas que servirão de base para a extração dos dados contidos nas demais linhas que constituem o registro.
No caso deste relatório, as linhas âncoras serão as linhas que contém o nome dos funcionários. A partir destas linhas, podemos buscar as informações relativas às “horas extras” (Overtime) e “código” (Code) que constam da linha seguinte.
Desejamos que os dados, após serem importados, estejam no seguinte formato:
Empregado Data HorasRegulares HorasExtras OutrasHoras Codigo
Doe, John 01/23/99 23.3 16.6 1.6 AC
Wacks, Gene 02/01/99 1.6 0.0 0.0
Peters, Kate 01/30/99 40.3 1.4 3.4 VA
Apresentaremos o código para a importação do relatório que está contido no arquivo Relatorio3.txt:
## Passo 1 - Importar as linhas do arquivo
r3 <- readLines("Relatorio3.txt")## Warning in readLines("Relatorio3.txt"): linha final incompleta encontrada
## em 'Relatorio3.txt'
r3## [1] "=========================================================="
## [2] "Employee Hours Report Page: 1"
## [3] "Company: XYZ Company Date Printed:02/02/99"
## [4] "=========================================================="
## [5] "Employee Date Regular Hours/ Other Hours/"
## [6] " Overtime Code"
## [7] "----------------------------------------------------------"
## [8] "Doe, John 01/23/99 23.3 1.6"
## [9] " 15.6 AC"
## [10] "----------------------------------------------------------"
## [11] "Wacks, Gene 02/01/99 1.6 0.0"
## [12] " 0.0"
## [13] "----------------------------------------------------------"
## [14] "Peters, Kate 01/30/99 40.3 3.4"
## [15] " 1.1 VA"
## [16] "----------------------------------------------------------"
## Passo 2 - Extrair as linhas de interesse
## (linhas do corpo do relatório)
idxLinhasAncoras <- grep("^\\w+, \\w+ +", r3)
linha1 <- r3[idxLinhasAncoras]
linha2 <- r3[idxLinhasAncoras + 1] linha1## [1] "Doe, John 01/23/99 23.3 1.6"
## [2] "Wacks, Gene 02/01/99 1.6 0.0"
## [3] "Peters, Kate 01/30/99 40.3 3.4"
linha2## [1] " 15.6 AC"
## [2] " 0.0"
## [3] " 1.1 VA"
Os dados que nos interessam estão contidos nos vetores linha1 e linha2. O vetor linha1 conté as informações relativas ao nome do empregado, data, horas regulares e outras horas, enquanto o vetor linha2 contém informações relativas a horas extras e código.
Falta agora o terceiro passo, que é separar adequadamente os campos. Para a realização desta etapa é necessário identificar em que coluna começa e termina cada campo.
Uma maneira de se fazer isso é abrir o arquivo em um editor de texto e contar o início e fim de cada campo.
## Passos 3 e 4 : Dividir as linhas nos campos desejados
## Campos na linha 1
df1 <- txt2df(linha1,
colunas=c("Employee", "Date", "RegularHours", "OtherHours"),
inicio=c( 1, 18, 26, 35),
fim=c(17, 25, 34, 58))
df1## Employee Date RegularHours OtherHours
## 1 Doe, John 01/23/99 23.3 1.6
## 2 Wacks, Gene 02/01/99 1.6 0.0
## 3 Peters, Kate 01/30/99 40.3 3.4
# Campos na linha 2
df2 <- txt2df(linha2,
colunas=c("Overtime", "Code"),
inicio=c(26, 35),
fim=c(34, 58))
df2## Overtime Code
## 1 15.6 AC
## 2 0.0
## 3 1.1 VA
## Agrupar os dois data frames em um
r3 <- cbind(df1, df2)
r3## Employee Date RegularHours OtherHours Overtime
## 1 Doe, John 01/23/99 23.3 1.6 15.6
## 2 Wacks, Gene 02/01/99 1.6 0.0 0.0
## 3 Peters, Kate 01/30/99 40.3 3.4 1.1
## Code
## 1 AC
## 2
## 3 VA
## Passo 5: limpar/preparar os dados
r3$Employee <- removeBrancos(r3$Employee)
r3$Date <- as.Date(removeBrancos(r3$Date), "%m/%d/%y")
r3$RegularHours <- as.numeric(removeBrancos(r3$RegularHours))
r3$Overtime <- as.numeric(removeBrancos(r3$Overtime))
r3$OtherHours <- as.numeric(removeBrancos(r3$OtherHours))
r3$Code <- removeBrancos(r3$Code)str(r3)## 'data.frame': 3 obs. of 6 variables:
## $ Employee : chr "Doe, John" "Wacks, Gene" "Peters, Kate"
## $ Date : Date, format: "1999-01-23" "1999-02-01" ...
## $ RegularHours: num 23.3 1.6 40.3
## $ OtherHours : num 1.6 0 3.4
## $ Overtime : num 15.6 0 1.1
## $ Code : chr "AC" "" "VA"
r3## Employee Date RegularHours OtherHours Overtime Code
## 1 Doe, John 1999-01-23 23.3 1.6 15.6 AC
## 2 Wacks, Gene 1999-02-01 1.6 0.0 0.0
## 3 Peters, Kate 1999-01-30 40.3 3.4 1.1 VA
Vamos ao quarto exemplar de relatório, um pouco mais complexo que os anteriores, contido no arquivo Relatorio4.txt cujo “layout” é mostrado a seguir:
Product Sales Report Page: 1
Company: XYZ Company For the month ended:09/30/98
==========================================================
Sales Person Date Qty Price Class
----------------------------------------------------------
Product: Tape
Doe, John 09/23/98 1,120 11,225.60 AC
09/24/98 21,123 233,112.67 VA
09/27/98 23 32.22 CS
Wacks, Gene 09/01/98 3,766 3,455.55 AC
Peters, Kate 09/30/98 4,000 3,999.44 VA
09/02/98 1,653 6,775.55 OT
Product: Stapler
Perrol, Barb 09/13/98 3,320 11,225.60 AC
Zonker, Pete 09/11/98 766 453.53 AC
09/20/98 1,455 2,543.43 VA
Perkins, Joe 09/12/98 23 23.55 OT
No relatório acima temos a seguinte característica que o distingue dos três anteriores e por isso exigirá uma nova estratégia para sua importação: os registros estão agrupados por produto e cada vendedor (Sales Person) possui uma quantidade variável de registros a ele associados.
Gostaríamos que os dados, após importados, estivessem no seguinte formato:
Product SalesPerson Date Qty Price Class
Tape Doe, John 09/23/98 1,120 11,225.60 AC
Tape Doe, John 09/24/98 21,123 233,112.67 VA
Tape Doe, John 09/27/98 23 32.22 CS
Tape Wacks, Gene 09/01/98 3,766 3,455.55 AC
Tape Peters, Kate 09/30/98 4,000 3,999.44 VA
Tape Peters, Kate 09/02/98 1,653 6,775.55 OT
Stapler Perrol, Barb 09/13/98 3,320 11,225.60 AC
Stapler Zonker, Pete 09/11/98 766 453.53 AC
Stapler Zonker, Pete 09/20/98 1,455 2,543.43 VA
Stapler Perkins, Joe 09/12/98 23 23.55 OT
Apresentamos a seguir as etapas para a importação deste relatório.
O primeiro passo consiste apenas em realizar a leitura do arquivo.
## Passo 1 - importação do relatório
r4 <- readLines("Relatorio4.txt")
r4 <- r4[r4 != ""] # Excluir linhas em branco...Considerando que será necessário identificar as linhas correspondentes a cada produto, vamos obter o número das mesmas. Isso pode ser feito da seguinte forma:
## Passo 2 - Identificar e marcar/extrair as linhas de interesse
ancora <- grep("Product:", r4)
ancora## [1] 6 13
As linhas contendo os dados relativos ao produto Tape vão da linha 7 à 12 e as linhas contendo os dados relativoa ao produto Stapler vão da linha 14 até a última linha de r4, ou seja, a linha 17. Será necessário introduzir este valor na variável ancora acrescido de uma unidade. Mais adiante ficará esclarecida a razão deste acréscimo.
ancora <- c(ancora, length(r4) + 1)
ancora## [1] 6 13 18
Agora que sabemos onde inicia e termina as linhas contendo os dados de cada produto, vamos construir uma lista na qual cada componente refira-se a um produto e contenha as linhas a ele correspondentes.
Inicialmente vamos obter um vetor com os nomes dos produtos que será utilizado para dar nome aos componentes da lista que iremos criar.
nomesProdutos <- grep("Product:", r4, value=TRUE)
nomesProdutos <- gsub("Product:(.*)", "\\1", nomesProdutos)
nomesProdutos <- removeBrancos(nomesProdutos)
nomesProdutos## [1] "Tape" "Stapler"
Agora vamos criar a lista. A criação da lista exigirá um loop pelos nomes dos produtos.
lista <- list()
for(k in nomesProdutos){
i <- which(nomesProdutos == k)
inicio <- ancora[i]
fim <- ancora[i + 1]
bloco <- r4[(inicio + 1):(fim - 1)]
lista[[k]] <- txt2df(bloco,
colunas=c("SalesPerson", "Date", "Qty", "Price", "Class"),
inicio=c( 1, 18, 26, 36, 50),
fim=c(17, 25, 35, 49, 58))
}lista## $Tape
## SalesPerson Date Qty Price Class
## 1 Doe, John 09/23/98 1,120 11,225.60 AC
## 2 09/24/98 21,123 233,112.67 VA
## 3 09/27/98 23 32.22 CS
## 4 Wacks, Gene 09/01/98 3,766 3,455.55 AC
## 5 Peters, Kate 09/30/98 4,000 3,999.44 VA
## 6 09/02/98 1,653 6,775.55 OT
##
## $Stapler
## SalesPerson Date Qty Price Class
## 1 Perrol, Barb 09/13/98 3,320 11,225.60 AC
## 2 Zonker, Pete 09/11/98 766 453.53 AC
## 3 09/20/98 1,455 2,543.43 VA
## 4 Perkins, Joe 09/12/98 23 23.55 OT
Como podemos ver, temos uma lista onde cada componente consiste de um data frame contendo os dados relativos a um produto.
O próximo passo é juntar estes data frames e criar uma nova coluna para identificar a que produto pertence cada registro. Os comandos a seguir mostram como realizar esta tarefa.
## Juntar os data frames e identificar os registros
lista <- do.call(rbind, lista)
lista## SalesPerson Date Qty Price Class
## Tape.1 Doe, John 09/23/98 1,120 11,225.60 AC
## Tape.2 09/24/98 21,123 233,112.67 VA
## Tape.3 09/27/98 23 32.22 CS
## Tape.4 Wacks, Gene 09/01/98 3,766 3,455.55 AC
## Tape.5 Peters, Kate 09/30/98 4,000 3,999.44 VA
## Tape.6 09/02/98 1,653 6,775.55 OT
## Stapler.1 Perrol, Barb 09/13/98 3,320 11,225.60 AC
## Stapler.2 Zonker, Pete 09/11/98 766 453.53 AC
## Stapler.3 09/20/98 1,455 2,543.43 VA
## Stapler.4 Perkins, Joe 09/12/98 23 23.55 OT
## Remover os números que foram acrescidos ao fim dos nomes...
lista <- transform(lista, Produtos = sub("\\.\\d+$", "", row.names(lista)))
lista## SalesPerson Date Qty Price Class
## Tape.1 Doe, John 09/23/98 1,120 11,225.60 AC
## Tape.2 09/24/98 21,123 233,112.67 VA
## Tape.3 09/27/98 23 32.22 CS
## Tape.4 Wacks, Gene 09/01/98 3,766 3,455.55 AC
## Tape.5 Peters, Kate 09/30/98 4,000 3,999.44 VA
## Tape.6 09/02/98 1,653 6,775.55 OT
## Stapler.1 Perrol, Barb 09/13/98 3,320 11,225.60 AC
## Stapler.2 Zonker, Pete 09/11/98 766 453.53 AC
## Stapler.3 09/20/98 1,455 2,543.43 VA
## Stapler.4 Perkins, Joe 09/12/98 23 23.55 OT
## Produtos
## Tape.1 Tape
## Tape.2 Tape
## Tape.3 Tape
## Tape.4 Tape
## Tape.5 Tape
## Tape.6 Tape
## Stapler.1 Stapler
## Stapler.2 Stapler
## Stapler.3 Stapler
## Stapler.4 Stapler
## Mudar os nomes das linhas...
rownames(lista) <- 1:nrow(lista)
lista## SalesPerson Date Qty Price Class Produtos
## 1 Doe, John 09/23/98 1,120 11,225.60 AC Tape
## 2 09/24/98 21,123 233,112.67 VA Tape
## 3 09/27/98 23 32.22 CS Tape
## 4 Wacks, Gene 09/01/98 3,766 3,455.55 AC Tape
## 5 Peters, Kate 09/30/98 4,000 3,999.44 VA Tape
## 6 09/02/98 1,653 6,775.55 OT Tape
## 7 Perrol, Barb 09/13/98 3,320 11,225.60 AC Stapler
## 8 Zonker, Pete 09/11/98 766 453.53 AC Stapler
## 9 09/20/98 1,455 2,543.43 VA Stapler
## 10 Perkins, Joe 09/12/98 23 23.55 OT Stapler
Agora chegamos na etapa em que precisamos realizar o tratamento dos dados.
## Excluir os brancos antes e depois dos dados
lista <- as.data.frame(sapply(lista, removeBrancos), stringsAsFactors=FALSE)
## Converter para o formato numérico as colunas relativas a volores
lista$Qty <- as.numeric(sub(",", "", lista$Qty))
lista$Price <- as.numeric(sub(",", "", lista$Price))
## Preencher os brancos nos nomes dos vendedores...
nomes <- lista$SalesPerson[lista$SalesPerson != ""]
repete <- diff(c(which(lista$SalesPerson != ""), length(lista$SalesPerson) + 1))
lista$SalesPerson <- rep(nomes, repete)
str(lista)## 'data.frame': 10 obs. of 6 variables:
## $ SalesPerson: chr "Doe, John" "Doe, John" "Doe, John" "Wacks, Gene" ...
## $ Date : chr "09/23/98" "09/24/98" "09/27/98" "09/01/98" ...
## $ Qty : num 1120 21123 23 3766 4000 ...
## $ Price : num 11225.6 233112.7 32.2 3455.6 3999.4 ...
## $ Class : chr "AC" "VA" "CS" "AC" ...
## $ Produtos : chr "Tape" "Tape" "Tape" "Tape" ...
lista## SalesPerson Date Qty Price Class Produtos
## 1 Doe, John 09/23/98 1120 11225.60 AC Tape
## 2 Doe, John 09/24/98 21123 233112.67 VA Tape
## 3 Doe, John 09/27/98 23 32.22 CS Tape
## 4 Wacks, Gene 09/01/98 3766 3455.55 AC Tape
## 5 Peters, Kate 09/30/98 4000 3999.44 VA Tape
## 6 Peters, Kate 09/02/98 1653 6775.55 OT Tape
## 7 Perrol, Barb 09/13/98 3320 11225.60 AC Stapler
## 8 Zonker, Pete 09/11/98 766 453.53 AC Stapler
## 9 Zonker, Pete 09/20/98 1455 2543.43 VA Stapler
## 10 Perkins, Joe 09/12/98 23 23.55 OT Stapler
Vamos a mais um relatório, sendo que este, cujo “layout” apresentamos a seguir, é bem diferente dos anteriores.
Name: Jan Vandam
Address: 123 Somewhere Str
AnyTown, AL 12345
USA
Tel: 123-456-7890
Fax: 747-868-2938
Email: jan@hola.net
Contact: Pete Caliber
Name: Roland Rolse
Address: 456 Elsewher Ave
ThisTown JX1 TH8
UK
Tel: +44-171-456-7890
Fax: +44-171868-2938
Name: Rick Rikkel
Address: 1 St. Michael Str
Nowhere, XX 99999
USA
Email: Rik@Rik.com
Tel: 222-333-4444
Contact: Bill Doe
Os dados relativos a cada campo de um registro encontram-se localizados em linhas distintas. Também é possível observar que nem todos os registros possuem os dados relativos a todos os campos. Por exemplo, o registro relativo a Roland Rolse não possui dados relativos a Email e Contact. Também deve ser notado que os dados relativos ao endereço ocupam três linhas.
A abordagem para a importação dos dados relativos a este relatório pode ser semelhante à adotada para o relatório anterior, ou seja, colocar em uma lista as linhas relativas a cada registro e posteriormente realizar as manipulações necessárias à extração dos dados desejados. Vejamos como implementar a importação deste relatório.
## Ler o arquivo contendo o relatório
r5 <- readLines("Relatorio5.txt")## Warning in readLines("Relatorio5.txt"): linha final incompleta encontrada
## em 'Relatorio5.txt'
r5 <- r5[r5 != ""] # Excluir linhas em branco...## Definir as linhas âncoras para a criação da lista
ancora <- grep("^Name:", r5)
ancora <- c(ancora, length(r5) + 1)
ancora## [1] 1 9 15 22
## Obtenção dos nomes dos componentes das listas
nomes <- grep("^Name:", r5, value=TRUE)
nomes <- gsub("^Name:(.*)", "\\1", nomes)
nomes <- removeBrancos(nomes)
nomes## [1] "Jan Vandam" "Roland Rolse" "Rick Rikkel"
lista <- list()
for(k in nomes){
i <- which(nomes == k)
inicio <- ancora[i]
fim <- ancora[i + 1]
lista[[k]] <- r5[(inicio + 1):(fim - 1)]
}
lista## $`Jan Vandam`
## [1] "Address: 123 Somewhere Str" " AnyTown, AL 12345"
## [3] " USA" "Tel: 123-456-7890"
## [5] "Fax: 747-868-2938" "Email: jan@hola.net"
## [7] "Contact: Pete Caliber"
##
## $`Roland Rolse`
## [1] "Address: 456 Elsewher Ave" " ThisTown JX1 TH8"
## [3] " UK" "Tel: +44-171-456-7890"
## [5] "Fax: +44-171868-2938"
##
## $`Rick Rikkel`
## [1] "Address: 1 St. Michael Str" " Nowhere, XX 99999"
## [3] " USA" "Email: Rik@Rik.com"
## [5] "Tel: 222-333-4444" "Contact: Bill Doe"
Obtida a lista, agora vamos iniciar as manipulações para obter os dados necessários.
Address1 <- lapply(lista, function(x) x[grep("^Address:", x)])
Address2 <- lapply(lista, function(x) x[grep("^Address:", x) + 1])
Address3 <- lapply(lista, function(x) x[grep("^Address:", x) + 2])
Tel <- lapply(lista, function(x) x[grep("^Tel:", x)])
Fax <- lapply(lista, function(x) x[grep("^Fax:", x)])
Email <- lapply(lista, function(x) x[grep("^Email:", x)])
Contact <- lapply(lista, function(x) x[grep("^Contact:", x)])
Contact## $`Jan Vandam`
## [1] "Contact: Pete Caliber"
##
## $`Roland Rolse`
## character(0)
##
## $`Rick Rikkel`
## [1] "Contact: Bill Doe"
Neste processo os registros que não possuem todos os campos não tem valor para a informação correspondente o que é representado pela expressão character(0). Este é o caso, por exemplo, do campo Contact que não apresenta valor para Roland Rolse. Para podermos montar os data frames, estes valores vazios devem ser preenchidos. Nossa escolha será substituí-los por NA.
Os comandos a seguir ilustram como fazer isso.
Fax <- lapply(Fax, function(x) ifelse(length(x) == 0, NA, x))
Email <- lapply(Email, function(x) ifelse(length(x) == 0, NA, x))
Contact <- lapply(Contact, function(x) ifelse(length(x) == 0, NA, x))Agora podemos começar a montar o data frame.
r5 <- data.frame(Names=names(lista),
Address1=unlist(Address1),
Address2=unlist(Address2),
Address3=unlist(Address3),
Tel=unlist(Tel),
Fax=unlist(Fax),
Email=unlist(Email),
Contact=unlist(Contact))
r5## Names Address1
## Jan Vandam Jan Vandam Address: 123 Somewhere Str
## Roland Rolse Roland Rolse Address: 456 Elsewher Ave
## Rick Rikkel Rick Rikkel Address: 1 St. Michael Str
## Address2 Address3
## Jan Vandam AnyTown, AL 12345 USA
## Roland Rolse ThisTown JX1 TH8 UK
## Rick Rikkel Nowhere, XX 99999 USA
## Tel Fax
## Jan Vandam Tel: 123-456-7890 Fax: 747-868-2938
## Roland Rolse Tel: +44-171-456-7890 Fax: +44-171868-2938
## Rick Rikkel Tel: 222-333-4444 <NA>
## Email Contact
## Jan Vandam Email: jan@hola.net Contact: Pete Caliber
## Roland Rolse <NA> <NA>
## Rick Rikkel Email: Rik@Rik.com Contact: Bill Doe
Obtido o data frame, devemos fazer a limpeza dos dados.
## Excluir "Address:", "Tel:", "Fax:", "Email:" e "Contact:"
r5$Address1 <- gsub("^Address:(.+)", "\\1", r5$Address1)
r5$Tel <- gsub("^Tel:(.+)", "\\1", r5$Tel)
r5$Fax <- gsub("^Fax:(.+)", "\\1", r5$Fax)
r5$Email <- gsub("^Email:(.+)", "\\1", r5$Email)
r5$Contact <- gsub("^Contact:(.+)", "\\1", r5$Contact)## Remover os brancos antes e depois dos dados
r5 <- as.data.frame(sapply(r5, removeBrancos),stringsAsFactors=FALSE)## Modificar os nomes do data frame
row.names(r5) <- 1:nrow(r5)
r5## Names Address1 Address2 Address3
## 1 Jan Vandam 123 Somewhere Str AnyTown, AL 12345 USA
## 2 Roland Rolse 456 Elsewher Ave ThisTown JX1 TH8 UK
## 3 Rick Rikkel 1 St. Michael Str Nowhere, XX 99999 USA
## Tel Fax Email Contact
## 1 123-456-7890 747-868-2938 jan@hola.net Pete Caliber
## 2 +44-171-456-7890 +44-171868-2938 <NA> <NA>
## 3 222-333-4444 <NA> Rik@Rik.com Bill Doe
O nosso sexto e último relatório, cujo “layout” apresentamos a seguir, possui uma estrutura muito parecida com a do relatório número 4, diferindo daquele no fato de que o nome dos produtos vem abaixo das linhas contendo os dados a ele pertencentes.
Assim, a importacão deste relatório segue o mesmo procedimento utilizado para a importação do relatório número 4, sendo necessário apenas fazer os ajustes em razão da âncora neste relatório estar abaixo das linhas e não acima como no relatório 4.
----------------------------------------------------------------------------------
INVENTORY MASTER REPORT 12/31/1998
MAROON AUTO PARTS, INC.
----------------------------------------------------------------------------------
ITEM NO DESCRIPTION ITEM COST QTY INV COST LAST PURCH LAST SALE
219434342 GASKET SET 123.35 3 370.05 19980301 19980630
798734776 OIL PUMP 345.23 1 345.23 19970403 19960704
872375762 VALVE GUIDE 10.25 8 82.00 19980523 19980723
897987237 VALVE SPRING 4.95 8 39.60 19980523 19980723
987987765 PISTON SET 805.00 2 1,610.00 19980523 19930913
SUBTOTAL ENGINE PARTS 22 2,446.88
987293744 TORSION BAR 218.50 2 437.00 19980427 19981010
098230984 SWAY BAR 399.00 1 399.00 19981010 19970119
958430987 CV JOINTS 318.75 3 956.25 19881112 19980909
092834844 STRUT ASSEMBLY 449.00 3 1,347.00 19970617 19970530
SUBTOTAL SUSPENSION 9 3,139.25
GRANDTOTAL 31 5,586.13
Vamos à importação do relatório.
## Leitura do arquivo contendo o relatório
r6 <- readLines("Relatorio6.txt")## Warning in readLines("Relatorio6.txt"): linha final incompleta encontrada
## em 'Relatorio6.txt'
## Pré-preparo dos dados...
Produtos <- grep("^SUBTOTAL", r6)
itens <- grep("^ +\\d{9}", r6)
r6 <- r6[sort(c(itens, Produtos))]
r6## [1] " 219434342 GASKET SET 123.35 3 370.05 19980301 19980630"
## [2] " 798734776 OIL PUMP 345.23 1 345.23 19970403 19960704"
## [3] " 872375762 VALVE GUIDE 10.25 8 82.00 19980523 19980723"
## [4] " 897987237 VALVE SPRING 4.95 8 39.60 19980523 19980723"
## [5] " 987987765 PISTON SET 805.00 2 1,610.00 19980523 19930913"
## [6] "SUBTOTAL ENGINE PARTS 22 2,446.88 "
## [7] " 987293744 TORSION BAR 218.50 2 437.00 19980427 19981010"
## [8] " 098230984 SWAY BAR 399.00 1 399.00 19981010 19970119"
## [9] " 958430987 CV JOINTS 318.75 3 956.25 19881112 19980909"
## [10] " 092834844 STRUT ASSEMBLY 449.00 3 1,347.00 19970617 19970530"
## [11] "SUBTOTAL SUSPENSION 9 3,139.25"
Para facilitar as etapas posteriores, realizamos um “pré-processamento” dos dados com vistas a excluir as linhas indesejadas. Esta etapa pode consistir apenas em excluir as linhas em branco, como já feito anteriormente ou algo um pouco mais elaborado, como o que fizemos acima.
Na verdade não existe uma rigidez nestas etapas, a estrutura do relatório específico que se queira importar é que irá ditar o que será necessário fazer para que seja possível importá-lo.
As demais etapas serão semelhantes àquelas feitas para o relatório 4.
Vamos agora obter os nomes dos produtos para a criação da lista:
nomes <- grep("^SUBTOTAL", r6, value=TRUE)
nomes <- substr(nomes, 9, 38)
nomes <- removeBrancos(nomes)Agora vamos criar a lista. Antes, contudo, será necessário realizar uma pequena modificação no vetor r6 que consistirá em introduzir um item na posição 1 do vetor para facilitar o loop de criação da lista.
r6 <- c("", r6) # Inclusão de uma linha em branco na posição 1
ancora <- grep("^SUBTOTAL", r6)
ancora <- c(1, ancora)Observe que, em razão da identificação dos produtos a que se refere as linhas estar na parte inferior, houve a necessidade de se fazer alterações no vetor âncora. Agora podemos criar a lista.
lista <- list()
for(k in nomes){
i <- which(nomes == k)
inicio <- ancora[i]
fim <- ancora[i + 1]
bloco <- r6[(inicio + 1):(fim - 1)]
lista[[k]]<- txt2df(bloco, colunas=c("ITEM_NO", "DESCRIPTION", "ITEM_COST", "QTY", "INV_COST", "LAST_PURCH", "LAST_SALE"),
inicio=c( 1, 12, 30, 39, 45, 57, 70),
fim=c(11, 29, 38, 44, 56, 69, 82))
}
lista <- do.call(rbind, lista)
lista <- transform(lista, Produtos = sub("\\.\\d+$", "", row.names(lista)))
rownames(lista) <- 1:nrow(lista)
lista ## ITEM_NO DESCRIPTION ITEM_COST QTY INV_COST
## 1 219434342 GASKET SET 123.35 3 370.05
## 2 798734776 OIL PUMP 345.23 1 345.23
## 3 872375762 VALVE GUIDE 10.25 8 82.00
## 4 897987237 VALVE SPRING 4.95 8 39.60
## 5 987987765 PISTON SET 805.00 2 1,610.00
## 6 987293744 TORSION BAR 218.50 2 437.00
## 7 098230984 SWAY BAR 399.00 1 399.00
## 8 958430987 CV JOINTS 318.75 3 956.25
## 9 092834844 STRUT ASSEMBLY 449.00 3 1,347.00
## LAST_PURCH LAST_SALE Produtos
## 1 19980301 19980630 ENGINE PARTS
## 2 19970403 19960704 ENGINE PARTS
## 3 19980523 19980723 ENGINE PARTS
## 4 19980523 19980723 ENGINE PARTS
## 5 19980523 19930913 ENGINE PARTS
## 6 19980427 19981010 SUSPENSION
## 7 19981010 19970119 SUSPENSION
## 8 19881112 19980909 SUSPENSION
## 9 19970617 19970530 SUSPENSION
Agora é só realizar a limpeza e o tratamento dos dados.
## Excluir os brancos antes e depois
lista <- as.data.frame(sapply(lista, removeBrancos), stringsAsFactors=FALSE)## Converter para o formato numérico as colunas relativas a valores
lista$ITEM_COST <- as.numeric(sub(",", "", lista$ITEM_COST))
lista$QTY <- as.numeric(lista$QTY)
lista$INV_COST <- as.numeric(sub(",", "", lista$INV_COST))## Converter para o formato de data as colunas relativas a datas
lista$LAST_PURCH <- as.Date(lista$LAST_PURCH, "%Y%m%d")
lista$LAST_SALE <- as.Date(lista$LAST_SALE, "%Y%m%d")
str(lista)## 'data.frame': 9 obs. of 8 variables:
## $ ITEM_NO : chr "219434342" "798734776" "872375762" "897987237" ...
## $ DESCRIPTION: chr "GASKET SET" "OIL PUMP" "VALVE GUIDE" "VALVE SPRING" ...
## $ ITEM_COST : num 123.35 345.23 10.25 4.95 805 ...
## $ QTY : num 3 1 8 8 2 2 1 3 3
## $ INV_COST : num 370.1 345.2 82 39.6 1610 ...
## $ LAST_PURCH : Date, format: "1998-03-01" "1997-04-03" ...
## $ LAST_SALE : Date, format: "1998-06-30" "1996-07-04" ...
## $ Produtos : chr "ENGINE PARTS" "ENGINE PARTS" "ENGINE PARTS" "ENGINE PARTS" ...
lista## ITEM_NO DESCRIPTION ITEM_COST QTY INV_COST LAST_PURCH LAST_SALE
## 1 219434342 GASKET SET 123.35 3 370.05 1998-03-01 1998-06-30
## 2 798734776 OIL PUMP 345.23 1 345.23 1997-04-03 1996-07-04
## 3 872375762 VALVE GUIDE 10.25 8 82.00 1998-05-23 1998-07-23
## 4 897987237 VALVE SPRING 4.95 8 39.60 1998-05-23 1998-07-23
## 5 987987765 PISTON SET 805.00 2 1610.00 1998-05-23 1993-09-13
## 6 987293744 TORSION BAR 218.50 2 437.00 1998-04-27 1998-10-10
## 7 098230984 SWAY BAR 399.00 1 399.00 1998-10-10 1997-01-19
## 8 958430987 CV JOINTS 318.75 3 956.25 1988-11-12 1998-09-09
## 9 092834844 STRUT ASSEMBLY 449.00 3 1347.00 1997-06-17 1997-05-30
## Produtos
## 1 ENGINE PARTS
## 2 ENGINE PARTS
## 3 ENGINE PARTS
## 4 ENGINE PARTS
## 5 ENGINE PARTS
## 6 SUSPENSION
## 7 SUSPENSION
## 8 SUSPENSION
## 9 SUSPENSION
Esperamos que com os exemplos apresentados neste documento o leitor possa importar seus próprios relatórios.
Acompanhando este documento juntamos os relatórios nele utilizados e mais 5 outros (Relatorio7.txt, Relatorio.8.txt, Relatorio9.txt, Relatorio10.txt e XYZ_CORP.txt) que poderão ser utilizados para treinamento com base nos exemplos apresentados. Todos os arquivos contendo os relatórios estão contidos no arquivo Relatorios.zip.
Sistema Integrado de Administração Financeira para Estados e Municípios↩
Para efeito deste documento definiremos registo como o conjunto dos atributos de um item, os campos são onde os atributos de cada item estão especificados e as linhas são cada linha do arquivo a ser importado.↩
Para maiores informações sobre expressões regulares consultar: http://aurelio.net/er/apostilaconhecendo-regex.pdf Outra fonte é: https://www.rstudio.com/wp-content/uploads/2016/09/RegExCheatsheet.pdf↩