0% acharam este documento útil (0 voto)
167 visualizações223 páginas

Ling Uage MR Omega Data Science

Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
167 visualizações223 páginas

Ling Uage MR Omega Data Science

Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 223

Linguagem R

Primeiros passos para análise de dados

Wagner Hugo Bonat


 Ômega Escola Online de Ciência de Dados
[email protected]
 leg.ufpr.br/~wagner

Walmes Marques Zeviani


 Ômega Escola Online de Ciência de Dados
[email protected]
 leg.ufpr.br/~walmes
“I keep saying that the sexy job in the next
10 years will be statisticians, and I’m not
kidding.”
Hal Varian
Sumário

Prefácio 3
Contexto e motivação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Objetivos e público alvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Seleção dos tópicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1 Instalação do ambiente de trabalho 7


1.1 Instalando o R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Instalando o RStudio IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3 Conhecendo o RStudio IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4 Outros editores para o R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2 Primeiros passos com o R 29


2.1 Área de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2 Documentação interna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3 Arquivos da linguagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.4 Instalação e gerenciamento de pacotes . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.5 Operações aritméticas e lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

3 Estruturas de dados 45
3.1 Vetores atômicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.2 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3 Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4 Dados tabulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

4 Estruturas de controle e repetição 63


4.1 Estruturas de controle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.2 Estruturas de repetição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

5 Funções 77

1
5.1 Funções e seus componentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
5.2 Tratando exceções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
5.3 Aspectos avançados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5.4 De instruções para funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

6 Lidando com dados com o R base 85


6.1 Importando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
6.2 Arrumando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
6.3 Manipulando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6.4 Combinando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
6.5 Exportando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

7 Lidando com dados com o tidyverse 109


7.1 Importando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
7.2 Arrumando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
7.3 Manipulando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
7.4 Combinando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
7.5 Exportando dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

8 Estatística descritiva e exploratória com o R base 133


8.1 Tipos de variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
8.2 Análise univariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
8.3 Análise bivariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

9 Estatística descritiva e exploratória com o tidyverse 163


9.1 Tipos de variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
9.2 Análise univariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
9.3 Análise bivariada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

10 Praticando com o R base 195


10.1 Análise exploratória de crimes contra criança e adolescentes no Brasil . . . . . . . . . 195
10.2 Importando o conjunto de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
10.3 Preparando a base de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
10.4 Análise descritiva e exploratória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

11 Praticando com o tidyverse 207


11.1 Análise exploratória de crimes contra criança e adolescentes no Brasil . . . . . . . . . 207
11.2 Importando o conjunto de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
11.3 Preparando a base de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
11.4 Análise descritiva e exploratória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Prefácio

Contexto e motivação
O desenvolvimento da tecnologia da informação atrelado à disponibilidade cada vez maior de
dispositivos como smartphones e tablets conectados à internet vêm trazendo uma verdadeira revolução
em praticamente todas as áreas do conhecimento. A chamada Era da Informação vem alterando
drásticamente a forma como vivemos e interagimos como sociedade.

O grande volume de pessoas conectadas está revolucionando todas as formas de negócio.


Esta revolução é baseada na capacidade cada vez maior de armazenar e gerenciar dados de como as
pessoas se comportam em praticamente todos os aspectos de sua vida online. Todo esse fluxo de dados
vem se tornando o principal valor de muitos negócios e, em muitos casos, vital para o seu sucesso.
Um exemplo clássico é a empresa Google, detentora do buscador mais famoso do mundo, é uma das
maiores empresas de tecnologia da atualidade e está presente em nossas vidas 24 horas por dia sete
dias por semana.

Com toda esta geração de dados resultante do acesso à internet, empresas de todos os ramos
estão buscando extrair algum tipo de valor destas informações com o objetivo de atrair, manter ou
ainda melhorar a forma de se relacionar com seus clientes. Neste contexto fica evidente que empresas
que sabem lidar de forma efetiva com dados tem uma grande vantagem competitiva. Empresas são
formadas por pessoas, e assim surgiu a profissão denominada de Cientista de Dados. Trata-se de uma
profissão para a qual ainda muito se discute sobre suas atribuições, contudo é composta minimamente
de três habilidades chaves:

i) Conhecimento de ferramentas para análise e resumo de dados. Estas ferramentas em geral são
herdadas de uma área mais antiga chamada de estatística que vem há anos sendo o principal
motor da ciência como um todo.

ii) Conhecimento de ferramentas computacionais capazes de lidar com a quantidade e complexi-


dade crescente de dados. Nesta área entram as chamadas ferramentas de big data que em geral

3
são dominadas por profissionais da ciência da computação.

iii) E por fim, de nada serve conhecer métodos estatísticos e ferramentas computacionais sem saber
exatamente o que fazer com elas para resolver problemas relevantes e gerar valor por meio da
análise de dados. Isso só é possível tendo um conhecimento razoável da área de negócio em
que se está trabalhando.

Neste cenário, o uso de ferramentas computacionais que permitam analisar quantidades mas-
sivas de dados usando métodos estatísticos cada vez mais complexos é de suma importância. A lingua-
gem de programação R pela sua flexibilidade, poder, sofisticação e expressividade vem se tornando
uma das principais ferramentas do cientista de dados em todo o mundo.

O R (como vamos chamar o software daqui em diante) é uma linguagem e ambiente para
computação estatística e gráficos. É um projeto da GNU similar a linguagem S desenvolvida nos
Laboratórios Bell por John Chambers e seus coautores. O R surgiu em 1993 e é de autoria de Ross
Ihaka e Robert Gentleman, do Departamento de Estatística da Universidade de Auckland, na Nova
Zelândia. O R é um software livre e de código aberto sob os termos da Free Software Foundation’s
GNU General Public License. Pode ser facilmente instalado em uma grande variedade de plataformas
UNIX incluindo FreeBSD e Linux, Windows e MacOS.

Objetivos e público alvo


O objetivo deste livro é oferecer um texto introdutório e acessível para profissionais de diver-
sas áreas sobre os fundamentos da linguagem de programação R. É importante ressaltar que o texto
explica a linguagem R em sua essência ao invés de focar em alguns frameworks como, por exemplo, o
tidyverse. O objetivo é justamente pavimentar o caminho de um profissional que busca uma forma-
ção completa e sólida para analisar grandes volumes de dados utilizando a linguagem R e todo o seu
potencial, sem particularizar em nenhum framework.

O público-alvo são profissionais que desejam uma introdução acessível aos fundamentos da
linguagem R de forma rápida e padronizada. Tais fundamentos são necessários para o profundo en-
tendimento da linguagem e uma maior desenvoltura no uso de frameworks específicos de ciência de
dados e modelagem estatística avançada. Formações usuais destes profissionais incluem, mas não está
limitada à: engenharia, ciência da computação, economia, física, administração, gestão da informação
e tecnologia em análise e desenvolvimento de sistemas.

Seleção dos tópicos


Selecionar os tópicos para este livro não foi uma tarefa trivial dado a quantidade enorme de
recursos disponíveis na linguagem R. Optamos por uma descrição sucinta da sua instalação e confi-
guração padrão. Seguida de uma discussão das principais IDEs (Integrated Development Environment)
disponíveis. Buscamos orientar o leitor iniciante sobre qual IDE pode ser a mais adequada depen-
dendo do seu perfil. Neste material optamos por usar o RStudio por ser provavelmente a IDE mais
popular para R e considerada adequada para iniciantes em programação.

Seguimos com os primeiros passos na linguagem apresentando o código, a área de trabalho,


como acessar a documentação (tanto interna como a vasta documentação disponível na internet) e
os tipos de arquivos que o R gera para armazenar os resultados de uma análise. O R é um software
colaborativo; isso significa que existe uma comunidade unida e ativa desenvolvendo e contribuindo
com uma série de métodos e ferramentas para melhorar e expandir as capacidades da linguagem.
Tudo isso é disponibilizado para os usuários por meio de pacotes. Assim, apresentamos como instalar,
usar e gerenciar pacotes adicionais.

Passada esta ambientação inicial, seguimos para a apresentação das operações matemáticas e
lógicas da linguagem. Após as operações passamos para as estruturas de controle como if, else, switch e
cases, bem como as estruturas de repetição for, foreach, while, repeat e do-until. O conhecimento de tais
estruturas levam a um domínio maior da linguagem, principalmente para implementação de solução
de problemas não explorados.

Um aspecto importante do trabalho do cientista de dados é estar apto a construir grandes


algoritmos encadeados com estruturas bem definidas e ordenadas. Para isto, a construção de funções
é primordial. Nós apresentamos uma descrição detalhada da implementação de funções em R com
toda a especificidade da linguagem focada para a implementação computacional de técnicas estatísticas
e matemáticas. A partir deste momento você não pergunta mais se o R faz alguma coisa ou se tem
alguma técnica implementada. Você será capaz de implementar o que desejar mesmo que a linguagem
não tenha a funcionalidade nativa. Por fim, apresentamos as principais estratégias para importação de
arquivos de dados em diversos formatos para o R, bem como a sua manipulação usando a classe data
frame.

O texto foi escrito utilizando o sistema para análise reproduzível knitr. Por meio da lin-
guagem de marcação markdown e a estrutura de livro fornecida pelo pacote bookdown dentro da
linguagem R. É uma iniciativa da Ômega Data Science para formar uma geração de Cientistas de
Dados com forte fundamentação matemática e de computação estatística baseada em R.

W.H.B e W.M.Z

Curitiba, Junho, 2022.


Capítulo 1

Instalação do ambiente de trabalho

O R é uma linguagem de programação e portanto precisa ser instalada e configurada em seu


sistema operacional (Windows, Linux ou MacOs). Além disso, alguns softwares adicionais podem
ser úteis para lhe ajudar a programar de forma mais rápida e eficiente. As chamadas IDE’s (Integrated
Development Environment) são softwares que oferecem algumas facilidades para se programar em de-
terminada linguagem. Entre essas facilidades incluímos highlight de código, indentação automática,
acesso rápido e integrado a documentação, além de diversas outras vantagens que serão discutidas ao
longo do capítulo. Os objetivos deste capítulo são:

▶ Apresentar a instalação do software R seguindo a documentação oficial do CRAN (The Com-


prehensive R Archive Network).
▶ Apresentar e discutir os principais aspectos de algumas IDE’s populares para R incluindo o Rs-
tudio, Tinn-R, GNU Emacs, Vim e VS Code.
▶ Fornecer um guia geral sobre qual IDE escolher de acordo com o seu perfil.

1.1 Instalando o R
O R pode ser instalado nos três principais sistemas operacionais em uso: Windows, Linux e
MacOS. Devido a popularidade do sistema operacional Windows nós vamos descrever como fazer a
instalação do R neste sistema operacional. Porém, recomendamos que você migre assim que possível
para um ambiente Linux. Este foi o ambiente no qual escrevemos este livro e é o sistema operacional
que recomendamos para trabalhar com ciência de dados de forma geral. O ambiente MacOS partilha
de muitas similaridades com o Linux e vamos apenas indicar alguns materiais extra sobre a instalação
do R neste ambiente. Vale ressaltar que após a instalação o uso da linguagem R é idêntico em qualquer
um dos sistemas operacionais mencionados.

7
8 Capítulo 1. Instalação do ambiente de trabalho

1.1.1 Instalando o R no Windows


O passo-a-passo para instalar o R no Windows é o seguinte:

1. O primeiro passo é acessar o CRAN e selecionar a opção “Download R for Windows”. Proce-
dimento é ilustrado na Figura 1.1.

Figura 1.1: Captura de tela da página inicial do CRAN.

2. Você será redirecionado para a seguinte página, na qual deve selecionar a opção “install R for
the first time”. Procedimento é ilustrado na Figura 1.2.

Figura 1.2: Captura de tela da página de instalação do R para Windows.

3. Uma nova página será aberta, clique em “Download R X.X.X for Windows”. Nesta etapa um
arquivo executável será baixado em seu computador. Procedimento é ilustrado na Figura 1.3.

4. O arquivo executável aparecerá no canto inferior esquerdo do seu monitor, execute-o. Proce-
dimento é ilustrado na Figura 1.4.

Ômega · Escola de Data Science omegadatascience.com.br


1.1 9

Figura 1.3: Captura de tela da página para download do arquivo executável.

Figura 1.4: Captura de tela que mostra o executável no canto inferior esquerdo da tela.

5. Ao executar o programa, a tela de instalação será iniciada, selecione o idioma. Procedimento é


ilustrado na Figura 1.5.

Figura 1.5: Captura de tela que mostra a seleção de idioma para instalação do R.

6. Leia as informações e clique em próximo. Procedimento é ilustrado na Figura 1.6.

7. Escolha o local onde o R será salvo no computador, recomendamos seguir a sugestão do insta-
lador. Procedimento é ilustrado na Figura 1.7.

8. Selecione os componentes que devem ser instalados, recomendamos seguir a sugestão do insta-
lador. Procedimento é ilustrado na Figura 1.8.

9. Quanto as opções de inicialização, recomendamos aceitar o padrão. Procedimento é ilustrado

Ômega · Escola de Data Science omegadatascience.com.br


10 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.6: Captura de tela com as informações a respeito do R que o usuário deve saber antes da
instalação.

Figura 1.7: Captura de tela da seleção de local de instalação do R.

na Figura 1.9.

10. Informe onde o instalador deve colocar os atalhos do programa, recomendamos seguir a suges-
tão do instalador. Procedimento é ilustrado na Figura 1.10.

11. Selecione as tarefas adicionais, como criar atalhos na área de trabalho. Procedimento é ilustrado
na Figura 1.11.

12. Após estas etapas, finalmente o R será instalado, conforme ilustrado na Figura 1.12.

13. Conclua o instalador como ilustrado na Figura 1.13.

14. Procure pelo R no menu iniciar e abra-o, conforme procedimento ilustrado na Figura 1.14.

15. Pronto, o R está instalado na sua máquina e pronto para uso. A tela inicial do R é apresentada
na Figura 1.15.

Ômega · Escola de Data Science omegadatascience.com.br


1.1 11

Figura 1.8: Captura de tela que mostra a etapa de seleção dos componentes para instalação.

Figura 1.9: Captura de tela que mostra as opções de inicialização.

1.1.2 Instalando o R no Linux


O sistema operacional Linux tem diversas distribuições. Nesta seção descreveremos a instala-
ção do R em ambiente Debian onde uma das distribuições mais populares é o Ubuntu. Abra o terminal
Linux e siga os seguintes passos:

▶ Adicione a seguinte chave

apt-key adv --keyserver keyserver.ubuntu.com \


--recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9

▶ Adicione o seguinte endereço à lista de repositórios

sudo add-apt-repository \
”deb https://cloud.r-project.org/bin/linux/ubuntu $(lsb_release -cs)-cran40/”

▶ Atualize a lista de repositórios

sudo apt-get update

▶ Proceda com a instalação do R usando o comando apt-get install

Ômega · Escola de Data Science omegadatascience.com.br


12 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.10: Captura de tela com as opções de atalhos do R.

Figura 1.11: Captura de tela com as opções adicionais.

sudo apt-get install r-base

Note que no passo-a-passo anterior você precisa ser um super usuário (sudo), ou seja, precisa
ter privilégios para instalar softwares em sua distribuição Linux. Após cada comando usando a instru-
ção sudo a senha de super usuário do Linux será requisitada. Esse simples passo-a-passo irá instalar o
R em seu Linux.

Para acessar o R basta você abrir um novo terminal de comando e digitar R. Após esse processo
você deve ver um terminal Linux similar ao apresentado na Figura 1.16

Assim, concluímos com sucesso a instalação do R. Apesar de ser possível usar o R diretamente
pelo terminal Linux ou usando o R Terminal no Windows, tal estratégia é pouco usada por ser im-
produtiva. Em geral é bastante trabalhoso digitar o código direto no terminal. Além disso, o terminal
não oferece nenhum recurso de programação como highlight de código, indentação, acesso rápido e
com bom visual da documentação, entre outros. Por isso, recomendamos que você instale alguma
IDE (Integrated Development Environment). Na próxima seção nós vamos mostrar como instalar a IDE
RStudio e descrever alguns de seus aspectos gerais.

Ômega · Escola de Data Science omegadatascience.com.br


1.2 13

Figura 1.12: Captura de tela da barra de progresso da instalação.

Figura 1.13: Captura de tela da etapa final do instalador.

1.2 Instalando o RStudio IDE


O RStudio é uma IDE customizada para trabalhar com programação em R. A empresa RS-
tudio oferece uma versão gratuita da sua IDE, o RStudio Desktop, com versões disponíveis para os
sistemas operacionais mais populares (Linux, MacOS e Windows).

Para instalar o RStudio devemos seguir os seguintes passos:

▶ Acesse RStudio download e faça download da versão adequada para seu sistema operacional.

1.2.1 Instalando o RStudio IDE no Windows


Selecionando a opção de download para Windows você fará download de um arquivo com
extensão .exe. O seguinte conjunto de telas mostra o passo-a-passo até a instalação.

1. Acesse a página do RStudio, conforme ilustrado na Figura 1.17.

2. Em “Products”, selecione a opção “RStudio: The premier IDE for R”. Procedimento é ilustrado
na Figura 1.18.

Ômega · Escola de Data Science omegadatascience.com.br


14 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.14: Captura de tela do ícone do R no botão iniciar do Windows.

Figura 1.15: Captura de tela do R pronto para uso.

3. Você será redirecionado para a página apresentada na Figura 1.19.

4. Role a página até encontrar a opção de download do RStudio Desktop Open Source Edition,
conforme ilustrado na Figura 1.20.

5. Ao clicar na opção de download, você será redirecionado para a página apresentada na Figura
1.21.

6. Role a página até encontrar o botão de download, conforme Figura 1.22.

7. Ao clicar no botão de download, um arquivo executável será baixado e aparecerá no canto


inferior esquerdo do monitor, conforme Figura 1.23.

8. Abra o executável para iniciar a instalação, conforme Figura 1.24.

9. Escolha o local de instalação, recomendamos seguir o padrão. Procedimento é ilustrado na


Figura 1.25.

Ômega · Escola de Data Science omegadatascience.com.br


1.2 15

Figura 1.16: Captura de tela do terminal Linux com o R aberto.

Figura 1.17: Captura de tela da página do Rstudio.

10. Escolha a pasta do menu iniciar, recomendamos seguir o padrão, conforme Figura 1.26.

11. Com estas opções feitas, o RStudio será instalado. O procedimento é ilustrada na Figura 1.27.

12. Após a instalação, feche o instalador. O procedimento de encerramento é ilustrado na Figura


1.28.

13. Por fim, você pode abrir o RStudio e terá uma tela similar a apresentada na Figura 1.29.

1.2.2 Instalando o RStudio IDE no Linux


Caso o seu sistema operacional seja Linux você deve escolher a distribuição adequada. Nova-
mente vamos descrever a instalação para as distribuições Debian especificamente no Ubuntu. Após
fazer o download de um arquivo com extensão .deb você poderá usar o Gerenciador de Software do
Ubuntu para realizar a instalação.

1. Na página de download do RStudio selecione a distribuição. Procedimento é ilustrado na


Figura 1.30.

2. Será feito o download de um arquivo executável, ele aparecerá no canto inferior esquerdo da
tela, conforme ilustrado na Figura 1.31.

Ômega · Escola de Data Science omegadatascience.com.br


16 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.18: Captura de tela da aba ”Products”.

Figura 1.19: Captura de tela da página do produto Rstudio.

3. Ao abrir o executável você será redirecionado a uma tela do gerenciador de software do Ubuntu,
clique em instalar. Procedimento é ilustrado na Figura 1.32.

4. O RStudio será instalado (conforme Figura 1.33) e estará disponível e pronto para uso em seus
aplicativos.

5. Após a instalação você deverá ter a opção de abrir o software RStudio e verá uma tela similar a
apresentada na Figura 1.34.

Para o sistema MacOS o processo é similar e instruções mais detalhadas podem ser vistas em
Instalando RStudio no MacOS.

Ômega · Escola de Data Science omegadatascience.com.br


1.3 17

Figura 1.20: Captura de tela da página do produto Rstudio com as informações do RStudio Desktop
Open Source Edition.

1.3 Conhecendo o RStudio IDE


O objetivo desta seção é apresentar o RStudio IDE de forma ampla para que você possa
localizar as principais opções da ferramenta. Note que na captura de telas desta seção estamos usando
o Rstudio com o tema Dark. Figura 1.35 apresenta a janela do RStudio com seus quatro painéis
principais.

No painel 1 é onde você vai digitar o código R que será executado no terminal R, localizado no
painel 2. Se você acabou de instalar o R no seu computador ou iniciou uma sessão sem abrir nenhum
arquivo com extensão .R, não haverá nada no painel 1. Para criar um arquivo com extensão .R você
deve clicar em File > New File > R script ou usar o atalho Ctrl + Shift + N. Este arquivo pode
ser nomeado e salvo em qualquer pasta de sua preferência, para isso siga o caminho File > Save ou
use o atalho Ctrl + S.

O painel 3 apresenta diversas características do ambiente de trabalho, bem como o histórico


de códigos, conexões e o tutorial do RStudio. Por fim, no painel 4 são apresentados os arquivos da
pasta de trabalho, os gráficos que você vai criando durante a sua análise, os pacotes disponiveis e ins-
talados. No painel 4 também ficam disponíveis os arquivos de documentação do R. Note que grande
parte das informações e recursos necessários para a o processo de programação estão disponíveis e
podem ser facilmente acessados pela IDE.

Ômega · Escola de Data Science omegadatascience.com.br


18 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.21: Captura de tela da página de download do RStudio IDE.

Figura 1.22: Captura de tela da página de download do RStudio IDE com botão de download.

A Figura 1.36 apresenta todos os menus disponíveis dentro do RStudio.

De forma geral o Menu do RStudio é similar a qualquer software de edição de texto e é


bastante auto-explicativo. Algumas abas que merecem atenção são a Session que controla a execução
de códigos R e também o diretório de trabalho (mais detalhes no próximo Capítulo). A aba Tools
permite a instalação de pacotes extras. Dentro da aba Tools também é possível customizar alguns
aspectos da IDE como tamanho de letra, layout dos painéis, opções de código entre diversos outros.
Essas opções estão disponíveis na aba Tools → Global Options…. Figura 1.37 apresenta a janela de
opções de customização do RStudio.

A melhor forma de você conhecer o RStudio é explorando cada um de seus Menus e op-
ções. O RStudio já vem preparado para trabalhar com diversas tarefas envolvendo o R e também suas
interfaces para lidar com bancos de dados relacionais, elaboração de documentos dinâmicos e desen-
volvimento de aplicações web. Além disso tem integração com softwares de versionamento de código

Ômega · Escola de Data Science omegadatascience.com.br


1.4 19

Figura 1.23: Captura de tela que mostra o arquivo executável no canto inferior esquerdo da tela.

Figura 1.24: Captura de tela que mostra o instalador do RStudio.

como o git. O processo de criação de pacotes R é totalmente integrado a IDE e também é possível
usar outras linguagens como o Python e o C++. É realmente uma ferramenta completa e bastante fácil
de usar.

Recomendamos que o leitor busque dominar alguns atalhos do teclado que podem ser con-
sultados no próprio Menu, do lado direito de cada comando. Uma outra recomendação é trabalhar
sempre com a versão mais atual do RStudio e para projetos grandes usar o recurso de projetos. Todos
esses recursos serão explorados ao longo dos próximos capítulos.

1.4 Outros editores para o R


Em geral uma IDE é customizada para uma determinada linguagem. Apesar de que mui-
tas IDEs oferecem suporte a diversas linguagens simultâneamente. Para R existem diversas opções,
contudo editores que são multi-linguagem devem ser configurados para que seja possível trabalhar
com o R. Estes editores geralmente oferecem mais possibilidades de customização e nesta seção vamos
apresentar algumas opções e deixar algumas recomendações para quem está começando e para quem
já tem experiência em linguagens de programação.

Uma das primeiras opções para usuários Windows do R foi o editor Tinn-R. Trata-se de um
editor genérico de texto para o sistema operacional Windows que integra perfeitamento com o soft-
ware R. O editor possui interface gráfica (GUI) e também o ambiente integrado de desenvolvimento
(IDE). É um projeto registrado sob a Licença Pública Geral GPL, e portanto é um software livre.

Ômega · Escola de Data Science omegadatascience.com.br


20 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.25: Captura de tela que mostra a opção de escolha do local de instalação do RStudio no
computador.

Figura 1.26: Captura de tela que mostra a opção de escolha da pasta do menu iniciar.

Importante mencionar que tal editor é mantido e desenvolvido pelo pesquisador José Claudio Faria.
Figura 1.38 apresenta a tela do Tinn-R.

Um dos editores mais poderosos que integra com diversas linguagens de programação é o
GNU-Emacs. O GNU-Emacs está disponível para todos os principais sistemas operacionais e tam-
bém se enquadra na categoria de software livre. É um dos editores mais maduros e estáveis disponíveis,
continua moderno e em evolução. O GNU-Emacs foi o primeiro editor a dar suporte a linguagem R
por meio do módulo ESS (Emacs speaks statistics). Também por meio do ESS o GNU-Emacs oferece
suporte a outros softwares estatísticos como S-Plus, SAS, Stata, Julia entre outros. Além disso, ainda
existem variantes como Spacemacs e Doom-Emacs. A Figura 1.39 apresenta a tela do GNU-Emacs
customizada para a linguagem R.

O Vim é uma outra opção de editor também muito maduro e de propósito geral como o

Ômega · Escola de Data Science omegadatascience.com.br


1.4 21

Figura 1.27: Captura de tela que mostra a barra de progresso do instalador.

Figura 1.28: Captura de tela que mostra o encerramento do instalador.

GNU-Emacs. O suporte para a linguagem R é oferecido pelo plugin Nvim-R. Interessante mencionar
que tal plugin é desenvolvido por dois brasileiros: Jackson Alves de Aquino e José Claudio Faria. A
Figura 1.40 apresenta a tela do Vim já configurada para trabalhar com o R.

O editor VS-Code tem ganhado grande popularidade entre desenvolvedores de outras lin-
guagens como JavaScript, Python entre outras. O suporte para R também é por meio de um plugin.
Mais instruções podem ser encontradas neste endereço https://producaoanimalcomr.wordpress.com/
2020/05/18/utilizando-o-r-no-visual-studio-code/. A Figura 1.41 apresenta a tela do VS-Code cus-
tomizada para o R.

Por fim, existem diversos outros editores que oferecem suporte para a linguagem R; entre eles
citamos:

▶ Atom;
▶ RGedit;

Ômega · Escola de Data Science omegadatascience.com.br


22 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.29: Captura de tela que mostra o RStudio aberto.

▶ RKward IDE;
▶ NppToR.

Com tantas opções é natural pensar se existe um melhor ou mais adequada para cada usuário.
De forma geral, a escolha do editor ou da IDE acaba sendo uma escolha de cada programador.

Em suma, recomendamos as IDE’s para usuários iniciantes uma vez que a curva de aprendi-
zado é mais rápida. O ambiente já vem todo configurado para uso e as funcionalidades em geral são
simples e fáceis de encontrar. Por outro lado, IDE’s não oferecem muitas opções de customização e
são limitadas em termos de linguagens suportadas.

Os editores são mais gerais, altamente customizáveis e podem trabalhar com diversas lingua-
gens. Geralmente precisam ser configurados e customizados, o que torna seu uso recomendado para
programadores mais experientes e que precisem usar diversas linguagens.

Concluímos este Capítulo com o R e um ambiente integrado de desenvolvimento (o RStudio)


instalados. Agora estamos prontos para começar a escrever nossos primeiros códigos R.

Ômega · Escola de Data Science omegadatascience.com.br


1.4 23

Figura 1.30: Captura de tela que mostra a página de download do RStudio com as possíveis distribui-
ções.

Figura 1.31: Captura de tela que mostra o arquivo executável no canto inferior esquerdo da tela.

Figura 1.32: Captura de tela que mostra o gerenciador de software do Ubuntu.

Ômega · Escola de Data Science omegadatascience.com.br


24 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.33: Captura de tela que mostra a barra de progresso da instalação do RStudio no Ubuntu.

Ômega · Escola de Data Science omegadatascience.com.br


1.4 25

Figura 1.34: Captura de tela do terminal Linux com o R aberto.

Figura 1.35: Painéis do RStudio.

Ômega · Escola de Data Science omegadatascience.com.br


26 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.36: Menus do RStudio.

Figura 1.37: Janela de opções do RStudio.

Ômega · Escola de Data Science omegadatascience.com.br


1.4 27

Figura 1.38: Captura de tela Tinn-R.

Figura 1.39: Captura de tela - Emacs.

Ômega · Escola de Data Science omegadatascience.com.br


28 Capítulo 1. Instalação do ambiente de trabalho

Figura 1.40: Captura de tela - Vim.

Figura 1.41: Captura de tela VS-Code.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 2

Primeiros passos com o R

O R é uma linguagem de programação, e portanto trabalha com a ideia de interface de linha


de comando (command line interface). Isso significa que você deve escrever para a linguagem o que
quer que ela passe para o computador executar. Em termos de modo de uso temos duas opções:

1. Modo REPL (Read, Eval, Print and Loop): a ideia é escrever as instruções ou códigos e avaliá-
las imediatamente no console (Painel 2 do RStudio), que faz o papel de interpretador. Neste
modo o analista vai supervisionando o processo quase que comando a comando. Você escreve
o código, executa, avalia o resultado e segue acrescentando as instruções até obter o resultado
esperado. É a forma mais comum para análise interativa de dados. Em geral, no decorrer deste
livro, vamos usar este modo.

2. Modo Batch: a ideia deste modo é primeiro escrever toda uma sequência de códigos e depois
executá-la de uma única vez através de um terminal de comando. Esse modo é necessário em
ambientes de produção onde as instruções devem rodar sem a supervisão do programador.

Neste livro nós estamos usando o ambiente RMarkdown para mesclar código R e texto usual.
Assim, tudo que estiver após ## é o resultado da execução de uma instrução R. Para você executar
uma instrução R dentro do RStudio você deve posicionar o cursor na linha da instrução que deseja
executar e pressionar CTRL+ENTER.

Antes de começar, um pequeno esclarecimento: ao decorrer do livro mencionaremos coisas


como “mande o R executar tal tarefa”. No entanto, o R não executa nenhuma tarefa, quem executa as
tarefas é o computador. Quando usarmos este estilo de linguagem é apenas para economizar a escrita
de algo como “mande o computador executar tal tarefa por meio da escrita de uma linha de comando
da linguagem R”.

Dito isso, para começar, abra o RStudio, crie um arquivo com extensão .R clicando em File >
New File > R script. No Painel 1 digite 2 + 3 e tecle CTRL+ENTER para executar. O RStudio enviará
a instrução para ser executada em R e no Painel 2 será exibida a saída da instrução, deve aparecer algo
como:

29
30 Capítulo 2. Primeiros passos com o R

2 + 3

## [1] 5

Algo importante que devemos deixar claro já no começo de nossos estudos é a diferença entre
uma instrução e um comentário. Digite no Painel 1 os seguintes comandos:

Código 2.1. Ilustrando a diferença entre instrução e comentário.

# Faz uma soma


2 + 3

# Meu índice de massa corportal


83/1.85^2

# Quantos segundos tem um dia?


24 * 60 * 60

Uma instrução vai dizer ao R o que fazer, por exemplo, a instrução 2 + 3 diz para o R somar
os números 2 e 3. Por outro lado, tudo que vem após uma # em R é considerado um comentário. Os
comentários são apenas para documentar o que as instruções fazem e não são executados pelo R. Um
código com comentários relevantes é uma ajuda do seu eu de hoje para o seu eu do futuro, mas evite
comentários óbvios e ambíguos.

Conforme já mencionado, para executar uma instrução no RStudio você deve ao lado de
cada instrução digitar CTRL+ENTER. O código é enviado para o Painel 2 e executado pelo R. É muito
importante ter claro que é a linguagem R quem realmente faz o processamento da instrução, ou seja,
manda a solicitação da tarefa para o seu computador executar. O RStudio é apenas a interface para
você solicitar a execução da instrução pelo R. Fazemos este comentário pois um erro muito comum é
confundir IDE com linguagem.

Com relação às instruções, elas podem ocupar uma única linha ou várias linhas. É possível
também uma linha ter várias instruções. Veja os exemplos abaixo.

Código 2.2. Exemplo de instrução escrita em uma linha.

# Instrução em uma linha


2 + 2 + 7 + 5

## [1] 16

Código 2.3. Exemplo de instrução escrita em várias linhas.

# Instrução em várias linhas


2 +
2 +
7 +
5

## [1] 16

Ômega · Escola de Data Science omegadatascience.com.br


2.1 31

Código 2.4. Exemplo de duas instruções em uma linha.

# Várias instruções em uma linha


2 + 2; 7 + 5

## [1] 4

## [1] 12

Note que no caso de várias instruções em uma linha o caracter ; é obrigatório para distinguir
entre as instruções.

Algumas recomendações para ter um código limpo e legível são:

▶ Evite ultrapassar 72 ou 80 caracteres por linha.

▶ Mantenha o código devidamente indentado, no RStudio use a tecla de atalho CTRL+I para in-
dentação automática.

▶ Evite muitas instruções em uma linha.

2.1 Área de trabalho


Em um contexto de análise de dados é comum precisarmos executar um conjunto de ins-
truções coordenadas, onde a próxima instrução depende da anterior. Por exemplo, suponha que
desejamos calcular o índice de massa corporal (IMC) de uma pessoa. A fórmula matemática para
calcular o IMC é a seguinte:

P eso
IM C = .
Altura2

Temos que o IMC é igual ao peso dividido pela altura ao quadrado. Para executar tal tarefa
precisamos das seguintes informações: i) do peso e ii) da altura da pessoa. Vamos supor que o peso
seja 83kg e a altura seja 1.80m. Assim, temos os ingredientes para solicitar ao R que faça tal cálculo.
O primeiro passo é criar as quantidades peso e altura e atribuir os valores do nosso exemplo.

Código 2.5. Exemplo de atribuição de valores à objetos.

peso <- 83
altura <- 1.80

No Código 2.5 nós criamos os objetos peso e altura e atribuimos os valores 83 e 1.80. Note
que, diferente do que ocorre em outras linguagens, não foi necessário criar os objetos antes de atribuir
valores à eles. Além disso, usamos o operador de atribuição <-, leia-se RECEBE. O sinal de = também
pode ser usado como operador de atribuição. Porém, o <- é mais popular e recomendamos que você
o use. Com os objetos devidamente especificados, podemos criar um novo objeto chamado imc que
vai receber o valor da equação avaliada para o peso e altura do nosso exemplo.

Ômega · Escola de Data Science omegadatascience.com.br


32 Capítulo 2. Primeiros passos com o R

imc <- peso/altura^2


imc

## [1] 25.6

Note que ao atribuir a equação peso/altura^2 ao objeto imc o valor do objeto imc não é
mostrado na tela. Para mostrar o valor de um objeto executamos a instrução imc e o seu valor será
mostrado no console R, localizado no Painel 2.

Ao fazer essa sequência de atribuições são criados objetos no que chamamos de área de tra-
balho. Um objeto nada mais é do que um nome que você atribui para dados armazenados. Objetos
são úteis quando precisamos de uma mesma informação repetidas vezes no código, eles podem ser
reutilizados para criar outros objetos; podemos ainda reescrever objetos e até mesmo apagá-los. Para
listar os objetos disponíveis na sua área de trabalho usamos a função ls().

## Listando objetos da área de trabalho


ls()

## [1] ”altura” ”imc” ”peso”

Para trocar o valor de um objeto, simplesmente fazemos uma nova atribuição. Por exemplo,
suponha que a altura da pessoa não é 1.80m mas 1.70m.

# Nova altura
altura <- 1.70

# imc anterior
imc

## [1] 25.6

# novo imc
imc <- peso/altura^2
imc

## [1] 28.7

Uma característica importante é que mesmo após modificar o objeto altura o objeto imc não
é alterado. Para recalcular o imc precisamos re-executar a instrução R que calcula o imc.

Quando há a necessidade de apagar um objeto da área de trabalho usamos a função rm(). Por
exemplo, vamos remover o objeto imc.

rm(imc)

Agora, quando listamos novamente os objetos em nossa área de trabalho, o objeto imc não
estará mais lá.

ls()

Ômega · Escola de Data Science omegadatascience.com.br


2.1 33

## [1] ”altura” ”peso”

Quando você executa o comando ls() o R mostra para você o conteúdo do chamado
.GlobalEnv, ou seja, a área de trabalho global. Porém, existem diversos objetos em outros ambientes
ou espaços. Quando falamos em espaços falamos de pacotes. O R como um projeto colaborativo é
composto por uma grande quantidade de pacotes adicionais. A ideia é que, ao solicitar um objeto,
o R busca primeiro no .GlobalEnv. Ao não encontrar o objeto solicitado, o R começa a buscar em
outros espaços de trabalho. O comando search() mostra a lista de espaços de trabalhos onde o R
vai procurar os objetos e em qual ordem. Além disso, cada pacote tem o seu espaço, o chamado
namespace.

Por exemplo, vamos ver como acessar alguns conjuntos de dados nativos do R.

# O que temos no .GlobalEnv}


ls()

## [1] ”altura” ”peso”

# Data sets (comando head mostra só os 6 primeiros registros)


head(women)

## height weight
## 1 58 115
## 2 59 117
## 3 60 120
## 4 61 123
## 5 62 126
## 6 63 129

Note que o objeto women não existe no .GlobalEnv. Então, onde está o objeto women? Para
identificar a origem do objeto women usamos a função search()

search()

## [1] ”.GlobalEnv” ”package:stringr”


## [3] ”package:geobr” ”package:ggplot2”
## [5] ”package:dplyr” ”package:magrittr”
## [7] ”package:tidyr” ”package:readr”
## [9] ”package:knitr” ”package:latticeExtra”
## [11] ”package:lattice” ”package:bookdown”
## [13] ”tools:rstudio” ”package:stats”
## [15] ”package:graphics” ”package:grDevices”
## [17] ”package:utils” ”package:datasets”
## [19] ”package:methods” ”Autoloads”
## [21] ”org:r-lib” ”package:base”

Note que existem diversos espaços no caminho de busca do R. Por exemplo, podemos ver o
que está disponível dentro do pacote datasets.

ls(”package:datasets”)

Ômega · Escola de Data Science omegadatascience.com.br


34 Capítulo 2. Primeiros passos com o R

Dentro do pacote datasets temos 104 datasets incluindo o conjunto de dados women. Note
que não incluímos a saída do comando no livro para poupar espaço. No entanto, você deve executar
o comando e analisar a saída. Uma pergunta que pode surgir é o que acontece se criarmos um objeto
chamado women.

women <- c(”Gertrude Mary Cox”,


”Florence Nightingale David”)
ls()

## [1] ”altura” ”peso” ”women”

Agora o objeto women existe no .GlobalEnv. Porém, esse objeto não sobrescreveu o objeto
women, uma vez que estão em namespaces diferentes. O objeto women que existe no .GlobalEnv é apenas
um vetor de caracteres. Por outro lado, o objeto women no namespace datasets continua existindo
e sendo um data.frame. Porém, para acessá-lo é necessário especificar o espaço no qual você está
procurando.

head(datasets::women)

## height weight
## 1 58 115
## 2 59 117
## 3 60 120
## 4 61 123
## 5 62 126
## 6 63 129

Objetos e funções são os dois ingredientes básicos de toda a programação em R. Na verdade,


funções são também objetos R, porém com algumas características especiais. O R vem equipado com
um conjunto enorme de funções que você pode usar para realizar as mais variadas tarefas, desde a
simples exibição de um número até ajuste de modelos estatísticos altamente complexos. O uso de
uma função é muito simples e segue as premissas da notação matemática. Por exemplo, suponha que
você quer calcular o logaritmo neperiano do número 100. A função em R para esta tarefa é a função
log(). Assim,

log(10)

## [1] 2.3

retorna o valor desejado.

Outro exemplo é calcular o fatorial de um número. O fatorial de um número n é definido


por n! = n · (n − 1) · (n − 2) · (n − 3) . . . 3 · 2 · 1. Em R temos,

factorial(10)

## [1] 3628800

Ômega · Escola de Data Science omegadatascience.com.br


2.2 35

Para você começar a usar uma função, o ideal é verificar o que ela precisa para ser executada.
Em R os argumentos de uma função são as entradas que ela necessita para ser executada. Por exemplo,

args(log)

## function (x, base = exp(1))


## NULL

A função log() precisa da entrada x que é um número e tem um argumento extra chamado
de base que permite especificar em qual base o logaritmo deve ser calculado. Por default o valor do
argumento base é exp(1). Você pode usar outra base, por exemplo base 10.

log(10, base = 10)

## [1] 1

Algumas funções tem apenas um argumento como a função factorial().

args(factorial)

## function (x)
## NULL

E outras vão ter diversos argumentos, como a função lm() usada para ajustar modelos lineares.

args(lm)

## function (formula, data, subset, weights, na.action, method = ”qr”,


## model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
## contrasts = NULL, offset, ...)
## NULL

Neste momento, você deve estar se perguntando: Como saber o que fornecer para cada
argumento? É nesse ponto que consultar a documentação é fundamental. E esse é o assunto da nossa
próxima seção.

2.2 Documentação interna


Para aprender R existem diversos recursos, porém a documentação interna é sem dúvida uma
fonte de informações relevante. Contudo, precisamos saber consultá-la para aproveita-lá ao máximo.
Nesta seção, nós vamos discutir como usar a documentão interna do R de forma eficiente.

Nós ensinamos R há muitos anos e os alunos que estão começando sempre se assustam com
a necessidade de decorar um grande conjunto de comandos. Na verdade, esse é um sentimento que
todos temos quando começamos a programar. No entanto, hoje em dia com a quantidade de recursos
e documentação existentes não é uma preocupação que devemos ter. O importante é saber consultar
a documentação de forma eficiente.

Ômega · Escola de Data Science omegadatascience.com.br


36 Capítulo 2. Primeiros passos com o R

De forma geral a documentação do R está dividida em quatro tópicos: em R cada função e


objeto tem a sua própria documentação. Em alguns casos, para pacotes que fazem algumas análises
especificas, temos tutoriais que são chamados de vinhetas (vignettes). Além disso, existem funções que
vão te ajudar a encontrar o que você quer. Por fim, você pode consultar o Google onde a quantidade
de materiais disponível sobre o R é enorme.

Para acessar a documentação específica de uma função ou objeto podemos usar as funções ?
ou help(). Por exemplo, para consultar a documentação do objeto women fazemos:

# Opção 1
?women

# Opção 2
help(women)

A documentação será exibida no Painel 4 do RStudio.

Suponha que você não saiba exatamente o nome da função ou objeto para o qual você quer
consultar a documentação. Neste caso, você pode procurar por funções e objetos por meio de algum
termo de busca. Por exemplo, usando o termo de busca women e a função help.search() temos acesso
a toda a documentação interna que menciona o termo women. O Código 2.6 apresenta um exemplo
de tal estilo de procura.

Código 2.6. Exemplo de acesso a documentação por termo.

help.search(”women”)

Novamente, o resultado da procura será mostrado no Painel 4 do RStudio.

Uma outra forma de obter ajuda quando você não sabe exatamente o que está procurando
é usar a função apropos(). Basicamente, ela vai procurar por objetos no caminho de procura que
batem com o termo que você está procurando. Por exemplo, vamos consultar o que temos em nosso
caminho de busca que bate com o termo tukey.

apropos(”tukey”)

Neste caso, temos três objetos (você precisa executar o comando para ver os objetos). Agora
basta você consultar a documentação de cada um para descobrir qual é o que você está procurando.

Os vignettes são vínculados a pacotes específicos. Assim, você pode consultar todos os vignettes
disponíveis dentro de um pacote. Por exemplo, o pacote survival é muito popular em R para realizar
análise de sobrevivência. Este é um pacote bastante geral que tem diversas metodologias implementa-
das e tem diversos vignettes explicando em detalhes como usar as metodologias implementadas. Para
consultar os vignettes usamos a função browseVignettes(). O Código 2.7 apresenta como consultar
os vignettes do pacote survival.

Código 2.7. Exemplo de acesso a vignettes de um pacote.

Ômega · Escola de Data Science omegadatascience.com.br


2.2 37

browseVignettes(package = ”survival”)

Neste caso, o R abrirá uma nova janela em seu browser onde mostrará os títulos dos vignettes
disponíveis para o pacote solicitado.

Uma outra forma ainda mais geral de obter ajuda é procurar por um termo no site oficial do
R o r-project.org. O R fornece a função RSiteSearch() para você fazer tal busca direto do console R.
Por exemplo, vamos procurar opções para fazer um gráfico do tipo spider plot.

Código 2.8. Exemplo de acesso a procura no site r-project.org.

RSiteSearch(”spider plot”)

O R vai abrir uma nova janela em seu browser com os resultados da busca.

A documentação do R segue um padrão rigoroso em termos do que deve conter. Os campos


e seus respectivos conteúdos são os seguintes:

▶ Cabeçalho: indica o pacote.


▶ Título: título da função.
▶ Description: descrição do que o objeto é/faz.
▶ Usage: como usar ou fazer a chamada.
▶ Arguments: quais os argumentos formais da função.
▶ Value: o que a função retorna.
▶ Details: detalhes adicionais de implementação.
▶ Note: notas adicionais sobre uso e afins.
▶ See Also: referências para documentação relacionada.
▶ References: referências bibliográficas.
▶ Authors: autores da função.
▶ Examples: exemplos de uso.

Uma outra opção ainda mais geral que é útil quando você está começando em uma área
da estatística ou quer saber como a literatura está se desenvolvendo em algum campo especifico é
consultar o task view. Trata-se de uma parte da documentação do R que agrupa os diversos pacotes
em grandes áreas tais como: Bayesian, Finance, Machine Learning, Natural Language Processing e diversas
outras. Em cada uma destas seções você vai encontrar os principais pacotes da área e uma breve
descrição de suas funcionalidades.

Esta parte da documentação é realmente muito útil. Suponha por exemplo que uma tarefa
relacionada ao processamento natural da linguagem foi dada a você. Porém, você não entende nada
disso. Você pode consultar rapidamente o task view Natural Language Processing e ter uma visão do
que você consegue fazer com os pacotes já implementados em R.

Finalmente, apresentamos uma lista de outras funções que você pode usar para obter ajuda e
conhecer mais sobre funções e objetos R. Convidamos você a explorar a documentação de cada uma

Ômega · Escola de Data Science omegadatascience.com.br


38 Capítulo 2. Primeiros passos com o R

delas.

1. ls().
2. apropos().
3. help().
4. help.search().
5. help.start().
6. RSiteSearch().
7. example().
8. demo().
9. browseVignettes().
10. vignette().
11. str().
12. args().
13. class().
14. methods().
15. find().

Como apresentado nesta seção o R possui uma documentação completa e com diversas opções
para acesso. Assim, não se preocupe em decorar comandos. Quando necessário você pode consultar
a documentação e verificar a sintaxe adequada. É claro, com a experiência você vai acabar decorando
uma série de comandos que são usados diariamente e ganhando fluência na linguagem.

2.3 Arquivos da linguagem


O R é um ambiente completo para análise de dados que também busca oferecer ao programa-
dor um ambiente fácil de usar e customizável. Existem alguns arquivos que são gerados para ajudar
o usuário a programar cada vez mais rápido. Abaixo listamos alguns deles e a sua descrição.

▶ .Rhistory: a cada sessão R você vai digitar diversos comandos e executá-los no console R. O
arquivo .Rhistory guarda todos esses comandos. Por default ele é criado ao abrir a sessão R.
Eventualmente, se no seu diretório de trabalho (pasta do seu computador onde está o script R)
já existir um arquivo .Rhistory ele será carregado automaticamente. Por isso, tome cuidado
com o que você tem ou é carregado em sua área de trabalho (.GlobalEnv). É muito comum ao
iniciar um novo script R limparmos a área de trabalho com o comando rm(list=ls()). Porém,
o recurso de projetos disponibilizado pelo RStudio é uma forma mais elegante de garantir uma
sessão limpa para iniciar a sua programação.

▶ .RData: durante uma sessão de programação em R você vai gerar diversos comandos e objetos
como: funções, conjuntos de dados intermediários, gráficos, entre outros. O R fornece uma
forma de você gravar tudo isso em um arquivo para retomar quando quiser do ponto em que
parou: o chamado .RData. Esse arquivo binário serve para restaurar a sua área de trabalho entre

Ômega · Escola de Data Science omegadatascience.com.br


2.4 39

uma sessão e outra. Isso é útil quando você tem uma sequência de comandos que demora algum
tempo para ser executada. Em geral no dia-a-dia para processamento rápido não usamos esse
recurso, simplesmente executamos tudo novamente.

▶ .Rprofile: esse é um arquivo de configurações carregado ao dar início a uma sessão R. Ele per-
mite ao programador customizar alguns aspectos de todas as sessões R. Por exemplo, você pode
já no inicio da sessão deixar um conjunto de pacotes carregados, configurar uma mensagem de
boas-vindas, entre outros.

▶ .Rproj: esse arquivo define as configurações de um projeto. Está disponível apenas para o
RStudio IDE. Tal arquivo é salvo em seu diretório de trabalho. Para configurá-lo acesse no
RStudio Tools → Global Options. O recurso de projetos do Rstudio é bastante útil, porém
por considerarmos ser de certa forma avançado não vamos explorá-lo em detalhes neste livro
introdutório. Além disso, este não é um recurso da linguagem R e sim da IDE RStudio.

Como já mencionado, o diretório de trabalho é a pasta em seu computador onde o seu


script R está gravado. É muito importante saber onde você está trabalhando e também poder trocar o
seu diretório de trabalho quando necessário. Para essas tarefas temos as funções getwd(), que mostra
qual o seu diretório de trabalho atual, e a função setwd(), que permite definir qual será o diretório
de trabalho. Por exemplo, ao escrever este material eu estou trabalhando no meu computador dentro
de uma pasta chamada gitprojects que dentro tem uma pasta chamada RBASICO. Veja o que aparece
quando executo o comando getwd().

getwd()

## [1] ”/home/wagner/gitprojects/RBASICO”

Na saída aparece todo o caminho de pastas dentro do meu computador até chegar ao diretório
atual de trabalho. Suponha por exemplo que ao invés de trabalhar dentro da pasta RBASICO você queira
que o diretório de trabalho seja apenas a pasta gitprojects. Podemos facilmente trocar o diretório
de trabalho, usando a função setwd().

setwd(”/home/wagner/gitprojects”)

Uma outra função bastante útil é a função dir() que lista todo o conteúdo do seu diretório
de trabalho atual.

dir()

2.4 Instalação e gerenciamento de pacotes


Dentro do ambiente R a principal forma de contribuição da comunidade é por meio de paco-
tes. Os pacotes são coleções de funções e/ou conjuntos de dados organizados e documentados. Um
pacote R pode conter código R e também de outras linguagens como C, Fortran e C++. É importante

Ômega · Escola de Data Science omegadatascience.com.br


40 Capítulo 2. Primeiros passos com o R

ressaltar que alguns pacotes podem depender de bibliotecas do seu sistema operacional, as chamadas
libs. Neste caso, você terá que instalar tais libs no seu sistema operacional para poder usar o pacote.
Mas não se preocupe, em geral esse é um procedimento bastante simples.

Existem ao menos três formas de disponibilizar um pacote R para instalação:

1. Repositórios oficiais como o CRAN, Biocondutor e MRAN. Neste livro a menos que seja dito
o contrário nós vamos usar o CRAN. Quando usamos esse repositório, a instalação do pacote
é feita usando a função install.packages(”NOME_DO_PACOTE”).

2. Nestes mesmos repositórios você pode baixar um arquivo *.tar.gz* e fazer a instalação manual.
Isso é útil caso você precise instalar algum pacote em um computador que não tem acesso livre
a internet.

3. Outra fonte de pacotes R são os repositórios dos próprios desenvolvedores em plataformas de


versionamento de código como o Git, GitHub, GitLab, entre outros. Por exemplo, você pode
instalar o pacote mcglm usando o CRAN ou o GitHub. Os comandos são os seguintes:

## CRAN
install.packages(”mcglm”)

## GitHub
install.packages(”devtools”)
devtools::install_github(”wbonat/mcglm”)

Note que, para usar a função install_github() do pacote devtools, nós primeiro tivemos
que instalar o pacote devtools direto do CRAN. Além disso, para não carregar todo o namespace do
pacote devtools usamos o artificio de usar apenas a função que nos interessa especificando qual o
pacote (devtools) e a função (install_github()) ligados por ::.

Resumindo: precisamos instalar, carregar e as vezes também descarregar um pacote R. O


Código 2.9 ilustra como instalar, carregar e descarregar o pacote dplyr.

Código 2.9. Instalar, carregar e descarregar um pacote.

## Instala
install.packages(”dplyr”)

## Carrega
library(dplyr)

## Descarrega
detach(”package:dplyr”, unload = TRUE)

Após ter instalado um pacote você pode ver todo o seu conteúdo.

library(dplyr)
ls(”package:dplyr”)

É possível consultar a documentação completa.

Ômega · Escola de Data Science omegadatascience.com.br


2.5 41

help(package = ”dplyr”)

E ainda verificar o diretório de instalação do pacote.

system.file(package = ”dplyr”)

2.5 Operações aritméticas e lógicas


Nesta seção nós vamos mostrar de que forma usar o R como uma potente calculadora ci-
entífica. O R vem nativamente equipado com um grande arsenal de funções matemáticas e lógicas.
Isso significa que você pode começar a usá-las imediatamente. As operações aritméticas básicas são
apresentadas no Código 2.10.

Código 2.10. Operações aritméticas básicas.

2 + 3 # Soma.
2 - 3 # Subtração.
2 * 3 # Multiplicação.
2/3 # Divisão.
2^3 # Potenciação.
2^(1/3) # Radiciação.
10 %% 3 # Resto.
10 %/% 3 # Parte inteira.

De forma similar, temos diversas funções trigonométricas como apresentado no Código 2.11.

Código 2.11. Funções trigonométricas.

sin(3) # Seno.
cos(3) # Cosseno.
tan(3) # Tangente.
asin(0.5) # Arco seno.
acos(0.5) # Arco cosseno.
atan(0.5) # Arco tangente.

Também existem diversas funções para resumir dados usando técnicas estatísticas como mé-
dia, mediana, desvio-padrão, quantis entre outras, conforme ilustrado no Código 2.12.

Código 2.12. Algumas funções para obter estatísticas.

y <- c(1.85, 1.78, 1.81, 1.69, 1.71)


mean(y) # Média.
median(y) # Mediana.
sd(y) # Desvio-padrão amostral.
var(y) # Variância amostral.
max(y) # Máximo.
min(y) # Mínimo.
length(y) # Número de valores.

Ômega · Escola de Data Science omegadatascience.com.br


42 Capítulo 2. Primeiros passos com o R

Funções matemáticas como exponenciais, logaritmos, gama, beta, entre outras, também estão
prontamente disponíveis, conforme mostra o Código 2.13.

Código 2.13. Algumas funções matemáticas especiais.

exp(2) # Exponencial neperiano.


log(10) # Neperiano.
log10(10) # Base 10.
log2(10) # Base 2.
log(10, base = 5) # Base qualquer.
gamma(10) # Função gamma
beta(2) # Função beta

O R é uma ferramenta completa para computação científica. Praticamente qualquer função


matemática está implementada nativamente ou em alguns de seus pacotes. Você pode usar as ferra-
mentas que apresentamos nas seções anteriores para procurar a função que você precisar.

Não podemos deixar de mencionar os operadores lógicos. Tratam-se de expressões que nos
permitem decidir se uma determinada condição é VERDADEIRA ou FALSA. Por exemplo, pode ser
de interesse comparar se dois valores são iguais, diferentes, se um é maior ou menor do que o outro
e assim por diante. O Código 2.14 apresenta os principais operadores lógicos em R.

Código 2.14. Ilustrando operadores lógicos.

x <- 3
y <- 4
2 == 2 # São iguais?
2 != 2 # São diferentes?
x <= y # x é menor ou igual a y?
x >= y # x é maior ou igual a y?
x > y # x é maior do que y?
x < y # x é menor do que y?

Note que para todas as perguntas em 2.14 uma resposta lógica (TRUE ou FALSE) é retornada.
Podemos ir mais longe e combinar operações lógicas com os operadores & leia-se E, OR leia-se OU e
NOT leia-se NEGAR. Por exemplo,

# Leia-se: 2 é menor que 5? E 7 é maior ou igual a 3?


(2 < 5) & (7 >= 3)
# Leia-se: 2 é menor que 5? OU 7 é maior ou igual a 3?
(2 < 5) | (7 >= 3)
# Leia-se: 2 é menor que 5? Negar
!(2 < 5)

Novamente uma resposta lógica será retornada.

Em alguns casos precisamos de alguns objetos especiais. Em particular quatro tipos são muito
populares:

▶ NA: para valores ausentes.


▶ NULL: para objetos vazios.

Ômega · Escola de Data Science omegadatascience.com.br


2.5 43

▶ Inf e -Inf: para infinitos.


▶ NaN: para resultados não razoavelmente definidos.

O Código 2.15 ilustra o uso de cada um deles.

Código 2.15. Tipos especiais de objetos.

5 + NA # O resultado é NA.
is.na(5 + NA) # Verifica se é NA.
10 + NULL # Retorna objeto vazio.
is.null(NULL) # Verifica se é vazio.
5/0 # Infinito.
is.finite(5/0) # Verifica se é finito.
0/0 # Valor indeterminado.
is.nan(0/0) # Verifica se é not a number.

Abaixo deixamos alguns cartões de referência para consulta futura. Recomendamos escolher
alguns e deixar sempre à mão.

▶ R Reference Card
▶ R Reference Card · Statistics
▶ R base
▶ R base · PT
▶ RStudio IDE
▶ RStudio IDE · PT

Neste Capítulo demos os primeiros passos com a linguagem R. Aprendemos a dar instruções
ao R, criar e manipular objetos. Usar algumas funções elementares, discutimos quais arquivos o R
gera e para que serve cada um. Entendemos onde o R está trabalhando e como mudar o diretório de
trabalho. Discutimos como instalar e gerenciar pacotes adicionais e por fim, operações aritméticas e
lógicas elementares foram apresentadas. Estamos aptos a caminhar na direção de analisar dados com o
R e para isso precisamos aprender quais são as estruturas de dados em R, assunto do próximo Capítulo.

Ômega · Escola de Data Science omegadatascience.com.br


44 Capítulo 2. Primeiros passos com o R

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 3

Estruturas de dados

Para entender a estrutura da linguagem R precisamos saber que praticamente tudo em R é um


objeto. Objetos têm dois aspectos importantes para se conhecer: tipo (type) e classe (class). Temos
que saber qual é o tipo de um objeto para saber o que é possível fazer com ele. A classe de um objeto
vai dizer quais métodos podemos aplicar. Esses aspectos ficarão mais claros ao decorrer do livro.

Na maioria das vezes, ao lidar com dados em R, você vai carregar ou ler um conjunto de
dados de alguma fonte externa, tais como de um simples arquivo de texto pleno tipo .csv ou .txt,
sistemas de planilhas eletrônicas como o Excel ou até mesmo de um banco de dados relacional como
o MySQL. Porém, para você entender o que o R faz quando carrega esses conjuntos de dados é
necessário conhecer as estruturas de dados presentes no R e suas principais características.

Os principais tipos de objetos em R em ordem de generalidade são:

▶ Caracteres (character);
▶ Números reais (double e numeric);
▶ Números inteiros (integer);
▶ Lógico (logical);
▶ Complexo (complex).
▶ Raw (raw).

Note que temos 3 categorias para representar valores numéricos: double, numeric e integer.
O tipo numeric em R basicamente agrupa os tipos double e integer. Por exemplo,

inteiro <- 10L


real <- 10

is.numeric(inteiro)

## [1] TRUE

is.numeric(real)

45
46 Capítulo 3. Estruturas de dados

## [1] TRUE

is.double(inteiro)

## [1] FALSE

is.double(real)

## [1] TRUE

is.integer(inteiro)

## [1] TRUE

is.integer(real)

## [1] FALSE

Para facilitar, quando estivermos falando sobre números de forma geral, sejam inteiros ou
reais vamos relacionar a classe numeric. Só vamos distinguir quando estivermos tratando de números
inteiros e houver necessidade de fazer uso do tipo integer. Por isso, na lista acima colocamos double
e numeric na mesma linha.

O que chamamos de conjuntos de dados ou dados de forma geral nada mais são do que
combinações estruturadas dos tipos de objetos descritos acima. Como organizar ou estruturar tais
dados é o que chamamos de estruturas de dados. O R vem equipado com diversas estruturas para
trabalhar com dados. Essas estruturas recebem o nome genérico de classes (class()).

As mais importantes são:

▶ atomic vector(vetores atômicos): a característica mais importante dos vetores é que todos os
seus elementos devem ser do mesmo tipo. É a estrutura mais simples para trabalhar com dados
em R. Na realidade, as outras estruturas são de alguma forma construídas baseadas em vetores
atômicos.

▶ matrix (matrizes): a classe matrix implementa a álgebra matricial usual em matemática. Você
pode pensar uma matriz como sendo um conjunto de vetores, empilhados ou colocados lado a
lado. Novamente, todos os elementos dentro de uma matriz devem ser do mesmo tipo.

▶ list (lista): a classe list, apesar de técnicamente ser também um vetor, é uma das estruturas
mais gerais para trabalhar com dados em R. Isso se deve ao fato de que os elementos dentro de
uma lista podem ser de tipos diferentes.

▶ data.frame (tabela): A classe data.frame é de certa forma uma simplificação da classe list. Na
verdade um data.frame é simplesmente uma lista bidimensional. É a classe mais usada para
armazenar dados para análise estatística em R. Você pode pensar na classe data.frame como o
equivalente a uma tabela do Excel em termos de formato, já que trata-se de uma estrutura que

Ômega · Escola de Data Science omegadatascience.com.br


3.1 47

agrupa vetores em um tabela bidimensional em que cada coluna pode conter um tipo diferente
de dado. Porém, dentro de cada coluna todos os registros devem ser do mesmo tipo.

Vamos discutir cada uma destas estruturas em detalhes nas seções seguintes.

3.1 Vetores atômicos


Quando combinamos diversos objetos de mesmo tipo em um único objeto dizemos que
temos um vetor atômico (atomic vector). Um vetor nada mais é do que um conjunto de elementos
enfileirados. É importante ressaltar que todos os elementos dentro de um vetor terão o mesmo tipo.
Por exemplo,

vetor_numerico <- c(1, 5, 11, 33)


vetor_numerico

## [1] 1 5 11 33

O objeto vetor_numerico é um vetor numérico. Note que o operador de concatenação c()


de certa forma junta os valores numéricos em um único objeto que chamamos de vetor. Uma dúvida
muito recorrente é por que o nome vetor_numerico?

O R permite nomear objetos de forma bastante geral. Um nome pode consistir de letras,
números (dígitos), e _. No entanto, um nome não pode começar com _ ou um dígito. Além disso,
você não pode usar nenhuma das palavras reservadas, tais como, TRUE, FALSE, NULL, if entre outras.
Veja a documentação detalhada usando ?Reserved. Um nome que não seguir essas restrições será
considerado non-syntactic name e o R vai retornar um erro.

Você pode usar o nome que achar mais conveniente, desde que este nome atenda às men-
cionadas restrições. Em geral, recomendamos usar nomes simples e autoexplicativos considerando o
contexto que você está trabalhando. Podemos também facilmente definir um vetor de caracteres

vetor_caracter <- c(”hello”, ”world”)

e até mesmo um vetor lógico, como

vetor_logico <- c(TRUE, TRUE, FALSE)

por fim, podemos ainda combinar diversos vetores em um grande vetor

vetor_combinado <- c(vetor_numerico, vetor_caracter, vetor_logico, ”boo”)

Um aspecto importante quando concatenamos vetores é a chamada coerção. Ao concatenar


vetores numéricos com lógicos ou caracteres o R precisa decidir qual será o tipo do vetor resultante.
De forma geral, o R vai sempre escolher o tipo mais geral. Por exemplo, ao concatenar um vetor
numérico com um lógico o resultado será um vetor numérico. O R converte a estrutura lógica para

Ômega · Escola de Data Science omegadatascience.com.br


48 Capítulo 3. Estruturas de dados

números 1, caso TRUE ou 0, caso FALSE. Por outro lado, ao concatenar um vetor númerico com um
vetor de caracteres o mais geral é o caracter. Então, o R irá converter todos os números para caracteres
e o tipo do vetor resultante será caracter.

Para consultar qual é o tipo de um objeto usamos a função is.*. No lugar do * colocamos
o nome do objeto que queremos avaliar. Por exemplo, para saber se um objeto é do tipo numérico
executamos is.numeric() a resposta será sempre um resultado lógico. Veja os exemplos no Código
3.1.

Código 3.1. Exemplos de consulta do tipo de um objeto.

# Funções que começam com is.


#apropos(”^is\\.”)
is.integer(1)
is.numeric(1)
is.integer(1L)
is.numeric(1L)
is.character(”Curitiba”)
y <- factor(c(”Solteiro”, ”Casado”))
is.factor(y)
is.character(y)
is.logical(c(TRUE, FALSE))

Uma outra opção é usar a função typeof().

x <- ”caracter”
typeof(x)

## [1] ”character”

x <- 10
typeof(x)

## [1] ”double”

x <- 10L
typeof(x)

## [1] ”integer”

x <- TRUE
typeof(x)

## [1] ”logical”

É possível também converter o tipo de um objeto para outro. Por exemplo,

x <- 10
is.numeric(x)

## [1] TRUE

Ômega · Escola de Data Science omegadatascience.com.br


3.1 49

x <- as.logical(x)
is.numeric(x)

## [1] FALSE

Note que criamos um objeto chamado de x que contem o valor 10. Esse objeto foi criado pelo
R como um numeric. Depois convertemos esse objeto para o tipo logical. Assim, quando consulta-
mos a sua classe como numeric recebemos o lógico FALSE. O R é uma linguagem automaticamente
tipificada, isso significa que quando você criar um objeto, o R vai automaticamente atribuir um tipo
a ele. Obviamente, nem sempre o tipo que o R atribui é o desejado. Portanto, fique atento a essa
característica do R.

Outro aspecto importante é a classe (class) de um objeto R. Os métodos vão se orientar pela
classe para saber o que é possível fazer com um determinado objeto. Métodos são funções genéricas
do R que atuam de forma diferente de acordo com o tipo de objetos as quais são aplicadas. Por fim,
alguns objetos podem conter metadados que em R são chamados de atributos.

O Código 3.2 cria um vetor numérico, acessa sua classe e os métodos associados.

Código 3.2. Acessando a classe e métodos de um objeto.

# Um vetor numérico.
x <- c(1, 2, 3)
class(x)

## [1] ”numeric”

methods(class = ”numeric”)

## [1] all.equal as.data.frame as.Date as.POSIXct


## [5] as.POSIXlt as.raster barchart bwplot
## [9] coerce densityplot dotplot ecdfplot
## [13] full_seq histogram Ops qqmath
## [17] recode scale_type stripplot units<-
## see ’?methods’ for accessing help and source code

Veja que para um objeto da classe numeric você tem diversas opções de ações. Você pode
fazer por exemplo, um histograma (histrogram), um gráfico da distribuição acumulada (ecdfplot),
converter para um objeto da classe data.frame, ou mesmo para a classe Date e assim por diante.

Vamos criar um outro vetor numérico, porém agora com um atributo adicional.

Código 3.3. Acessando a classes e atributos de um objeto.

# Numérico mas com valores nomeados.


notas <- c(”João” = 7.8,
”Bianca” = 10,
”Eduarda” = 8.5)
class(notas)

## [1] ”numeric”

Ômega · Escola de Data Science omegadatascience.com.br


50 Capítulo 3. Estruturas de dados

attributes(notas)

## $names
## [1] ”João” ”Bianca” ”Eduarda”

names(notas)

## [1] ”João” ”Bianca” ”Eduarda”

Neste exemplo, o atributo foi o nome, porém de forma geral um objeto R pode ter diversos
atributos dependendo de sua classe. Uma outra característica de um vetor é o seu tamanho (length).
A função length() acessa o tamanho de um vetor, por exemplo,

length(notas)

## [1] 3

Para lidar com dados em R é útil saber criar sequências e repetições de números de forma
estruturada. Uma outra tarefa que aparece com frequência em estatística e aprendizagem de máquina
é a geração de números aleatórios. O R fornece funções para rapidamente gerar sequências, repetições
e números aleatórios.

Para criar sequências regulares usamos a função seq() conforme ilustrado no Código 3.4.

Código 3.4. Exemplos de uso da função seq().

# Sequencia de 1 a 7
1:7

## [1] 1 2 3 4 5 6 7

# Sequencia de 1 a 10 de 2 em 2
seq(from = 1, to = 10, by = 2)

## [1] 1 3 5 7 9

# Sequencia de 1 a 20 de tamanho 7
seq(from = 1, to = 20, length.out = 7)

## [1] 1.00 4.17 7.33 10.50 13.67 16.83 20.00

# Sequencia começando em 1 de tamanho sete de 2 em 2.


seq(from = 1, by = 2, length.out = 7)

## [1] 1 3 5 7 9 11 13

De forma similar, para criar repetições usamos a função rep() conforme ilustra o Código 3.5.

Código 3.5. Exemplos de uso da função rep().

Ômega · Escola de Data Science omegadatascience.com.br


3.1 51

# Repita o 0 5 vezes
rep(0, 5)

## [1] 0 0 0 0 0

# Repita a sequencia 1 a 3, 2 vezes


rep(1:3, times = 2)

## [1] 1 2 3 1 2 3

# Repita a sequencia 1 a 3, cada número 2 vezes


rep(1:3, each = 2)

## [1] 1 1 2 2 3 3

Dada uma sequência, podemos ter interesse em obter uma amostra aleatória desta sequência.
Para isso, usamos a função sample() conforme ilustrado no Código 3.6.

Código 3.6. Exemplos de uso da função sample().

# Retire uma amostra aleatório de tamanho 10


# de uma sequencia de 1 a 20 sem reposição.
sample(1:20, size = 10, replace = FALSE)

## [1] 15 9 1 2 14 11 5 20 3 13

# Retire uma amostra de tamanho 10 da sequencia


# ”a”, ”b”, ”c” de tamanho 10 com reposição.
sample(c(”a”, ”b”, ”c”), size = 10, replace = TRUE)

## [1] ”b” ”b” ”c” ”b” ”b” ”c” ”a” ”a” ”b” ”a”

Por fim, podemos simular amostras aleatórias de acordo com distribuições de probabilidade
como a uniforme e normal. Se você não conhece essas distribuições não se preocupe, apenas fique
com essa possibilidade na memória.

# 10 amostras da distribuição uniforme entre 0 e 1


runif(n = 10, min = 0, max = 1)

## [1] 0.586 0.877 0.813 0.381 0.231 0.825 0.927 0.696 0.911 0.831

# 10 amostras da distribuição Normal com média 1.80 e desvio-padrão 0.1


rnorm(n = 10, mean = 1.80, sd = 0.1)

## [1] 1.81 1.84 1.81 1.75 1.90 1.72 1.90 1.90 1.77 1.79

Tendo um vetor, podemos ter interesse em selecionar apenas alguns elementos que tenham
alguma característica importante, ou ainda, por nome ou posição. Além disso, podemos querer mo-
dificar, remover ou adicionar elementos.

Ômega · Escola de Data Science omegadatascience.com.br


52 Capítulo 3. Estruturas de dados

Para selecionar por posição usamos a seguinte sintaxe nome_objeto[posicao]. Por exemplo,

## Criando vetor numérico nomeado.


notas <- c(”João” = 7.8,
”Bianca” = 10,
”Eduarda” = 8.5,
”Felipe” = 7.0,
”Márcia” = 6.5)
notas[1] # A posição 1.

## João
## 7.8

notas[5] # A posição 5.

## Márcia
## 6.5

notas[1:2] # Um intervalo.

## João Bianca
## 7.8 10.0

notas[c(1, 3)] # Um conjunto.

## João Eduarda
## 7.8 8.5

notas[-1] # Remove.

## Bianca Eduarda Felipe Márcia


## 10.0 8.5 7.0 6.5

No caso de seleção condicional combinamos as operações lógicas com a posição dos elemen-
tos. Neste caso criamos o que chamamos de máscara lógica. Por exemplo,

# Alunos com nota maior que 7.0


mask <- notas > 7.0
mask

## João Bianca Eduarda Felipe Márcia


## TRUE TRUE TRUE FALSE FALSE

notas[mask]

## João Bianca Eduarda


## 7.8 10.0 8.5

# Alunos com nota maior que 9.0


notas[notas > 9.0]

## Bianca
## 10

A seleção por nome pode ser realizada como descrito abaixo.

Ômega · Escola de Data Science omegadatascience.com.br


3.1 53

# Seleciona valores pelo nome associado.


notas[”João”]

## João
## 7.8

notas[c(”Márcia”, ”Eduarda”)]

## Márcia Eduarda
## 6.5 8.5

Para modificar o conteúdo de um vetor simplesmente selecionamos a posição que desejamos


alterar e fazemos uma atribuição.

# Atribui nota para um aluno.


notas[”João”] <- 0
notas

## João Bianca Eduarda Felipe Márcia


## 0.0 10.0 8.5 7.0 6.5

# Atribui nota ”desconhecida” para aluno.


notas[”Felipe”] <- NA
notas

## João Bianca Eduarda Felipe Márcia


## 0.0 10.0 8.5 NA 6.5

Para remover é similar, porém usamos o sinal de negativo.

# Remove elemento do vetor.


notas <- notas[-4]
notas

## João Bianca Eduarda Márcia


## 0.0 10.0 8.5 6.5

Finalmente, podemos incrementar o vetor já existente ou concatenar com um novo vetor.

append(notas, value = c(”Carlos” = 9.0))


append(notas, value = c(”Simone” = 7.2),
after = 0)
novas_notas <- c(notas,
c(”Pedro” = 8.0,
”Luana” = 8.3))
novas_notas

Além de objetos R para armazenar diferentes tipos de dados, vetores numéricos são também
entidades matemáticas para as quais diversas operações como soma, subtração, multiplicação por es-
calar, produto interno, entre outras são bem definidas.

O Código 3.7 ilustra as operações mais importantes com vetores. Para executar tais operações,
os vetores devem ser compatíveis. Novamente se você não está familiarizado com operações vetoriais

Ômega · Escola de Data Science omegadatascience.com.br


54 Capítulo 3. Estruturas de dados

não se assuste. A Ômega Data Science oferece um curso único de matemática para Ciência de Dados
que explica em detalhes todas essas operações.

Código 3.7. Operações com vetores.

# Definindo dois vetores compatíveis (mesmo tamanho)


a <- c(4,5,6)
b <- c(1,2,3)

# Soma
a + b

## [1] 5 7 9

# Subtração
a - b

## [1] 3 3 3

# Multiplicação por escalar


alpha = 10
alpha*a

## [1] 40 50 60

# Produto interno
a%*%b

## [,1]
## [1,] 32

# Multiplicacao elemento por elemento (Hadamard)


a*b

## [1] 4 10 18

# Multiplicação entre vetores


a%*%b

## [,1]
## [1,] 32

# Ângulo entre dois vetores compatíveis


a <- c(1,0)
b <- c(0,1)
cos_theta <- t(a)%*%b/(sqrt(t(a)%*%a)*sqrt(t(b)%*%b))
cos_theta

## [,1]
## [1,] 0

Note, no Código 3.7, a diferença entre o operador especial de multiplicação vetorial %*% e o
de multiplicação *.

Ômega · Escola de Data Science omegadatascience.com.br


3.2 55

Outra característica interessante do R é a chamada Lei da Reciclagem. Considere o Código


3.8.

Código 3.8. Lei da reciclagem.

a <- c(4,5,6,5,6,7)
b <- c(1,2,3)
a + b

## [1] 5 7 9 6 8 10

Note que os vetores a e b, definidos em 3.8, não são compatíveis para soma. Em termos
matemáticos a soma não faz sentido, no entanto o R retorna um vetor.

Dada a incompatibilidade dos vetores, o R reciclou os elementos do vetor b para realizar a


soma, ou seja, o R fez (4 + 1) = 5; (5 + 2) = 7; (6 + 3) = 9. Note que os elementos do vetor b
acabaram. Porém o vetor a ainda tem três elementos restantes. Assim, o R recicla os elementos de b
e faz (5 + 1) = 6; (6 + 2) = 8; (7 + 3) = 10. Essa é a chamada Lei da reciclagem. Tome cuidado,
pois nem sempre é esse o resultado desejado ao multiplicar dois vetores.

3.2 Matrizes
Em R uma matriz (matrix) é uma simples extensão dos vetores atômicos. Matrizes não são
um tipo diferente de objeto, são apenas vetores atômicos com dimensões, ou seja, número de linhas
e colunas. Da mesma forma que nos vetores, todos os elementos de uma matriz devem ser do mesmo
tipo. Para definir uma matriz em R precisamos minimamente definir os dados (data) que vão compor
a matriz e sua dimensão, número de linhas (nrow) e colunas (ncol).

matriz <- matrix(data = c(1, 0, 0, 1), nrow = 2, ncol = 2)


matriz

## [,1] [,2]
## [1,] 1 0
## [2,] 0 1

Para acessar a dimensão de uma matriz usamos a função dim(matriz). Matrizes em R são
preenchidas por colunas. Por exemplo,

matriz <- matrix(c(1,2,3,4,5,6,7,8), nrow = 4, ncol = 2)


matriz

## [,1] [,2]
## [1,] 1 5
## [2,] 2 6
## [3,] 3 7
## [4,] 4 8

Ômega · Escola de Data Science omegadatascience.com.br


56 Capítulo 3. Estruturas de dados

Caso seja de interesse, podemos pedir ao R para preencher a matriz por linhas usando o argu-
mento byrow = TRUE.

matriz <- matrix(c(1,2,3,4,5,6,7,8), nrow = 4, ncol = 2, byrow = TRUE)


matriz

## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
## [3,] 5 6
## [4,] 7 8

Os elementos de uma matriz são acessados pela sua posição. Uma matriz é indexada por dois
índices, linha e coluna.

matriz[1,2] # Linha 1 Coluna 2

## [1] 2

matriz[3,1] # Linha 3 Coluna 1

## [1] 5

matriz[1:2, 2] # Linhas 1 e 2 Coluna 2

## [1] 2 4

matriz[2:3, 1:2] # Linhas 2 e 3 e Colunas 1 e 2

## [,1] [,2]
## [1,] 3 4
## [2,] 5 6

A seleção condicional é feita da mesma forma que para vetores usando máscara lógica, por
exemplo,

matriz[matriz > 4] ## Elementos maiores do que 4

## [1] 5 7 6 8

Podemos combinar duas matrizes desde que tenham o número de linhas e colunas compatí-
veis.

matriz2 <- matrix(c(1,2,3,4), nrow = 4)


cbind(matriz, matriz2) ## Combina por coluna

## [,1] [,2] [,3]


## [1,] 1 2 1
## [2,] 3 4 2
## [3,] 5 6 3
## [4,] 7 8 4

Ômega · Escola de Data Science omegadatascience.com.br


3.2 57

matriz3 <- matrix(c(1,2), ncol = 2)


rbind(matriz, matriz3) # Combina por linha

## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
## [3,] 5 6
## [4,] 7 8
## [5,] 1 2

Todas as operações básicas de Álgebra Linear estão implementadas em R para objetos da


classe matrix. O Código 3.9 ilustra diversas operações matriciais. Note que as matrizes envolvidas
devem ser compatíveis. Novamente, se você não conhece essas operações matriciais não se preocupe.
O Curso de Matemática para Cientistas de Dados explica com detalhes cada uma destas operações
matriciais.

Código 3.9. Operações com matrizes.

# Declarando uma matriz


a <- c(1,2,3,4,5,6)
A <- matrix(a, nrow = 3, ncol = 2)
A

## [,1] [,2]
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6

# Matriz transposta
t(A)

## [,1] [,2] [,3]


## [1,] 1 2 3
## [2,] 4 5 6

# Multiplicação por escalar


A <- matrix(c(1,2,3,4,5,6), nrow = 3, ncol = 2)
alpha <- 10
alpha*A

## [,1] [,2]
## [1,] 10 40
## [2,] 20 50
## [3,] 30 60

Ômega · Escola de Data Science omegadatascience.com.br


58 Capítulo 3. Estruturas de dados

# Soma e subtração
A <- matrix(c(1,2,3,4,5,6), nrow = 3, ncol = 2)
B <- matrix(c(10,20,30,40,50,60), nrow = 3, ncol = 2)
C <- A + B
D <- A - B

# Multiplicação matricial
A <- matrix(c(2,8,6,-1,3,7), nrow = 3, ncol = 2)
B <- matrix(c(4,-5,9,2,1,4,-3,6), nrow = 2, ncol = 4)
C <- A%*%B

# Produto de Hadamard
A <- matrix(c(1,2,3,4), nrow = 2, ncol = 2)
B <- matrix(c(10,20,30,40), nrow = 2, ncol = 2)
C <- A*B

# Matriz inversa
A <- matrix(c(4, 2, 7, 6), 2, 2)
A_inv <- solve(A)
## Conferindo: deve resultar na matriz identidade
A%*%A_inv

## [,1] [,2]
## [1,] 1 0
## [2,] 0 1

# Determinante de uma matriz


A <- matrix(c(3,-2,-2,4),2,2)
determinant(A, logarithm = FALSE)

## $modulus
## [1] 8
## attr(,”logarithm”)
## [1] FALSE
##
## $sign
## [1] 1
##
## attr(,”class”)
## [1] ”det”

# Traço (soma da diagonal)


sum(diag(A))

## [1] 7

3.3 Listas
A estrutura list é similar ao atomic vector porém não há a necessidade de todos os elemen-
tos serem do mesmo tipo. Por exemplo, podemos ter uma lista armazenando elementos dos tipos
numeric, logical, matrix, data.frame e até mesmo outra list. Assim, a estrutura de lista é bastante
flexível e útil. Para criar uma lista usamos list() e para converter um objeto para a classe list usamos
as.list(). O Código 3.10 ilustra a criação de uma lista com objetos da classe numeric, character,

Ômega · Escola de Data Science omegadatascience.com.br


3.3 59

logical e complex.

Código 3.10. Exemplo de criação de uma lista.

minha_lista <- list(10, ”Dez”, TRUE, 1+10i)


minha_lista

## [[1]]
## [1] 10
##
## [[2]]
## [1] ”Dez”
##
## [[3]]
## [1] TRUE
##
## [[4]]
## [1] 1+10i

Para acessar os elementos de uma lista usamos o operador duplo colchetes.

minha_lista[[1]] # Primeiro elemento

## [1] 10

minha_lista[[4]] # Quarto elemento

## [1] 1+10i

Para acessar mais de um elemento da lista usamos o operador colchete.

minha_lista[c(1,4)] # Primeiro e quarto elemento

## [[1]]
## [1] 10
##
## [[2]]
## [1] 1+10i

Os elementos da lista podem ser nomeados.

minha_lista <- list(”Números” = c(10, 100),


”Caracter” = c(”Dez”, ”Cem”),
”Logico” = TRUE, ”Complexo” = 1+10i)
minha_lista

Ômega · Escola de Data Science omegadatascience.com.br


60 Capítulo 3. Estruturas de dados

## $Números
## [1] 10 100
##
## $Caracter
## [1] ”Dez” ”Cem”
##
## $Logico
## [1] TRUE
##
## $Complexo
## [1] 1+10i

E neste caso acessados por meio do operador $ seguido pelo nome.

minha_lista$Logico

## [1] TRUE

minha_lista$Números

## [1] 10 100

Podemos facilmente acessar os atributos de uma lista.

attributes(minha_lista)

## $names
## [1] ”Números” ”Caracter” ”Logico” ”Complexo”

Listas são muito úteis dentro de funções, conforme será discutido no Capítulo 5. As vezes os
elementos da lista são chamados de slots.

3.4 Dados tabulares


Por fim, temos a classe data.frame. Esta é a classe mais utilizada para representar conjuntos
de dados. Um data.frame é muito similar a uma tabela como as utilizadas em softwares de planilhas
eletrônicas como o Excel, LibreOffice, entre outros. Um data.frame é um tipo especial de lista
onde cada elemento da lista é do mesmo tipo e tamanho. Um data.frame tem diversos atributos
como rownames(), colnames(), names() e dim(). Em geral usamos a convenção de que cada linha
representa uma observação (registro) e cada coluna uma variável. O R traz uma série de conjuntos
de dados populares na literatura para estudar estatística no pacote datasets. Todos esses datasets
são objetos da classe data.frame. Por exemplo, o conjunto iris é muito famoso na literatura de
aprendizagem de máquina e pode ser acessado simplesmente digitando iris. Existem diversas funções
para inspecionar um data.frame. Em especial a função str() faz um resumo rápido da estrutura do
data.frame considerado.

str(iris)

Ômega · Escola de Data Science omegadatascience.com.br


3.4 61

## ’data.frame’: 150 obs. of 5 variables:


## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels ”setosa”,”versicolor”,..: 1 1 1 1 1 1 1 1 1 1 ...

Neste caso o objeto iris é um data.frame com 150 observações de 5 variáveis, sendo quatro
delas numéricas e uma do tipo fator. A classe factor é muito similar a classe character. No entanto
a classe factor é comumente usada para representar categorias ou níveis (levels). Por exemplo,

fator <- factor(c(”alta”,”baixa”,”baixa”,”media”,


”alta”,”media”,”baixa”,”media”,”media”))
fator

## [1] alta baixa baixa media alta media baixa media media
## Levels: alta baixa media

Uma funcionalidade dos fatores é que você pode definir a ordem dos níveis. Isso será útil
para ordenar os níveis em gráficos e tabelas. Por exemplo, suponha que desejamos que os níveis
sejam apresentados na seguinte ordem: baixa, media, alta.

fator <- factor(c(”alta”,”baixa”,”baixa”,”media”,


”alta”,”media”,”baixa”,”media”,”media”),
levels = c(”baixa”, ”media”, ”alta”),
ordered = TRUE)

Agora se fizermos uma tabela com esses dados a ordem será respeitada.

table(fator)

## fator
## baixa media alta
## 3 4 2

Até aqui nós usamos apenas o data.frame iris que já vem com o R. No entanto, podemos
criar um data.frame do zero. Por exemplo,

dados <- data.frame(Letras = letters[1:6],


Numeros = 1:6,
Logico = rep(c(TRUE, FALSE), each = 3))
dados

## Letras Numeros Logico


## 1 a 1 TRUE
## 2 b 2 TRUE
## 3 c 3 TRUE
## 4 d 4 FALSE
## 5 e 5 FALSE
## 6 f 6 FALSE

Para objetos da classe data.frame as opções de inspeção são amplas. Abaixo listamos as prin-
cipais funções.

Ômega · Escola de Data Science omegadatascience.com.br


62 Capítulo 3. Estruturas de dados

▶ head() - mostra as seis primeiras linhas.


▶ tail() - mostra as seis últimas linhas.
▶ dim() - número de linhas e de colunas.
▶ nrow() - número de linhas.
▶ ncol() - número de colunas.
▶ str() - estrutura do data.frame.
▶ names(), colnames() e rownames() nome das linhas e colunas.

Note que cada coluna de um data.frame é um atomic vector e portanto só pode ter ele-
mentos de mesmo tipo. Para acessar os elementos de um data.frame usamos uma sintaxe similar a
usada com matrizes.

iris[1,] # Primeira linha todas as colunas

## Sepal.Length Sepal.Width Petal.Length Petal.Width Species


## 1 5.1 3.5 1.4 0.2 setosa

iris[2,1:3] # Segunda linha colunas de 1 a 3

## Sepal.Length Sepal.Width Petal.Length


## 2 4.9 3 1.4

iris[c(1, 5),] # Linhas 1 e 5 todas as colunas

## Sepal.Length Sepal.Width Petal.Length Petal.Width Species


## 1 5.1 3.5 1.4 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa

Por fim, as colunas podem ser acessadas pelo nome, usando o operador $.

iris$Sepal.Length

Para lembrar o que foi tratado neste Capítulo:

▶ Os principais tipos de dados são: character, numeric, integer, logical, complex e raw.

▶ As principais estruturas de dados são: vector, matrix, list e data.frame.

▶ Lembre-se:

▶ Vetores: conjunto de elementos unidimensional, todos do mesmo tipo.

▶ Matrizes: conjunto de elementos bidimensional (linha e coluna), todos do mesmo tipo.

▶ Listas: caso especial de vetor em que cada elemento pode ser uma estrutura diferente.

▶ Data frames: tabela. Cada coluna é um vetor, portanto os elementos dentro da coluna são
de mesmo tipo mas os tipos entre colunas podem ser diferentes.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 4

Estruturas de controle e repetição

No contexto de linguagens de programação as estruturas de controle e de repetição estão


sempre presentes. As estruturas de controle permitem executar instruções conforme o resultado de
condicionais. Os tipos mais comuns em R são if-else, switch e cases. As estruturas de repetição,
também chamadas de loops ou estruturas de iteração permitem executar instruções por um certo
número de vezes até que uma condição seja satisfeita. Os tipos mais comuns em R são for, foreach,
while, repeat e do-until. Neste Capítulo nós vamos discutir a sintaxe das principais estruturas e
apresentar exemplos de como utilizá-las.

4.1 Estruturas de controle


Uma estrutura condicional é utilizada quando a ação a ser tomada depende de uma condição
ser ou não satisfeita. Veremos nesta seção as estruturas if-else e switch.

4.1.1 if-else
A estrutura if-else é a estrutura de controle mais simples e permite desviar a execução do
código conforme uma condição lógica. A Figura 4.1 ilustra o fluxograma da estrutura if-else.

A ideia é muito simples: uma instrução chega para ser executada e avalia-se uma condição,
representada pelo losango amarelo. Caso a condição seja verdadeira, a instrução representada pelo
retângulo verde é executada. Caso contrário, ou seja, condição é falsa, a instrução representada pelo
retângulo laranja é executada.

Vamos fazer um exemplo para ilustrar a ideia: suponha que ao final de um semestre um
professor avalia a frequência e nota de um aluno para decidir se ele será aprovado, reprovado por nota
ou reprovado por faltas. Por simplicidade, considere os seguintes critérios (condições) apresentados
abaixo.

▶ Aprovado: nota maior ou igual a 70 e faltas menor que 15.

63
64 Capítulo 4. Estruturas de controle e repetição

Figura 4.1: Fluxograma de uma estrutura de controle tipo if-else.

▶ Reprovado por nota: Nota menor que 70.


▶ Reprovado por falta: Caso contrário.

A implementação R desta estrutura de condições é apresentada na Figura 4.2.

Figura 4.2: Exemplo de código com a estrutura de controle tipo if-else.

Note que a condição deve ser um lógico, ou seja, apenas os valores TRUE ou FALSE são possíveis
de serem avaliados. Note ainda que se um vetor lógico for fornecido a função retornará um erro.

Vamos retornar ao exemplo de calcular o IMC de uma pessoa. Porém, além de obter o IMC
vamos também avaliá-lo de acordo com os seguintes critérios:

▶ Magreza: menor que 18.5.


▶ Adequado: maior ou igual a 18.5 e menor que 25.
▶ Pré-obeso: maior ou igual a 25 e menor que 30.
▶ Obeso: maior ou igual a 30.

A sintaxe R para implementar tal estrutura de controle é ilustrada no Código 4.1.

Considere uma pessoa com 1, 60m e 80kg e que a tabela assume que o IMC foi calculado com

Ômega · Escola de Data Science omegadatascience.com.br


4.1 65

apenas uma casa decimal de precisão. Assim, precisamos forçar o R a usar apenas uma casa decimal.
Isso pode ser feito usando a função round().

Código 4.1. Exemplo de implementação da estrutura de controle if-else.

peso <- 80
altura <- 1.60
imc <- round(peso/(altura^2), 1)

if(imc < 18.5) {


classificacao <- ”Magreza”
} else if (imc >= 18.5 & imc < 25) {
classificacao <- ”Adequado”
} else if (imc >= 25 & imc < 30) {
classificacao <- ”Pré-obeso”
} else {
classificacao <- ”Obeso”
}
classificacao

## [1] ”Obeso”

imc

## [1] 31.2

4.1.2 switch
A estrutura switch() é uma espécie de empilhamento de estruturas if-else. O objetivo é
oferecer uma estrutura mais clara e computacionalmente mais eficiente. O caso mais comum de uso
da estrutura switch() é para testar um valor contra um conjunto de strings. É também comum
incluir uma condição final de escape, conforme ilustrado na Figura 4.3.

A ideia é que existe um conjunto de condições representadas pelos losangos na Figura 4.3.
Quando uma delas é verdadeira, a instrução representada pelos quadrados é executada. No caso
da Figura 4.3, a condição de escape é o quadrado em azul, ou seja, se nenhuma das condições for
verdadeira a condição de escape será executada. A sintaxe é ilustrada na Figura 4.4.

Podemos adaptar a nossa rotina para avaliar o IMC de uma pessoa usando a estrutura switch()
conforme ilustrado abaixo. Porém, precisamos de uma função extra para descobrir em qual intervalo
de IMC a pessoa está.

escala_imc <- c(0, 18.5, 25, 30, Inf)


switch(as.character(findInterval(imc, escala_imc)) ,
”0” = {classificacao = ”Magreza”},
”1” = {classificacao = ”Adequado”},
”2” = {classificacao = ”Pré-obeso”},
{classificacao = ”Obeso”}
)
classificacao

Ômega · Escola de Data Science omegadatascience.com.br


66 Capítulo 4. Estruturas de controle e repetição

Figura 4.3: Fluxograma de uma estrutura de controle tipo SWITCH.

Figura 4.4: Exemplo de código com a estrutura de controle tipo SWITCH.

## [1] ”Obeso”

Para exercitar o uso das estruturas de controle apresentadas vamos fazer mais um exemplo.
Considere a tabela de alíquotas do imposto de renda de pessoa física apresentada na Figura 4.5.

A faixa de salário está na coluna 1 da tabela, ao lado da alíquota que deve ser paga. Vamos
começar usando a estrutura if-else considerando um usuário com renda = 2000.

Ômega · Escola de Data Science omegadatascience.com.br


4.1 67

Figura 4.5: Tabela de imposto de renda. Fonte: <a href=”https://www.leoa.com.br/blog/tabela-do-


imposto-de-renda-2020»https://www.leoa.com.br/blog/tabela-do-imposto-de-renda-2020</a>

renda = 2000
if (renda < 1903.98) {
aliquota <- 0
} else if (renda > 1903.99 & renda < 2826.65) {
aliquota <- 7.5
} else if (renda > 2826.66 & renda < 3751.05) {
aliquota <- 15
} else if (renda > 3751.06 & renda < 4664.68) {
aliquota <- 22.5
} else {
aliquota <- 27.5
}
aliquota

## [1] 7.5

Novamente, uma alternativa é usar a estrutura swicth() combinada com a função


findInterval().

Ômega · Escola de Data Science omegadatascience.com.br


68 Capítulo 4. Estruturas de controle e repetição

escala_salario <- c(1903.98, 2826.65, 3751.05, 4664.68)


renda = 2000
switch(as.character(findInterval(renda, escala_salario)) ,
”0” = {aliquota = 0},
”1” = {aliquota = 7.5},
”2” = {aliquota = 15},
”3” = {aliquota = 22.5},
{aliquota = 27.5}
)
aliquota

## [1] 7.5

Para usar a função findInterval() primeiro foi necessário criar um vetor com as classes de
renda. Considerando uma determinada renda (2000, em nosso exemplo), a função findInterval()
retorna um inteiro dizendo a qual classe a renda pertence. Por exemplo, renda = 2000 está na segunda
faixa. Como a função começa contando do 0, o valor retornado é 1. A entrada para a função switch()
precisa ser uma string, ou seja, um objeto da classe caracter. Por isso, foi necessário usar a função
as.character() para converter o inteiro retornado pela função findInterval() em uma string. Por
fim, a função switch() encontra qual a faixa de aliquota. Caso não seja nenhum valor inteiro entre 0
e 3 a função retorna aliquota = 27.5, a nossa condição de escape.

As estruturas if-else e switch não são vetorizadas. Isso significa que para um vetor elas
devem ser avaliadas em cada um dos seus elementos de forma separada. Existem algumas opções
nativas do R que são vetorizadas. Isso significa que quando aplicadas a um vetor a função irá avaliar
cada um de seus elementos.

Por exemplo, suponha que temos um vetor de notas

notas <- c(”João” = 70, ”Ana” = 89,


”Márcia” = 81, ”Tiago” = 65,
”Rodrigo” = 35)

Nosso interesse é criar uma regra para avaliar se o aluno está aprovado, em exame ou repro-
vado. A regra é a seguinte, se a nota for maior ou igual a 70, o aluno está aprovado. Se a nota for
maior ou igual a 40 e menor que 70, o aluno está em exame. E se a nota for menor que 40, o aluno
está reprovado. Agora, nós queremos fazer esse teste para todos os alunos. A função ifelse permite
realizar tal tarefa facilmente.

ifelse(notas >= 70, ”Aprovado”,


ifelse(notas >= 40, ”Exame”,
”Reprovado”))

## João Ana Márcia Tiago Rodrigo


## ”Aprovado” ”Aprovado” ”Aprovado” ”Exame” ”Reprovado”

Note que executamos o teste lógico para todos os elementos do vetor notas, por isso dizemos
que esta função está vetorizada ou é vetorizada.

Ômega · Escola de Data Science omegadatascience.com.br


4.2 69

De maneira similar, o pacote dplyr oferece uma versão vetorizada da função switch(). Por
exemplo,

dplyr::case_when(notas >= 70 ~ ”Aprovado”,


notas >= 40 ~ ”Exame”,
TRUE ~ ”Reprovado”)

## [1] ”Aprovado” ”Aprovado” ”Aprovado” ”Exame” ”Reprovado”

Note que para usar a função case_when() é necessário ter instalado o pacote dplyr. Caso
você não tenha execute install.packages(”dplyr”).

4.2 Estruturas de repetição


As estruturas de repetição, também chamadas de loops são utilizadas quando queremos exe-
cutar um conjunto de tarefas várias vezes. O número final de execuções pode ser definido pelo pro-
gramador ou definido de acordo com alguma condição de parada. Veremos nesta seção as estruturas
for, while e repeat.

4.2.1 for
Em geral, quando o número de execuções é conhecido usamos a estrutura for. O for vai
iterar sobre uma sequência de elementos executando alguma tarefa em cada elemento. A ideia é
ilustrada na Figura 4.6.

A instrução pode ser lida da seguinte forma: para i indo de 1 até n faça tal tarefa. O i é o
índice de iteração e vai percorrer cada entrada do vetor onde a operação deve ser aplicada.

Para ilustrar a ideia considere que é de interesse obter o quadrado de cada um dos valores
inteiros entre 1 e 5. O Código 4.2 realiza esta tarefa.

Código 4.2. Exemplo de estrutura for.

quadrado <- c()


entrada <- 1:5
for(i in 1:5) {
quadrado[i] <- entrada[i]^2
print(quadrado[i])
}

## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25

quadrado

Ômega · Escola de Data Science omegadatascience.com.br


70 Capítulo 4. Estruturas de controle e repetição

Figura 4.6: Fluxograma de uma estrutura de repetição tipo FOR. Fonte: os autores.

## [1] 1 4 9 16 25

Alguns aspectos importantes do Código 4.2 são:

▶ Primeiro foi declarado um vetor chamado de quadrado para armazenar os resultados.

▶ Usamos o operador colchetes [i] para iterar/percorrer o vetor de entrada.

▶ Usamos a variável i como indexador, porém poderíamos usar qualquer outra letra.

▶ Para ilustração usamos a função print() para imprimir cada iteração do nosso for.

Vamos fazer um segundo exemplo que consiste em somar dois vetores. A soma de dois
vetores é possível quando os vetores são do mesmo tamanho e é definida por a + b = (ai + bi ) =
(a1 + b1 , . . . , an +n ).

Em R podemos implementar esta operação usando o loop for, conforme o Código 4.3.

Código 4.3. Soma de vetores usando for.

Ômega · Escola de Data Science omegadatascience.com.br


4.2 71

a <- c(1, 2, 3)
b <- c(5, 6, 7)
resultado <- c()

for(i in 1:length(a)) {
resultado[i] <- a[i] + b[i]
}
resultado

## [1] 6 8 10

Por fim, é importante saber como parar um loop for de acordo com alguma condição con-
trolada durante a avaliação das instruções, ou mesmo não parar dado alguma condição não esperada
nas iterações. Para estas duas tarefas temos as funções break e next. Pra ilustrar o seu uso, suponha
que desejamos somar os elementos de um vetor, porém quando a soma for superior a 10 devemos
parar o loop for. Além disso, caso o vetor tenha um elemento como NA o loop não deve parar, apenas
passar para o próximo elemento.

y <- c(1, 2, 1, 4, 0, NA, 3, 2, 4)


s <- 0
for(i in y) {
if(s > 10) break
if(is.na(i)) next
s <- s + i
print(s)
}

## [1] 1
## [1] 3
## [1] 4
## [1] 8
## [1] 8
## [1] 11

## [1] 11

A estrutura da sintaxe de um loop for é ilustrada na Figura 4.7.

4.2.2 while
Outra estrutura de repetição é o while. A principal diferença em comparação com o for é
que o número de repetições é desconhecido. A ideia é que a instrução será executada até que uma
condição lógica seja atendida. A Figura 4.8 ilustra a estrutura while.

No while a condição de parada deve ser especificada. Para ilustrar esta estrutura vamos criar
uma rotina que vai somar números aleatórios de uma distribuição Uniforme(a = 0, b = 1) até que a
soma destes números seja maior do que quatro. A condição final de parada será simular 12 números.

Ômega · Escola de Data Science omegadatascience.com.br


72 Capítulo 4. Estruturas de controle e repetição

Figura 4.7: Exemplo de código com a estrutura de repetição tipo FOR.

n_numbers <- 12
total <- 0
i <- 1L
while(i < n_numbers) {
u <- total + runif(1)
if(sum(u) > 4) break
total <- u
i <- i + 1L
}

Figura 4.9 ilustra em detalhes a estrutura while.

4.2.3 repeat
A última estrutura de repetição que vamos discutir neste capítulo é o repeat. É uma estrutura
muito parecida com a estrutura while e usada quando precisamos executar um conjunto de instruções
por um número desconhecido de vezes até que uma condição seja atendida. A principal diferença
é que a condição pode ser testada em qualquer posição dentro das instruções a serem executadas.
Novamente, é muito importante que a condição de parada seja declarada para evitar que o loop seja
interminável. A Figura 4.10 ilustra a ideia da estrutura repeat.

Como ilustração vamos usar o mesmo exemplo da estrutura while, conforme o Código 4.4.

Código 4.4. Exemplo da estrutura repeat.

total <- 0
i <- 1L
repeat {
u <- total + runif(1)
if(sum(u) > 4) break
total <- u
i <- i + 1L
}

Os detalhes da sintaxe da estrutura repeat são apresentados na Figura 4.11.

Ômega · Escola de Data Science omegadatascience.com.br


4.2 73

Figura 4.8: Fluxograma de uma estrutura de repetição tipo WHILE.

Figura 4.9: Exemplo de código com a estrutura de repetição tipo WHILE.

Para terminar este Capítulo vamos ver como usar tais estruturas para resolver um problema
um pouco mais complicado.

Considere o seguinte jogo: lançar três dados até que os valores das faces sejam uma sequência,
por exemplo, 3, 4 e 5 ou 1, 2 e 3. Nosso objetivo é contar quantas tentativas são necessárias até atingir
o resultado.

Para estruturar nossa solução computacional é interessante usar os princípios do algorithimic


thinking (pensamento algorítmico). Basicamente, a ideia é quebrar o problema em vários pequenos
problemas que podem ser resolvidos de forma simples. Para o nosso jogo precisamos:

1. Encontrar uma forma de simular o lançamento de três dados.


2. Ordenar os valores simulados.
3. Decidir se são ou não uma sequência.

Ômega · Escola de Data Science omegadatascience.com.br


74 Capítulo 4. Estruturas de controle e repetição

Figura 4.10: Fluxograma de uma estrutura de repetição tipo REPEAT. Fonte: os autores.

Figura 4.11: Exemplo de código com a estrutura de repetição tipo REPEAT.

Para simular o lançamento de três dados podemos usar a função sample(). Note que o lan-
çamento de um dado nada mais é do que sortear um número aleatóriamente entre 1 e 6 todos com
igual probablidade, ou seja, 1/6. O segundo passo é ordenar os valores simulados. A função sort()
serve a este propósito. Por fim, precisamos decidir se os valores são ou não uma sequência. Uma
ideia simples é calcular a diferença entre os valores ordenados. Se todas as diferenças forem iguais a 1
temos uma sequência, caso contrário não temos. Em R a função diff() calcula a diferença entre os
elementos de um vetor. Vamos primeiro fazer um protótipo.

## Lançamento dos dados


l1 <- sample(1:6, 3, replace = TRUE)
l1

## [1] 1 5 3

Ômega · Escola de Data Science omegadatascience.com.br


4.2 75

# Ordenando
l1_ordenado <- sort(l1)

# Decidindo se é sequencia
diff(l1_ordenado)

## [1] 2 2

Note que no passo 3 precisamos olhar se todos os elementos do vetor de diferenças são iguais
a 1. Existem diversas formas de fazer isso. Neste exemplo, optamos por usar a função ifelse que já
é vetorizada, ou seja, vai avaliar todos os elementos do vetor.

ifelse(diff(l1_ordenado) == 1, TRUE, FALSE)

## [1] FALSE FALSE

Porém, ela retorna dois valores, o que ainda não é suficiente para decidir se é uma sequencia
ou não. Para ser sequência ambos os testes lógicos devem ser verdadeiros. Assim, se somarmos o
resultado do ifelse, o R vai converter a saída lógica para numeric. Por fim, se a soma for igual a dois
significa que temos uma sequência, caso contrário não é uma sequência. Com esses detalhes, estamos
aptos a implementar a nossa rotina.

n_max <- 100


tentativas <- 1

while(tentativas < n_max) {


l1 <- sample(1:6, 3, replace = TRUE) # joga os dados
l1_ordenado <- sort(l1) # ordenada
print(l1_ordenado)
seque <- sum(ifelse(diff(l1_ordenado) == 1, TRUE, FALSE))
if(seque == 2) break
tentativas <- tentativas + 1
}

## [1] 3 3 6
## [1] 2 2 6
## [1] 3 4 5

tentativas

## [1] 3

Neste caso foram necessárias três tentativas até obter uma sequência. Perceba que quando
você realizar essa mesma instrução no seu computador provavelmente você vai obter um número
diferente de tentativas. Isso se deve ao fato do algoritmo ter um componente aleatório: o lançamento
dos dados. Em termos computacionais nós não estamos realmente jogando os dados. O R tem um
mecanismo para imitar o que seria o lançamento do dado, porém não é realmente aleatório, é o que
chamamos de pseudo aleatório. Assim, se você quiser obter exatamente o mesmo resultado que foi
apresentado antes de executar a sua instrução inclua set.seed(123). Esse comando fixa a semente
aleatória e permite você replicar exatamente o mesmo experimento realizado no livro.

Ômega · Escola de Data Science omegadatascience.com.br


76 Capítulo 4. Estruturas de controle e repetição

Também fica claro que cada vez que você fizer o experimento você vai obter um número
diferente de tentativas até obter uma sequência. Por exemplo, se realizarmos o experimento nova-
mente

n_max <- 100


tentativas <- 1

while(tentativas < n_max) {


l1 <- sample(1:6, 3, replace = TRUE) # joga os dados
l1_ordenado <- sort(l1) # ordenada
print(l1_ordenado)
seque <- sum(ifelse(diff(l1_ordenado) == 1, TRUE, FALSE))
if(seque == 2) break
tentativas <- tentativas + 1
}

## [1] 1 2 4
## [1] 1 2 6
## [1] 3 4 4
## [1] 1 4 6
## [1] 1 4 6
## [1] 1 2 4
## [1] 5 5 5
## [1] 3 4 5

tentativas

## [1] 8

observamos um número diferente de tentativas, neste caso oito foram necessárias para obter
uma sequência. Uma pergunta natural agora é: em média quantos lançamentos são necessários para
obter uma sequência?

A resposta pode ser obtida repetindo o conjunto de instruções um grande número de vezes,
digamos, 1000. E guardar o número de tentativas necessárias para posteriormente calcular a média.
Porém, vamos postergar tal tarefa para o próximo Capítulo onde vamos ver como encapsular um
conjunto de instruções em uma função.

Com isso encerramos o capítulo sobre estruturas de controle e repetição, vimos:

▶ if-else: estrutura usada para definir o que fazer caso uma condição seja aceita.

▶ switch: pode ser entendido como um empilhamento de condicionais if-else.

▶ for: realiza uma tarefa um número definido de vezes.

▶ while e repeat: realizam uma tarefa até que uma condição seja aceita.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 5

Funções

Em R, quase tudo o que acontece é resultado da chamada de funções. Em algum momento


é natural, e quase que inevitável, que você precise escrever funções por conta própria. O R permite
criar funções de forma bastante intuitiva e rápida. Criar funções é muito importante para encapsular
tarefas específicas que são compostas por diversas instruções. Uma forma de você decidir se vale a
pena ou não encapsular suas instruções em uma função é avaliar se você está copiando e colando
diversas vezes o mesmo bloco de código. Se sim, é um bom cenário onde a escrita de uma função
pode ser bastante útil. A Figura 5.1 ilustra a ideia de funções.

Figura 5.1: Ilustração da ideia de função.

Basicamente, uma função recebe um conjunto de entradas, faz algum tipo de processamento

77
78 Capítulo 5. Funções

e retorna uma saída. Funções permitem organizar o código separando-o em partes específicas. Essa
prática facilita encontrar e corrigir erros e evita incluir novos erros ao tentar corrigir outros. A ideia
é que, como as tarefas estão divididas em funções específicas, quando um erro surgir você saberá em
qual função ele ocorreu e poderá proceder com a correção. Além disso, você pode aproveitar funções
desenvolvidas em um projeto para outros projetos similares.

Vamos começar com um exemplo: relembre do Capítulo 4 onde discutimos estruturas de


controle e repetição e criamos uma rotina para avaliar o IMC de uma pessoa e classificá-lo em uma de
várias categorias. Podemos facilmente criar uma função para receber o peso e altura de uma pessoa e
retornar o IMC e a classificação do IMC. Vejamos o Código 5.1.

Código 5.1. Função para calcular o IMC e classificá-lo.

calcula_imc <- function(peso, altura) {


imc <- peso/(altura^2)
limits <- c(0, 18.5, 25, 30, Inf)
labels <- c(”Magreza”, ”Adequado”, ”Pré-obeso”, ”Obesidade”)
classif <- labels[findInterval(imc, limits)]
return(list(IMC = imc, Classificao = classif))
}
calcula_imc(peso = 80, altura = 1.80)

## $IMC
## [1] 24.7
##
## $Classificao
## [1] ”Adequado”

Neste exemplo usamos uma abordagem diferente. Apenas encontramos a classe em que o
IMC se encaixa e pareamos com as classificações. Assim, não foi necessário usar as estruturas de
controle como o if-else ou switch. Essa é uma característica interessante do R. Existem diversas
formas de fazer a mesma tarefa.

5.1 Funções e seus componentes


Ao decidir por implementar uma função é importante estar seguro de que conhece bem o
procedimento a ser implementado. Além disso, a escolha de um nome significativo é primordial para
ajudar o usuário a identificar a funcionalidade. Em geral, recomendamos usar verbos para indicar
claramente qual é a ação que a função executa. Outro aspecto é cuidar com o nome dos argumentos,
nomes intuitivos são altamente encorajados.

A Figura 5.2 ilustra cada um dos componentes da função implementada no Código 5.1.

Os componentes básicos de uma função em R são:

▶ Nome da função: usado para chamá-la. Em geral usamos as mesmas premissas usadas para
nomear objetos.

Ômega · Escola de Data Science omegadatascience.com.br


5.1 79

Figura 5.2: Anatomia de uma função no R. Fonte: os autores.

▶ Lista de parâmetros: também chamado de lista de argumentos formais que passa argumentos
atuais ou valores como variáveis de entrada.

▶ Corpo da função: contém a série de instruções que serão realizadas.

▶ Retorno da função: retorna o que a função calculou com as instruções implementadas e as


entradas.

Os argumentos de uma função podem ser qualquer estrutura de dados que vimos no Capítulo
4. Exemplos comuns são vetores, matrizes, listas e data.frames. Os argumentos podem conter valores
default, ou seja, se nada for especificado para um argumento o valor default será usado. Por exemplo,
vamos especificar na nossa função para calcular o IMC que o valor default para o peso é de 80kg. A
nova função fica dada por

calcula_imc <- function(altura, peso = 80) {


imc <- peso/(altura^2)
limits <- c(0, 18.5, 25, 30, Inf)
labels <- c(”Magreza”, ”Adequado”, ”Pré-obeso”, ”Obesidade”)
classif <- labels[findInterval(imc, limits)]
return(list(IMC = imc, Classificao = classif))
}
calcula_imc(altura = 1.80)

## $IMC
## [1] 24.7
##
## $Classificao
## [1] ”Adequado”

Ômega · Escola de Data Science omegadatascience.com.br


80 Capítulo 5. Funções

Note que agora na chamada da função calcula_imc() não foi necessário informar o peso da
pessoa. Por default este argumento tem o valor de 80kg. No caso de não querer usar o valor default
basta passar o valor desejado para o argumento da função, por exemplo,

calcula_imc(altura = 1.80, peso = 90)

## $IMC
## [1] 27.8
##
## $Classificao
## [1] ”Pré-obeso”

Recomendamos que os argumentos para os quais você especifica valores default sejam decla-
rados após os argumentos sem valores default. No nosso exemplo, o primeiro argumento é a altura
para a qual não especificamos um valor default.

Outra curiosidade sobre funções em R é que você pode passar os valores para os argumentos
simplesmente pela ordem em que são definidos. Por exemplo,

calcula_imc(1.80, 90)

## $IMC
## [1] 27.8
##
## $Classificao
## [1] ”Pré-obeso”

Note que não foi necessário digitar o nome dos argumentos. Apesar de ser possível passar
os argumentos desta forma, recomendamos que sempre passe os argumentos nomeados. Isso ajuda
muito a encontrar erros, dar manutenção no código e a trabalhar em equipe.

Outro cuidado é sempre deixar explícito o que a sua função está retornando usando a função
return. Apesar de não ser obrigatório consideramos uma boa prática. Se você não usar a função
return() a sua função irá retornar o que for executado por último no corpo da função.

5.2 Tratando exceções


Ao implementar uma função devemos pensar nos possíveis usuários e como eles vão interagir
com a nossa função. Neste sentido é importante prever possíveis maus usos da função. Por exemplo,
o que acontecerá se um usuário passar peso ou altura negativos para a nossa função?

calcula_imc(altura = -1, peso = -10)

## $IMC
## [1] -10
##
## $Classificao
## character(0)

Ômega · Escola de Data Science omegadatascience.com.br


5.3 81

Neste caso o IMC foi calculado como −10, um valor que obviamente não faz sentido prático.
Além disso, a nossa estrutura de classificação não encontrou uma classificação coerente e retornou va-
zio. Se o resultado de nossa função fosse usado como entrada de algum outro cálculo, provavelmente
teríamos um erro. Assim, é importante tratar as exceções, ou seja, avisar ao nosso usuário quando
ele informar valores para os argumentos que não fazem sentido. Temos diversas opções para fazer o
tratamento de exceções as mais populares são:

▶ cat() e print(): usa-se para imprimir conteúdo no console.

▶ message(): usa-se para imprimir mensagens neutras para o usuário.

▶ warning(): usa-se para imprimir mensagens de aviso. Ela causa a saída [Warning].

▶ stop(): usa-se para imprimir mensagens de erro. Ela causa a saída [Error] e interrompe a
execução do código.

No caso do cálculo do IMC tanto o peso quanto a altura devem ser valores estritamente
positivos. Assim, vamos parar a execução do código caso a altura ou o peso sejam menores do que
zero.

calcula_imc <- function(altura, peso = 80) {


if(altura < 0) stop(”Altura deve ser maior do que zero.”)
if(peso < 0) stop(”Peso deve ser maior do que zero.”)
imc <- peso/(altura^2)
limits <- c(0, 18.5, 25, 30, Inf)
labels <- c(”Magreza”, ”Adequado”, ”Pré-obeso”, ”Obesidade”)
classif <- labels[findInterval(imc, limits)]
return(list(IMC = imc, Classificao = classif))
}
calcula_imc(altura = -1)

## Error in calcula_imc(altura = -1): Altura deve ser maior do que zero.

calcula_imc(altura = 1.90, peso = -90)

## Error in calcula_imc(altura = 1.9, peso = -90): Peso deve ser maior do que zero.

Quando se implementa funções para usos gerais que provavelmente serão usadas por diferen-
tes públicos, é importante fazer os tratamentos de exceção e fazer a função se comunicar de forma
clara com o usuário. Tratar exceções é prever desvios de uso e/ou de processamento causados, por
exemplo, por:

▶ Variáveis com tipos incorretos.


▶ Objetos de classe incorreta.
▶ Indeterminação nos resultados.
▶ Falha de convergência.
▶ Conexão/rede não disponível.
▶ Arquivos/objetos não encontrados.

Ômega · Escola de Data Science omegadatascience.com.br


82 Capítulo 5. Funções

5.3 Aspectos avançados


Em algumas situações pode ser que você precise escrever uma função para a qual você não
sabe exatamente quais argumentos serão necessários. Isso acontece com frequência quando você tem
a chamada de diversas funções dentro de uma função genérica, porém cada função tem uma lista
diferente e opcional de argumentos. O R tem um mecanismo muito interessante para lidar com esse
tipo de situação: os três pontos (. . .). O uso dos três pontos é a forma de expressar que não queremos
ou não sabemos quais argumentos passar para a nossa função.

Suponha que na função para calcular o IMC não desejamos especificar quais serão seus argu-
mentos. Podemos escrever a função da seguinte forma:

calcula_imc <- function(...) {


if(altura < 0) stop(”Altura deve ser maior do que zero.”)
if(peso < 0) stop(”Peso deve ser maior do que zero.”)
imc <- peso/(altura^2)
limits <- c(0, 18.5, 25, 30, Inf)
labels <- c(”Magreza”, ”Adequado”, ”Pré-obeso”, ”Obesidade”)
classif <- labels[findInterval(imc, limits)]
return(list(IMC = imc, Classificao = classif))
}
calcula_imc(peso = 70, altura = 1.70)

## $IMC
## [1] 31.2
##
## $Classificao
## [1] ”Obesidade”

Note que não especificamos os argumentos da função, apenas usamos os três pontos. Porém,
na chamada da função explicitamente passamos o peso e a altura. Obviamente, se você passar qualquer
nome para os argumentos, o R não saberá o que fazer e retornará um erro. O uso deste tipo de recurso é
enconrajado apenas para usuários avançados e quando realmente necessário, contudo é algo que você
verá ao usar diversas funções do R.

Um outro aspecto importante sobre argumentos chama-se de lazy evaluation, ou avaliação


preguiçosa. Basicamente, isso significa que o R só vai usar um argumento quando necessário. Por
exemplo, suponha que em nossa função para calcular o IMC deixamos, por engano, um argumento
extra chamado de altura2.

calcula_imc <- function(altura, peso = 80, altura2) {


if(altura < 0) stop(”Altura deve ser maior do que zero.”)
if(peso < 0) stop(”Peso deve ser maior do que zero.”)
imc <- peso/(altura^2)
limits <- c(0, 18.5, 25, 30, Inf)
labels <- c(”Magreza”, ”Adequado”, ”Pré-obeso”, ”Obesidade”)
classif <- labels[findInterval(imc, limits)]
return(list(IMC = imc, Classificao = classif))
}
calcula_imc(altura = 1.90, peso = 90)

Ômega · Escola de Data Science omegadatascience.com.br


5.4 83

## $IMC
## [1] 24.9
##
## $Classificao
## [1] ”Adequado”

Note que mesmo não passando nenhum valor para o argumento altura2 o R não reportou
nenhum erro. Isso se deve simplesmente ao fato de que o R não avaliou o argumento altura2. Além
disso, mesmo que um valor seja passado para altura2 nenhum erro será reportado, simplesmente
porque esse argumento não é usado em nenhum lugar dentro da função.

calcula_imc(altura = 1.90, peso = 90, altura2 = -10)

## $IMC
## [1] 24.9
##
## $Classificao
## [1] ”Adequado”

Assim, quando a sua função tiver diversas opções de avaliação, é importante verificar que
todas funcionam conforme esperado e retornar mensagens de erros informativas quando necessário.

5.4 De instruções para funções


Para terminar esse Capítulo vamos retomar o exemplo do jogo de dados discutido no Caítulo
4. O jogo consiste em lançar três dados até que os valores das faces sejam uma sequência, por exemplo,
3, 4 e 5 ou 1, 2 e 3. Nosso objetivo é contar quantas tentativas são necessárias até atingir o resultado.

Usando os princípios do pensamento algorítmico nós chegamos aos seguintes passos:

1. Encontrar uma forma de simular o lançamento de três dados.


2. Ordenar os valores simulados.
3. Decidir se são ou não uma sequência.

Isso resultou no seguinte conjunto de instruções

n_max <- 100


tentativas <- 1

while(tentativas < n_max) {


l1 <- sample(1:6, 3, replace = TRUE) # joga os dados
l1_ordenado <- sort(l1) # ordenada
print(l1_ordenado)
seque <- sum(ifelse(diff(l1_ordenado) == 1, TRUE, FALSE))
if(seque == 2) break
tentativas <- tentativas + 1
}
tentativas

Ômega · Escola de Data Science omegadatascience.com.br


84 Capítulo 5. Funções

Agora vamos pegar esse conjunto de instruções e transformar em uma função. Novamente,
usando o pensamento algorítmico divimos a tarefa nos seguintes passos:

▶ Escolher o nome para a função.


▶ Escolher quais argumentos e seus nomes.
▶ Decidir o que a função irá retornar e como (qual tipo de objeto).

Vamos nomear a função de acordo com o que ela faz: joga_dados(). Os argumentos são os
aspectos que vamos controlar do jogo. Neste caso, vamos controlar o número de dados que vamos
jogar, que será o argumento n_dados. Precisamos ter uma condição de escape para o loop while que
é o número máximo de tentativas, vamos chamar de n_max. Por default vamos fixar que vamos tentar
no máximo 1000 vezes. Por fim, a função irá retornar um número (numeric) que é o número de
tentativas necessárias para obter uma sequência.

joga_dados <- function(n_dados, n_max = 1000) {


tentativas <- 1
while(tentativas < n_max) {
l1 <- sample(1:6, n_dados, replace = TRUE) # joga os dados
l1_ordenado <- sort(l1) # ordenada
seque <- sum(ifelse(diff(l1_ordenado) == 1, TRUE, FALSE))
if(seque == 2) break
tentativas <- tentativas + 1
}
return(tentativas)
}
joga_dados(n_dados = 3)

## [1] 8

Finalmente, podemos usar a nossa função para responder a pergunta: em média quantos
lançamentos são necessários para obter uma sequência?

Vamos simplesmente repetir o experimento um número grande de vezes (10000), guardar os


resultados e depois calcular a média. Usando a estrutura de repetição for temos,

tentativas <- numeric(10000)


for(i in 1:10000) {
tentativas[i] <- joga_dados(n_dados = 3)
}
mean(tentativas)

## [1] 8.97

Assim, encerramos este capítulo onde discutimos:

▶ Porquê e quando criar uma função.


▶ Anatomia básica de um função: nome, argumentos, corpo e retorno.
▶ Tratamento de exceções.
▶ Aspectos avançados como o uso do . . . e lazy evaluation.
▶ Como transformar um conjunto de instruções em uma função.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 6

Lidando com dados com o R base

Ao trabalhar com ciência de dados lidamos com dados de todos os tipos e formatos diaria-
mente. O R nativamente apresenta um conjunto completo de ferramentas para importar, manipular
e exportar conjuntos de dados. Neste Capítulo vamos discutir os aspectos básicos da manipulação de
dados usando os princípios do tidy data ou dados arrumados. Este termo ficou famoso após o artigo
Tidy Data. O chamado tidy data segue três principios:

▶ Cada variável está em uma coluna.


▶ Cada observação está em uma linha.
▶ Cada tipo de unidade observacional está em uma célula.

A Figura 6.1 mostra uma representação de conjunto de dados em que os 3 princípios do tidy
data são atendidos.

Figura 6.1: Representação dos 3 princípios do tidy data.

A ideia parece simples mas na prática pode ser confuso. A melhor forma de entender esses
conceitos é por meio da prática e exemplos. Neste Capípulo vamos lidar com um conjunto de dados
bem simples para ilustrar os principais aspectos da importação, manipulação e exportação de dados.
No Capítulo 8 nós vamos retornar a todos esses conceitos por meio de um exemplo real similar ao
que você vai encontrar no dia-a-dia ao analisar dados.

85
86 Capítulo 6. Lidando com dados com o R base

6.1 Importando dados


No universo da análise de dados existem diversos tipos de arquivos, tais como: arquivos de
texto pleno, planilhas eletrônicas e banco de dados relacionais. Provavelmente, a forma mais popular
de armazenar um pequeno conjunto de dados é em uma planilha eletrônica. Todas as planilhas ele-
trônicas podem facilmente exportar uma tabela no formato retangular em um arquivo de texto pleno
(plain text). Para salvar uma planilha em formato texto pleno na maioria das planilhas eletrônicas basta
selecionar o Menu -> Arquivo (File) -> Salvar como (Save as) e selecionar o formato desejado. Um
cuidado importante é deixar a sua planilha o mais simples possível, ou seja, sem formatações, cores, cé-
lulas mescladas etc. Lembre-se cada coluna deve ser uma variável e cada linha uma observação. Entre
os diversos formatos disponíveis os mais usuais são: .csv (comma-separated value), .tsv (tab separated
values) e .fwf (fixed width format) ou versões destes.

A principal diferença entre esses formatos é o caracter ou estratégia usada para separar as
colunas da base de dados. Os nomes são auto-explicativos, por exemplo, no formato .csv as colunas
são separadas pelo símbolo , (vírgula). Em português usamos a , para representar decimais, por isso
usamos o ; (ponto e vírgula) para separar as colunas. Na prática tanto faz o formato desde que você
saiba qual é o caracter ou estratégia usada para delimitar as colunas.

Você pode estar pensando: por que não ler a planilha eletrônica diretamente? Isso é uma
possibilidade, porém a extensão das planilhas está atralada ao sistema operacional. Por exemplo: você
não terá planilhas do famoso Microsoft Excel em um sistema operacional Linux. Da mesma forma,
você não terá arquivos do tipo .odf do pacote OpenOffice, popular em ambientes Linux, em sistemas
operacionais Windows. Assim, optamos por usar arquivos de texto pleno porque são mais portáveis
e, de certa forma, agnósticos ao sistema operacional e/ou software fabricante.

Um arquivo no formato .csv quando visualizado em um editor de texto simples como o


bloco de notas, wordpad ou gedit tem o seguinte formato.

Sigla;Código;Município;idh;renda;alfab;
AC;1200013;Acrelândia;;136,539;73,309;
AC;1200054;Assis Brasil;;115,16;70,954;
AC;1200104;Brasiléia;;132,383;75,493;
AC;1200138;Bujari;;118,815;61,23;
AC;1200179;Capixaba;;108,164;62,283;
AC;1200203;Cruzeiro do Sul;;140,199;71,548;
AC;1200252;Epitaciolândia;;134,364;75,381;

Note que o caracter ; separa as colunas. Isso significa que ; é o caracter delimitador de
campos. De forma similar um arquivo .tsv tem a seguinte estrutura

circuito data rank corredor equipe


Monza 03 September 1950 1 Giuseppe Farina Alfa Romeo
Monza 03 September 1950 2 Dorino Serafini Ferrari
Monza 03 September 1950 2 Alberto Ascari Ferrari
Monza 03 September 1950 3 Luigi Fagioli Alfa Romeo
Monza 03 September 1950 4 Louis Rosier Lago
Monza 03 September 1950 5 Philippe Etancelin Lago

Ômega · Escola de Data Science omegadatascience.com.br


6.1 87

Neste caso o espaço em branco é quem delimita as colunas. Já o formato .fwf tem a seguinte
estrutura
1 2 PAUL TERGAT (69) M2529 0:44:47
2 6 HENDRICK RAMAALA (72) M2529 0:45:05
3 4 ELIJAH KIPTARBEI LAGAT (98) M0014 0:45:08
4 7 SILVIO GUERRA (68) M3034 0:45:17
5 12 JOHN GWAKO (78) M2024 0:45:29
6 1 EMERSON ISER BEM (73) M2529 0:45:37
7 134 JOSE TELES DE SOUZA (71) M2529 0:45:56
8 25 GERALDO DE ASSIS (65) M3034 0:46:04
9 14 PATRICK NDAYISENGA (71) M2529 0:46:11

Este formato é um pouco mais complicado, uma vez que não tem um caracter delimitador
de colunas. As colunas são especificadas pelo número de caracteres. Assim, você precisará saber qual
o comprimento em número de caracteres de cada coluna. Por ser mais complicado é um formato
menos popular.

Em R a função read.table() oferece uma forma simples de importar a maioria dos formatos
de dados em texto pleno. Ela oferece uma série de opções, vejamos os seus argumentos

args(read.table)

## function (file, header = FALSE, sep = ””, quote = ”\”’”, dec = ”.”,
## numerals = c(”allow.loss”, ”warn.loss”, ”no.loss”), row.names,
## col.names, as.is = !stringsAsFactors, na.strings = ”NA”,
## colClasses = NA, nrows = -1, skip = 0, check.names = TRUE,
## fill = !blank.lines.skip, strip.white = FALSE, blank.lines.skip = TRUE,
## comment.char = ”#”, allowEscapes = FALSE, flush = FALSE,
## stringsAsFactors = FALSE, fileEncoding = ””, encoding = ”unknown”,
## text, skipNul = FALSE)
## NULL

Você deve estar atento a alguns aspectos da base de dados que quer importar:

▶ A primeira linha de cada coluna é um título? Se sim, use header = TRUE.

▶ Qual é o caracter separador de colunas? Especifique o caracter separador usando o argumento


sep. Por exemplo, para arquivos .csv em português, usamos sep = ”;”.

▶ Qual é o caracter que representa decimais? Lembre-se, em inglês o decimal é representado pelo
ponto (.) ao invés da vírgula (,) como usamos em português.

▶ Qual foi o encoding usado para criar a base de dados? Esse é um aspecto mais avançado e diz res-
peito a forma como o computador armazena os caracteres que usamos de forma geral. Existem
diversos tipos de encoding e o tipo usado vai depender do seu sistema operacional. Geralmente,
sempre que criar e trabalhar com a base de dados no mesmo sistema operacional você não vai
precisar se preocupar com encoding. Porém, tenha em mente que se você importar um con-
junto de dados para o R e surgirem alguns caracteres estranhos, provavelmente você tem um
problema de encoding. Em geral, basta você abrir na sua planilha preferida e trocar o encoding
para algo como utf8 e dizer isso ao R por meio do argumento encoding.

Ômega · Escola de Data Science omegadatascience.com.br


88 Capítulo 6. Lidando com dados com o R base

Além destes tópicos devemos saber qual é o diretório dentro do computador onde o arquivo
está gravado. Neste livro leremos a base de dados direto de um endereço web. Porém, se não for o
seu caso, basta você especificar o caminho do seu arquivo no argumento file. Uma recomendação
é deixar a base de dados no mesmo diretório do seu arquivo .R. Assim, você pode simplesmente
fixar o diretório de trabalho como o diretório atual usando a função setwd() e ler o arquivo apenas
especificando o nome.

Para começar, vamos importar um arquivo no formato .txt que está no seguinte endereço:
http://leg.ufpr.br/~walmes/data/anovareg.txt. Você pode acessar este endereço e ver que o caracter
separar neste exemplo é um tab. Assim, devemos especificar o argumento sep = ”\t”. Além disso,
cada coluna tem um nome, por isso o argumento header = TRUE deve ser usado. O Código 6.1 ilustra
como importar esta base de dados para o R.

Código 6.1. Importando um arquivo do tipo .txt usando a função read.table().

#url <- ”http://leg.ufpr.br/~walmes/data/anovareg.txt”


#dados <- read.table(url, header = TRUE, sep = ”\t”)
#head(dados)

Vamos importar um outro conjunto de dados agora no formato .csv que está no seguinte
endereço web: http://leg.ufpr.br/~wagner/data/reglinear.csv. Novamente, você pode abrir o arquivo
em um editor de texto e ver que o caracter separador é um espaço em branco.

Código 6.2. Importando um arquivo do tipo .csv usando a função read.table().

#url <- ”http://leg.ufpr.br/~wagner/data/reglinear.csv”


#dados <- read.table(url, header = TRUE, sep = ” ”)
#head(dados)

Se a leitura foi executada com sucesso você não deve receber nenhuma mensagem. O erro
mais comum neste ponto é não especificar o caminho de diretórios corretamente, neste caso você vai
receber uma mensagem como esta

dados <- read.table(”reglinear.csv”, header = TRUE, sep = ” ”)

## Error in file(file, ”rt”): não é possível abrir a conexão

O R está dizendo que não conseguiu encontrar o arquivo que você deseja ler no diretório
que ele está procurando. Lembre-se: para saber onde o R está trabalhando use o comando getwd().

Com a leitura bem sucedida, é hora de inspecionar o que foi carregado. Recomendamos usar
a função str() para ter uma visão geral do arquivo.

#str(dados)

A função str() começa mostrando quantas observações e quantas colunas a base de dados
contém. Neste caso temos 20 observações (linhas) e 2 variáveis (colunas). Na sequência é apresentado

Ômega · Escola de Data Science omegadatascience.com.br


6.2 89

o nome de cada coluna e o tipo de dado que ela representa. Neste exemplo, temos variáveis do tipo
num e int que são abreviações dos tipos de vetores numeric e integer.

6.2 Arrumando dados


Para analisar um conjunto de dados é importante que ele esteja arrumado, ou seja, cada coluna
deve ser uma variável e cada linha uma observação. Na maioria das situações práticas os dados não
estarão neste formato e você precisará trabalhar para deixá-lo desta forma.

Uma situação comum é quando os dados vêm em muitas colunas. Este caso ocorre muito
na tabulação de dados de experimentos nos quais se tem medidas realizadas ao longo do tempo. Por
exemplo,

n <- 3
tb1 <- data.frame(”trat” = LETTERS[1:n],
aval1 = rpois(n, 4),
aval2 = rpois(n, 4),
aval3 = rpois(n, 4))
tb1

## trat aval1 aval2 aval3


## 1 A 5 5 6
## 2 B 3 9 6
## 3 C 4 4 5

Neste caso temos que as observações da variável de interesse está em três colunas. Além disso,
a variável avaliação, que deveria ser uma única coluna, está no título de três outras colunas. Este
é um exemplo típico de dados desorganizados que está no formato amplo (wide). Nós queremos
transformá-lo para o formato longo (long), de modo que cada variável esteja em uma coluna e cada
observação em uma linha.

tb1_long <- reshape(data = tb1,


direction = ”long”,
v.names = ”resposta”,
varying = c(”aval1”, ”aval2”, ”aval3”),
times = names(tb1)[2:4],
timevar = ”avaliação”,
idvar = ”trat”,
new.row.names = 1:9)
tb1_long

## trat avaliação resposta


## 1 A aval1 5
## 2 B aval1 3
## 3 C aval1 4
## 4 A aval2 5
## 5 B aval2 9
## 6 C aval2 4
## 7 A aval3 6
## 8 B aval3 6
## 9 C aval3 5

Ômega · Escola de Data Science omegadatascience.com.br


90 Capítulo 6. Lidando com dados com o R base

Vamos aos detalhes desta operação:

▶ O argumento data simplesmente recebe o data.frame que queremos organizar.

▶ O argumento direction indica que vamos criar um novo data.frame no formato longo.

▶ O argumento v.names recebe o nome da coluna que vamos criar para receber os valores que
estavam nas colunas aval1, aval2 e aval3.

▶ O argumento varying indica quais colunas tem os valores que queremos empilhar.

▶ O argumento times indica a qual coluna os dados empilhados pertenciam.

▶ O argumento timevar simplesmente nomeia a coluna criada com o argumento times.

▶ O argumento idvar é o nome da coluna que vai identificar múltiplas observações provenientes
do mesmo grupo, neste caso os tratamentos entre as múltiplas avaliações.

▶ O argumento new.row.names dá nomes novos às linhas do data.frame criado. Neste caso como
o novo data.frame terá nove linhas, elas foram nomeadas com os inteiros entre 1 e 9.

Podemos também fazer a operação inversa, ou seja, desempilhar caso seja de interesse.

reshape(data = tb1_long,
direction = ”wide”,
timevar = ”avaliação”,
idvar = ”trat”,
v.names = ”resposta”)

## trat resposta.aval1 resposta.aval2 resposta.aval3


## 1 A 5 5 6
## 2 B 3 9 6
## 3 C 4 4 5

Outra operação que pode ser necessária é separar uma variável em várias outras. Isso é comum
quando um campo de texto é a união de várias informações. Considere o seguinte data.frame.

tb <- data.frame(veiculo = c(”Celta”, ”Gol”, ”Uno”),


ano_mod = c(”2011/2012”, ”2012/2012”, ”2015/2016”),
local = c(”Curitiba-PR”, ”Santos-SP”, ”Viçosa-MG”))
tb

## veiculo ano_mod local


## 1 Celta 2011/2012 Curitiba-PR
## 2 Gol 2012/2012 Santos-SP
## 3 Uno 2015/2016 Viçosa-MG

A coluna ano_mod é a mistura das variáveis ano do veículo e modelo do veículo. De forma
similar, a coluna local é a mistura de duas variáveis: município e unidade federativa (UF). Assim,
precisamos separar estas informações. Note que o caracter / é quem separa as informações na coluna
ano_mod enquanto que na coluna local o caracter - é o separador. Neste caso precisamos primeiro
separar as informações e depois criar novas colunas com as informações corretas. Para separar as
informações usamos a função strsplit.

Ômega · Escola de Data Science omegadatascience.com.br


6.2 91

strsplit(as.character(tb$ano_mod), split = ”/”)

## [[1]]
## [1] ”2011” ”2012”
##
## [[2]]
## [1] ”2012” ”2012”
##
## [[3]]
## [1] ”2015” ”2016”

strsplit(as.character(tb$local), split = ”-”)

## [[1]]
## [1] ”Curitiba” ”PR”
##
## [[2]]
## [1] ”Santos” ”SP”
##
## [[3]]
## [1] ”Viçosa” ”MG”

A função strsplit() retornou uma lista. Agora precisamos manipular esta lista para depois
juntá-la com o data.frame original.

ano_temp <- data.frame(do.call(rbind, strsplit(as.character(tb$ano_mod), split = ”/”)))


local_temp <- data.frame(do.call(rbind, strsplit(as.character(tb$local), split = ”-”)))
ano_temp

## X1 X2
## 1 2011 2012
## 2 2012 2012
## 3 2015 2016

A ideia deste código é que a função do.call() vai a cada slot da lista e aplica a função
rbind() que serve para agregar linhas em um vetor. O objeto resultante é uma matrix que é então
convertida para um data.frame. Podemos renomear as colunas do data.frame gerado e acoplar com o
data.frame original.

# Renomeando
names(ano_temp) <- c(”Ano”, ”Modelo”)
names(local_temp) <- c(”Município”, ”UF”)

# Acoplando
tb_nova <- cbind(tb, ano_temp, local_temp)
tb_nova

## veiculo ano_mod local Ano Modelo Município UF


## 1 Celta 2011/2012 Curitiba-PR 2011 2012 Curitiba PR
## 2 Gol 2012/2012 Santos-SP 2012 2012 Santos SP
## 3 Uno 2015/2016 Viçosa-MG 2015 2016 Viçosa MG

Para manter os princípios do tidy data precisamos remover as colunas desnecessárias. Para
isso vamos usar a função subset(). Como o nome sugere, esta função captura um sub conjunto do

Ômega · Escola de Data Science omegadatascience.com.br


92 Capítulo 6. Lidando com dados com o R base

conjunto de dados original. O argumento select permite remover as colunas não necessárias pelo
nome, basta colocar o sinal - na frente do nome das colunas que desejamos remover.

tb_nova <- subset(tb_nova, select = -c(ano_mod, local))


tb_nova

## veiculo Ano Modelo Município UF


## 1 Celta 2011 2012 Curitiba PR
## 2 Gol 2012 2012 Santos SP
## 3 Uno 2015 2016 Viçosa MG

Da mesma forma que podemos separar variáveis que estão em uma mesma coluna pode ser
necessário criar novas variáveis unindo os valores de duas ou mais colunas. Por exemplo, suponha que
em um data.frame os campos dia, mês e ano estão cada um em uma coluna. Porém, você precisa de
apenas uma coluna que represente a data da observação. Assim, precisamos juntar essas três colunas
em uma nova. Uma função bastante útil nesta situação é a função paste(). A ideia é simplesmente
colar os caracteres criando um novo caracter.

tb <- data.frame(dia = c(1, 5, 23, 16),


mes = c(3, 6, 2, 9),
ano = 2018)
tb$data <- paste(tb$dia, tb$mes, tb$ano, sep = ”/”)

A solução de certa forma funcionou. No entanto, o caracter criado não tem a classe de data.
Podemos agora converter para a classe Date

tb$data <- as.Date(tb$data, format = ”%d/%m/%Y”)


tb

## dia mes ano data


## 1 1 3 2018 2018-03-01
## 2 5 6 2018 2018-06-05
## 3 23 2 2018 2018-02-23
## 4 16 9 2018 2018-09-16

Por fim, teremos frequentemente que lidar com dados faltantes. Algumas vezes podemos
simplesmente querer remover todas as linhas que tenham algum NA. Outras vezes queremos preencher
com algum valor específico. Ambas as situações são comuns e facilmente executadas em R. Veja o
seguinte conjunto de dados

tb <- data.frame(jogador = 1:5,


jogos = c(0, 1, 3, 1, 2),
gols = c(NA, 0, 0, 2, 1),
faltas = c(NA, 1, 1, 0, 0))

Para excluir todas as linhas que contenham pelo menos um NA temos a função na.exclude.

na.exclude(tb)

Ômega · Escola de Data Science omegadatascience.com.br


6.3 93

## jogador jogos gols faltas


## 2 2 1 0 1
## 3 3 3 0 1
## 4 4 1 2 0
## 5 5 2 1 0

Para substituir os campos iguais a NA por algum valor, como 0, primeiro precisamos localizá-
los e depois atribuir o valor.

tb[is.na(tb)] <- 0
tb

## jogador jogos gols faltas


## 1 1 0 0 0
## 2 2 1 0 1
## 3 3 3 0 1
## 4 4 1 2 0
## 5 5 2 1 0

Uma estratégia similar pode ser aplicada para cada coluna atribuindo valores diferentes de-
pendendo do contexto. É importante salientar que tratar dados ausentes de forma estatisticamente
coerente nem sempre é uma tarefa fácil. Assim, pense muito bem o que os dados faltantes significam
no contexto que você está trabalhando e se faz sentido substituir por algum número ou mesmo excluir
da base de dados.

6.3 Manipulando dados


Uma vez que os dados estejam arrumados é a hora de começar a conhecê-los. Seguindo os
princípios do tidy data para manipular um conjunto de dados temos cinco ações essenciais:

▶ Ordenar observações de acordo com os seus valores.

▶ Selecionar variáveis de acordo com o seu nome e/ou características.

▶ Filtrar observações de acordo com os seus valores.

▶ Criar/transformar variáveis a partir de variáveis já existentes.

▶ Resumir ou sumarizar dados. Essa ação é a mais complexa e em geral envolve o uso de medidas
estatísticas como média, mediana, desvio-padrão entre outros para criar resumo dos dados.

Para ilustrar o uso de cada uma destas ações vamos considerar os dados apresentados na Figura
6.2.

Podemos entrar com esses dados diretamente em R conforme abaixo.

Ômega · Escola de Data Science omegadatascience.com.br


94 Capítulo 6. Lidando com dados com o R base

Figura 6.2: Uma tabela com dados fictícios sobre alunos e seus desempenhos.

df1 <- data.frame(


matricula = c(256, 487, 965,
125, 458, 874, 963),
nome = c(”João”, ”Vanessa”, ”Tiago”,
”Luana”, ”Gisele”, ”Pedro”,
”André”),
curso = c(”Mat”, ”Mat”, ”Est”, ”Est”,
”Est”, ”Mat”, ”Est”),
prova1 = c(80, 75, 95, 70, 45, 55, 30),
prova2 = c(90, 75, 80, 85, 50, 75, NA),
prova3 = c(80, 75, 75, 50, NA, 90, 30),
faltas = c(4, 4, 0, 8, 16, 0, 20))

A ação mais simples é a de ordenação, ilustrada na Figura 6.3. A ordenação pode ser feita de
acordo com os valores de uma ou mais variáveis.

Em R a função order() retorna a ordem crescente de um vetor. Podemos usar esta função
para reordenar um data.frame de acordo com os valores de uma ou mais de suas colunas. Por exemplo,
podemos ordenar os alunos pelo número de matrícula, como ilustrado na Figura 6.3 (linha 1).

df1[order(df1[, ”matricula”]),]

## matricula nome curso prova1 prova2 prova3 faltas


## 4 125 Luana Est 70 85 50 8
## 1 256 João Mat 80 90 80 4
## 5 458 Gisele Est 45 50 NA 16
## 2 487 Vanessa Mat 75 75 75 4
## 6 874 Pedro Mat 55 75 90 0
## 7 963 André Est 30 NA 30 20
## 3 965 Tiago Est 95 80 75 0

A ideia é similar para ordenar por duas ou mais colunas. Por exemplo, ordenando por curso
e nota da prova 1.

Ômega · Escola de Data Science omegadatascience.com.br


6.3 95

Figura 6.3: Ordenação dos registros de uma tabela.

idx <- order(df1[,”curso”], df1[,”prova1”])


df1[idx,]

## matricula nome curso prova1 prova2 prova3 faltas


## 7 963 André Est 30 NA 30 20
## 5 458 Gisele Est 45 50 NA 16
## 4 125 Luana Est 70 85 50 8
## 3 965 Tiago Est 95 80 75 0
## 6 874 Pedro Mat 55 75 90 0
## 2 487 Vanessa Mat 75 75 75 4
## 1 256 João Mat 80 90 80 4

Para ordenar de forma descrescente basta usar a função order() com o argumento decreasing
= TRUE.

A próxima ação é de seleção e pode ser feita de várias formas:

▶ Pelo nome das colunas.


▶ Pela posição das linhas ou das colunas.
▶ Condicional ao valor de uma ou mais variáveis.
▶ Por extremidades cabeça (head) e cauda (tail).

Suponha que temos interesse apenas nas colunas nome, curso e faltas. Podemos selecionar
as colunas pelos seus nomes.

df1[,c(”nome”, ”curso”, ”faltas”)]

Ômega · Escola de Data Science omegadatascience.com.br


96 Capítulo 6. Lidando com dados com o R base

## nome curso faltas


## 1 João Mat 4
## 2 Vanessa Mat 4
## 3 Tiago Est 0
## 4 Luana Est 8
## 5 Gisele Est 16
## 6 Pedro Mat 0
## 7 André Est 20

Pelas posições das colunas.

df1[, c(2,3,7)]

## nome curso faltas


## 1 João Mat 4
## 2 Vanessa Mat 4
## 3 Tiago Est 0
## 4 Luana Est 8
## 5 Gisele Est 16
## 6 Pedro Mat 0
## 7 André Est 20

Podemos selecionar apenas os alunos com mais de dez faltas.

subset(df1, faltas > 10)

## matricula nome curso prova1 prova2 prova3 faltas


## 5 458 Gisele Est 45 50 NA 16
## 7 963 André Est 30 NA 30 20

Podemos também selecionar pelo número das linhas.

df1[3:5,]

## matricula nome curso prova1 prova2 prova3 faltas


## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16

E pelas extremidades: cabeça (head) mostra as primeiras seis observações e cauda (tail) mostras
as últimas seis observações. O número de observações pode ser alterado pelo argumento n.

# Cabeça
head(df1)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 6 874 Pedro Mat 55 75 90 0

# Cauda
tail(df1)

Ômega · Escola de Data Science omegadatascience.com.br


6.3 97

## matricula nome curso prova1 prova2 prova3 faltas


## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 6 874 Pedro Mat 55 75 90 0
## 7 963 André Est 30 NA 30 20

Entre as diversas ações possíveis, a de filtrar observações de acordo com suas características é
uma das mais importantes. Em R nós já vimos a função subset(), que permite fazer filtros ou obter
subconjuntos que tenham características de interesse. Similar a ação de seleção, a ação de filtro pode
ser realizada por uma ou mais características. Por exemplo, podemos selecionar só os alunos do curso
de estatística.

subset(df1, curso == ”Est”)

## matricula nome curso prova1 prova2 prova3 faltas


## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 7 963 André Est 30 NA 30 20

Outro exemplo é selecionar alunos do curso de estatística e que a soma das notas das provas
1, 2 e 3 seja maior que 180.

subset(df1, curso == ”Est” & (prova1 + prova2 + prova3) > 180)

## matricula nome curso prova1 prova2 prova3 faltas


## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8

Alunos que tenham alguma falta.

subset(df1, faltas != 0)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 7 963 André Est 30 NA 30 20

Pelo nome dos alunos.

subset(df1, nome %in% c(”Aline”, ”Vanessa”))

## matricula nome curso prova1 prova2 prova3 faltas


## 2 487 Vanessa Mat 75 75 75 4

O operador %in% implica na seleção de qualquer um que se encaixar em c(”Aline”,


”Vanessa”). Como não temos nenhuma Aline, a saída retornou apenas a linha da aluna Vanessa.

Ômega · Escola de Data Science omegadatascience.com.br


98 Capítulo 6. Lidando com dados com o R base

As operações de criar/transformar nos permitem por exemplo renomear as colunas do con-


junto de dados. Veja a ilustração da Figura 6.4.

Figura 6.4: Formas de renomear as colunas de uma tabela.

Para renomear as colunas de um data.frame basta atribuir novos nomes.

names(df1) <- c(”mat.”, ”nome”, ”curso”, ”p1”, ”p2”, ”p3”, ”fl”)

Trocar a ordem das colunas para que as notas das provas apareçam primeiro pode ser feito
tanto pelo nome como pelos números associados às colunas.

df1[,c(4,5,6,1,2,3)]

## p1 p2 p3 mat. nome curso


## 1 80 90 80 256 João Mat
## 2 75 75 75 487 Vanessa Mat
## 3 95 80 75 965 Tiago Est
## 4 70 85 50 125 Luana Est
## 5 45 50 NA 458 Gisele Est
## 6 55 75 90 874 Pedro Mat
## 7 30 NA 30 963 André Est

A ação de transformação consiste em criar novas variáveis a partir das variáveis existentes. A
ideia é ilustrada na Figura 6.5.

Por exemplo, podemos calcular a média dos alunos.

df1$media <- (df1$p1 + df1$p2 + df1$p3)/3

Ômega · Escola de Data Science omegadatascience.com.br


6.3 99

Figura 6.5: Criação e deleção de variáveis em uma tabela.

Note que, onde os alunos não tem nota na prova, o cálculo da média resultou em NA. Vamos
supor que se o aluno não realizou a prova a nota dele será zero.

df1[is.na(df1)] <- 0
df1$media <- (df1$p1 + df1$p2 + df1$p3)/3
df1

## mat. nome curso p1 p2 p3 fl media


## 1 256 João Mat 80 90 80 4 83.3
## 2 487 Vanessa Mat 75 75 75 4 75.0
## 3 965 Tiago Est 95 80 75 0 83.3
## 4 125 Luana Est 70 85 50 8 68.3
## 5 458 Gisele Est 45 50 0 16 31.7
## 6 874 Pedro Mat 55 75 90 0 73.3
## 7 963 André Est 30 0 30 20 20.0

Podemos criar uma coluna para verificar se o aluno está aprovado (média > 70), em exame
(40 < média < 70) ou reprovado (média < 40) usando a função cut() temos

breaks <- c(0, 40, 70, 100)


df1$Condicao <- cut(df1$media,
breaks = breaks,
labels = c(”Reprovado”, ”Exame”, ”Aprovado”))
df1

Ômega · Escola de Data Science omegadatascience.com.br


100 Capítulo 6. Lidando com dados com o R base

## mat. nome curso p1 p2 p3 fl media Condicao


## 1 256 João Mat 80 90 80 4 83.3 Aprovado
## 2 487 Vanessa Mat 75 75 75 4 75.0 Aprovado
## 3 965 Tiago Est 95 80 75 0 83.3 Aprovado
## 4 125 Luana Est 70 85 50 8 68.3 Exame
## 5 458 Gisele Est 45 50 0 16 31.7 Reprovado
## 6 874 Pedro Mat 55 75 90 0 73.3 Aprovado
## 7 963 André Est 30 0 30 20 20.0 Reprovado

A última ação que vamos discutir é a de resumo ou sumarização. Esta ação está muito ligada
com a ideia de dados no formato longo e amplo. No exemplo das notas dos alunos o conjunto de dados
está no formato amplo. Se desejarmos calcular a média de cada prova precisamos percorrer as colunas
p1, p2 e p3 uma a uma calculando a média. Se os dados estiverem no formato longo poderíamos mais
facilmente usar a ideia de resumir uma variável condicional aos valores de uma outra, neste caso: a
prova. A Figura 6.6 ilustra como é o processo de tornar um conjunto de dados do formato amplo
para o longo ou empilhado.

Usando a função reshape podemos facilmente passar um conjunto de dados do formato am-
plo para longo. Note que vamos remover as colunas mat., fl, media e condicao antes de fazer a
manipulação.

df1_temp <- subset(df1, select = -c(mat., fl, media, Condicao))


df1_long <- reshape(data = df1_temp,
direction = ”long”,
v.names = ”notas”,
varying = c(”p1”, ”p2”, ”p3”),
times = names(df1)[4:6],
timevar = ”exame”,
idvar = ”nome”,
new.row.names = 1:21)

Agora suponha que queremos saber qual é a nota média por prova. Estamos fazendo um
resumo da coluna notas porém de acordo com os valores da coluna exame. Informalmente, dizemos
que estamos agrupando pela coluna exame ou fazendo um group by por exame. Este tipo de sumariza-
ção é tão comum em análise de dados que em R temos a função aggregate(), especializada neste tipo
de sumarização. Vejamos a sintaxe no Código 6.3.

Código 6.3. Exemplo de sintaxe da função aggregate.

aggregate(x = df1_long$notas,
by = list(df1_long$exame),
FUN = mean)

## Group.1 x
## 1 p1 64.3
## 2 p2 65.0
## 3 p3 57.1

Em detalhes, temos:

▶ x: neste argumento passamos os valores que queremos resumir. No exemplo: as notas dos

Ômega · Escola de Data Science omegadatascience.com.br


6.3 101

Figura 6.6: Modificação da disposição com empilhamento.

alunos.

▶ by: este argumento deve ser uma lista com os valores pelos quais queremos calcular o resumo.
No nosso exemplo: por cada prova.

▶ FUN: neste argumento dizemos qual é o resumo que queremos calcular. Neste exemplo: a média
(mean).

O retorno da função é um data.frame com os valores calculados. Podemos agrupar por mais
de uma coluna. Por exemplo, a nota média de cada curso para cada exame.

aggregate(x = df1_long$notas,
by = list(df1_long$curso, df1_long$exame),
FUN = mean)

Ômega · Escola de Data Science omegadatascience.com.br


102 Capítulo 6. Lidando com dados com o R base

## Group.1 Group.2 x
## 1 Est p1 60.0
## 2 Mat p1 70.0
## 3 Est p2 53.8
## 4 Mat p2 80.0
## 5 Est p3 38.8
## 6 Mat p3 81.7

Outra opção é calcular mais do que uma medida resumo. Neste caso a sintaxe fica um pouco
mais complicada porque devemos passar uma função no argumento FUN que calcula todas os resumos
que desejarmos. No exemplo do Código 6.4 calculamos a média e o desvio-padrão por curso e prova.

Código 6.4. Exemplo de sintaxe da função aggregate para obter múltiplas medidas resumo.

aggregate(x = df1_long$notas,
by = list(df1_long$curso, df1_long$exame),
FUN = function(x) {
c(”media” = mean(x), ”sd” = sd(x))
})

## Group.1 Group.2 x.media x.sd


## 1 Est p1 60.00 28.58
## 2 Mat p1 70.00 13.23
## 3 Est p2 53.75 39.02
## 4 Mat p2 80.00 8.66
## 5 Est p3 38.75 31.72
## 6 Mat p3 81.67 7.64

Este tipo de tarefa é também chamada de split-apply-combine. A Figura 6.7 mostra em detalhes
o que foi realizado.

Primeiro nós dividimos (split) o conjunto de dados pelas variáveis curso e exame. Para cada
pedaço foram calculadas as medidas resumo (apply). Finalmente, combinamos os resultados em um
novo data.frame (combine).

6.4 Combinando dados


Em algumas situações pode ser necessário combinar diversos conjuntos de dados. A situação
mais comum é quando você já tem um conjunto de dados, como por exemplo o nosso df1, e um novo
conjunto de dados chega. Assim, precisamos combinar os dados que já temos com o novo. Suponha
que o novo conjunto de dados é o seguinte.

df2 <- data.frame(


matricula = c(505, 658, 713),
nome = c(”Bia”, ”Carlos”, ”Cris”),
curso = c(”Eng”, ”Eng”, ”Eng”),
prova1 = c(65, 75, 75),
prova2 = c(85, 80, 90),
faltas = c(0, 0, 2))

Ômega · Escola de Data Science omegadatascience.com.br


6.4 103

Figura 6.7: Agregação de uma tabela.

Para combinar o novo conjunto de dados com o antigo a primeira coisa a fazer é deixá-los
compatíveis. Isso significa que devem ter os mesmos dados e as colunas devem ter os mesmos nomes.
Como fizemos diversos cálculos com o df1, vamos recriá-lo.

df1 <- data.frame(


matricula = c(256, 487, 965,
125, 458, 874, 963),
nome = c(”João”, ”Vanessa”, ”Tiago”,
”Luana”, ”Gisele”, ”Pedro”,
”André”),
curso = c(”Mat”, ”Mat”, ”Est”, ”Est”,
”Est”, ”Mat”, ”Est”),
prova1 = c(80, 75, 95, 70, 45, 55, 30),
prova2 = c(90, 75, 80, 85, 50, 75, NA),
prova3 = c(80, 75, 75, 50, NA, 90, 30),
faltas = c(4, 4, 0, 8, 16, 0, 20))

Note que no conjunto df2 não temos uma coluna chamada de prova3. Assim, primeiro
precisamos criar esta coluna.

df2$prova3 <- NA

Ômega · Escola de Data Science omegadatascience.com.br


104 Capítulo 6. Lidando com dados com o R base

Uma vez que os conjuntos de dados são compatíveis, podemos simplesmente concatenar suas
linhas usando a função rbind().

df <- rbind(df1, df2)


df

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 6 874 Pedro Mat 55 75 90 0
## 7 963 André Est 30 NA 30 20
## 8 505 Bia Eng 65 85 NA 0
## 9 658 Carlos Eng 75 80 NA 0
## 10 713 Cris Eng 75 90 NA 2

Figura 6.8 ilustra a operação realizada.

Figura 6.8: Concatenação de duas tabelas.

Por fim, uma outra operação que aparece com frequência ao analisar dados é a de juntar/parear
duas tabelas que possuem uma chave primária. Essas operações são geralmente chamadas de junções
( join ) e existem diversas versões, as mais comuns são:

▶ Junção por interseção (inner join).


▶ Junção por união (full join).
▶ Junção à esquerda (left join).
▶ Junção à direita (right join).
▶ Existem também os chamados exclusive joins.

Cada uma destas versões são ilustradas na Figura 6.10.

Ômega · Escola de Data Science omegadatascience.com.br


6.4 105

Figura 6.9: Tipos de junções de tabelas ilustrado com diagramas de Veen.

Para praticarmos este tipo de operação considere o seguinte conjunto de dados.

df_extra <- data.frame(


”matricula” = c(256, 965, 285, 125, 874, 321, 669, 963),
”nome” = c(”João”, ”Tiago”, ”Tiago”, ”Luana”,
”Pedro”, ”Mia”, ”Luana”, ”André”),
”idade” = c(18, 18, 22, 21, 19, 18, 19, 20),
”bolsista” = c(”S”, ”N”, ”N”, ”S”, ”N”, ”N”, ”S”, ”N”))

Para junções, a função merge() é a principal referência em R.

# Left join
merge(df1, df_extra, by = ”matricula”, all.x = TRUE)

# Right join
merge(df1, df_extra, by = ”matricula”, all.y = TRUE)

# inner join
merge(df1, df_extra, by = ”matricula”, all = FALSE)

# full join
merge(df1, df_extra, by = ”matricula”, all = TRUE)

A diferença entre os diferentes join é bastante simples:

▶ left join: mantém todos os registros da tabela a esquerda (df1) e completa com os corresponden-
tes na tabela da direita (df_extra).

Ômega · Escola de Data Science omegadatascience.com.br


106 Capítulo 6. Lidando com dados com o R base

▶ right join: mantém todos os registros da tabela da direita (df_extra) e completa com os dados
da tabela da esquerda (df1).

▶ inner join: mantém apenas os registros que estão em ambas tabelas.

▶ full join: mantém todos os registros e preenche com NA onde não tem correspondência entre
as tabelas.

Figura 6.10 ilustra os diferentes tipos de join para um subconjunto dos dados das notas dos
alunos.

Figura 6.10: Junções de tabelas do tipo inclusivas.

6.5 Exportando dados


Após realizar as análises é bastante provável que você precise exportar um conjunto de dados
organizado ou mesmo uma tabela com estatísticas. O R tem uma longa lista de funções para exportar
dados. Novamente, a forma mais comum é exportar um arquivo de texto pleno nos formatos .csv
ou .txt. Para esta tarefa a função write.table() é a referência a ser usada. Podemos exportar o
resultado da junção das tabelas df1 e df_extra como o resultado final de nossa análise, conforme
ilustra o Código 6.5.

Código 6.5. Exemplo de uso da função write.table() para exportar arquivos de texto pleno.

final <- merge(df1, df_extra,


by = ”matricula”,
all = FALSE) # inner join

write.table(x = final,
file = ”Nome_do_arquivo.csv”,
row.names = FALSE)

Os argumentos básicos são o data.frame que você quer salvar em disco e o nome desejado.
Neste caso foi solicitado para que o nome das linhas não fosse incluído no arquivo salvo. A maioria dos

Ômega · Escola de Data Science omegadatascience.com.br


6.5 107

argumentos de escrita são iguais ou muito similares aos argumentos de leitura. Assim, exportação de
dados não gera mais complexidade e tudo que você já aprendeu para leitura se aplica imediatamente.

Sem dúvida, exportar dados em texto pleno é muito fácil e simples. No entanto, existem
algumas desvantagens. A principal é que as classes das colunas podem ser perdidas ao ler novamente
o conjunto de dados em R. Por ser um texto pleno o arquivo não carrega metadados que foram criados
em R. Caso seja de interesse, é possível salvar o próprio objeto R que contém o seu data.frame usando
a função save().

save(final,
file = ”Nome_do_arquivo.RData”)

A principal vantagem é que tudo que você fez no objeto final será mantido. Outra vanta-
gem é que você pode salvar outros formatos de dados como listas, matrizes e arrays. Para carregar
novamente o data.frame você deve usar a função load().

load(”Nome_do_arquivo.RData”)

Caso você tenha um objeto mais complicado, como por exemplo uma série de listas, a função
dput() é uma opção interessante. Ela permite salvar um objeto R como um texto simples que pode
ser copiado e colado.

dput(final)

É possível também escrever um arquivo com extensão .R que pode ser posteriormente carre-
gado no R.

dput(final,
file = ”Nome_do_arquivo.R”)

Para carregar os dados basta usar a função dget().

dget(”Nome_do_arquivo.R”)

Essa estratégia pode ser usada para múltiplos objetos usando a função dump().

dump(c(”final”, ”df1”),
file = ”Nome_do_arquivo.R”)

Que agora deve ser carregado em R usando a função source().

source(”Nome_do_arquivo.R”)

Um outro formato que o R exporta é o formato binário com a extensão .rda. As vantagens
deste formato são que ocupa pouco espaço em disco e preserva as propriedades do objeto R.

Ômega · Escola de Data Science omegadatascience.com.br


108 Capítulo 6. Lidando com dados com o R base

save(final,
file = ”Nome_do_arquivo.rda”)

Neste caso, podemos usar novamente a função load() para fazer a leitura em R.

Por fim, você pode salvar todos os objetos e instruções que você usou em sua sessão R usando
a função save.image().

Lembre-se: sempre que você não especificar o caminho de escrita explicitamente, o R vai
escrever no diretório de trabalho atual. Algumas funções úteis para você ter controle de onde o R está
escrevendo os arquivos são:

▶ file.info(): mostra o tamanho do arquivo, data de criação e outros detalhes do arquivo.


▶ dir(): mostra todos os arquivos presentes em um diretório.
▶ file.exists(): verifica se um arquivo já existe (TRUE) ou não (FALSE) no diretório de trabalho.
▶ getwd() e setwd(): verifica e altera o diretório de trabalho, respectivamente.

Neste Capítulo foram vistas as principais operações com dados tabulares. A esta altura, esta-
mos prontos para falar sobre análise descritiva e exploratória de dados.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 7

Lidando com dados com o tidyverse

Ao trabalhar com ciência de dados lidamos com dados de todos os tipos e formatos diaria-
mente. O R nativamente apresenta um conjunto completo de ferramentas para importar, manipular
e exportar conjuntos de dados. Também existem pacotes especializados para estas tarefas, tais como
os pacotes tidyverse: readr para leitura, tidyr para arrumação e o dplyr para manipulação. Neste
Capítulo vamos discutir os aspectos básicos da manipulação de dados usando os princípios do tidy
data ou dados arrumados. Este termo ficou famoso após o artigo Tidy Data. O chamado tidy data
segue três principios:

▶ Cada variável está em uma coluna.


▶ Cada observação está em uma linha.
▶ Cada tipo de unidade observacional está em uma célula.

A Figura 7.1 mostra uma representação de conjunto de dados em que os 3 princípios do tidy
data são atendidos.

Figura 7.1: Representação dos 3 princípios do tidy data.

A ideia parece simples mas na prática pode ser confuso. A melhor forma de entender esses
conceitos é por meio da prática e exemplos. Neste Capítulo vamos lidar com conjuntos de dados bem
simples para ilustrar os principais aspectos da importação, manipulação e exportação de dados. No

109
110 Capítulo 7. Lidando com dados com o tidyverse

Capítulo 8 vamos retornar a todos esses conceitos por meio de um exemplo real similar ao que você
vai encontrar no dia-a-dia ao analisar dados.

7.1 Importando dados


No universo da análise de dados existem diversos tipos de arquivos, tais como: arquivos de
texto pleno, planilhas eletrônicas e banco de dados relacionais. Provavelmente, a forma mais popular
de armazenar um pequeno conjunto de dados é em uma planilha eletrônica. Todas as planilhas ele-
trônicas podem facilmente exportar uma tabela no formato retangular em um arquivo de texto pleno
(plain text). Para salvar uma planilha em formato texto pleno na maioria das planilhas eletrônicas basta
selecionar o Menu -> Arquivo (File) -> Salvar como (Save as) e selecionar o formato desejado. Um
cuidado importante é deixar a sua planilha o mais simples possível, ou seja, sem formatações, cores,
células mescladas, etc. Lembre-se: cada coluna deve ser uma variável e cada linha uma observação.
Entre os diversos formatos disponíveis os mais usuais são: .csv (comma-separated value), .tsv (tab
separated values), .fwf (fixed width format) ou versões destes.

A principal diferença entre esses formatos é o caracter ou estratégia usada para separar as
colunas da base de dados. Os nomes são auto-explicativos, por exemplo, no formato .csv as colunas
são separadas pelo símbolo , (vírgula). Em português usamos a , para representar decimais, por isso
usamos o ; (ponto e vírgula) para separar as colunas. Na prática tanto faz o formato desde que você
saiba qual é o caracter ou estratégia usada para delimitar as colunas.

Você pode estar pensando: por que não ler a planilha eletrônica diretamente? Isso é uma
possibilidade, porém a extensão das planilhas está atrelada ao sistema operacional. Por exemplo: você
não terá planilhas do famoso Microsoft Excel em um sistema operacional Linux. Da mesma forma,
você dificilmente terá arquivos do tipo .odf do pacote OpenOffice, popular em ambientes Linux, em
sistemas operacionais Windows. Assim, optamos por usar arquivos de texto pleno porque são mais
portáveis e, de certa forma, agnósticos ao sistema operacional e/ou software fabricante.

Um arquivo no formato .csv quando visualizado em um editor de texto simples como o


bloco de notas, wordpad ou gedit tem o seguinte formato.

Sigla;Código;Município;idh;renda;alfab;
AC;1200013;Acrelândia;;136,539;73,309;
AC;1200054;Assis Brasil;;115,16;70,954;
AC;1200104;Brasiléia;;132,383;75,493;
AC;1200138;Bujari;;118,815;61,23;
AC;1200179;Capixaba;;108,164;62,283;
AC;1200203;Cruzeiro do Sul;;140,199;71,548;
AC;1200252;Epitaciolândia;;134,364;75,381;

Note que o caracter ; separa as colunas. Isso significa que ; é o caracter delimitador de
campos. De forma similar um arquivo .tsv tem a seguinte estrutura

Ômega · Escola de Data Science omegadatascience.com.br


7.1 111

circuito data rank corredor equipe


Monza 03 September 1950 1 Giuseppe Farina Alfa Romeo
Monza 03 September 1950 2 Dorino Serafini Ferrari
Monza 03 September 1950 2 Alberto Ascari Ferrari
Monza 03 September 1950 3 Luigi Fagioli Alfa Romeo
Monza 03 September 1950 4 Louis Rosier Lago
Monza 03 September 1950 5 Philippe Etancelin Lago

Neste caso o espaço em branco é quem delimita as colunas. Já o formato .fwf tem a seguinte
estrutura
1 2 PAUL TERGAT (69) M2529 0:44:47
2 6 HENDRICK RAMAALA (72) M2529 0:45:05
3 4 ELIJAH KIPTARBEI LAGAT (98) M0014 0:45:08
4 7 SILVIO GUERRA (68) M3034 0:45:17
5 12 JOHN GWAKO (78) M2024 0:45:29
6 1 EMERSON ISER BEM (73) M2529 0:45:37
7 134 JOSE TELES DE SOUZA (71) M2529 0:45:56
8 25 GERALDO DE ASSIS (65) M3034 0:46:04
9 14 PATRICK NDAYISENGA (71) M2529 0:46:11

Este formato é um pouco mais complicado, uma vez que não tem um caracter delimitador
de colunas. As colunas são especificadas pelo número de caracteres. Assim, você precisará saber qual
o comprimento em número de caracteres de cada coluna. Por ser mais complicado é um formato
menos popular.

Em R a função read.table() oferece uma forma simples de importar a maioria dos formatos
de dados em texto pleno. Além desta função nativa existem pacotes especializados na leitura de dados,
tal como o readr.

O objetivo do readr é fornecer uma maneira rápida e amigável de ler dados retangulares.
Este pacote foi criado para lidar com os mais diversos tipos de dados encontrados na prática e dispõe
das funções read_csv(), read_tsv(), read_delim(), read_fwf(), read_table() e read_log(). Além
de serem funções bastante simples do ponto de vista do usuário, elas possuem um recurso interessante:
por meio de um argumento col_types é possível fornecer uma lista que informa já na leitura o tipo
da variável, o que poupa esforços na fase de tratamento dos dados para análise.

library(readr)
help(readr)

Para leitura é importante saber qual é o diretório dentro do computador onde o arquivo
de interesse está gravado. Neste livro leremos a base de dados direto de um endereço web. Porém,
se não for o seu caso, basta você especificar o caminho do seu arquivo no argumento file. Uma
recomendação é deixar a base de dados no mesmo diretório do seu arquivo .R. Assim, você pode
simplesmente fixar o diretório de trabalho como o diretório atual usando a função setwd() e ler o
arquivo apenas especificando o nome.

Para começar, vamos importar um arquivo no formato .txt que está no seguinte endereço:
http://leg.ufpr.br/~walmes/data/anovareg.txt. Você pode acessar este endereço e ver que o caracter

Ômega · Escola de Data Science omegadatascience.com.br


112 Capítulo 7. Lidando com dados com o tidyverse

separar neste exemplo é um tab. Por este motivo usaremos a função do readr destinada a conjuntos
de dados separados por tabulação: a read_tsv(). Ao abrir o txt nota-se que cada coluna tem um
nome, por isso o argumento col_names = TRUE deve ser usado. O Código 7.1 ilustra como importar
esta base de dados para o R.

Código 7.1. Importando um arquivo do tipo .txt usando a função read_tsv().

#url <- ”http://leg.ufpr.br/~walmes/data/anovareg.txt”


#dados <- read_tsv(url, col_names = TRUE)
#head(dados)

Vamos importar um outro conjunto de dados agora no formato .csv que está no seguinte
endereço web: http://leg.ufpr.br/~wagner/data/reglinear.csv. Novamente, você pode abrir o arquivo
em um editor de texto e ver que o caracter separador é um espaço em branco. Neste caso a função
readr para leitura é a read_table().

Código 7.2. Importando um arquivo do tipo .csv usando a função read_table().

#url <- ”http://leg.ufpr.br/~wagner/data/reglinear.csv”


#dados <- read_table(url, col_names = TRUE)
#head(dados)

Se a leitura foi executada com sucesso você não deve receber nenhuma mensagem. O erro
mais comum neste ponto é não especificar o caminho de diretórios corretamente, neste caso você vai
receber uma mensagem como esta

dados <- read_table(”reglinear.csv”, col_names = TRUE)

## Error: ’reglinear.csv’ does not exist in current working directory (’/home/wagner/gitprojects/RBASICO’).

O R está dizendo que não conseguiu encontrar o arquivo que você deseja ler no diretório
que ele está procurando. Lembre-se: para saber onde o R está trabalhando use o comando getwd().

Com a leitura bem sucedida, é hora de inspecionar o que foi carregado. Recomendamos usar
a função str() para ter uma visão geral do arquivo.

#str(dados)

A função str() começa mostrando quantas observações e quantas colunas a base de dados
contém. Neste caso temos 20 observações (linhas) e 2 variáveis (colunas). Na sequência é apresentado
o nome de cada coluna e o tipo de dado que ela representa.

7.2 Arrumando dados


Para analisar um conjunto de dados é importante que ele esteja arrumado, ou seja, cada coluna
deve ser uma variável e cada linha uma observação. Na maioria das situações práticas os dados não

Ômega · Escola de Data Science omegadatascience.com.br


7.2 113

estarão neste formato e você precisará trabalhar para deixá-lo desta forma. Um dos pacotes R mais
famosos para arrumação de dados é o tidyr.

library(tidyr)
help(tidyr)

Uma situação comum é quando os dados vêm em muitas colunas. Este caso ocorre muito
na tabulação de dados de experimentos nos quais se tem medidas realizadas ao longo do tempo. Por
exemplo,

n <- 3

tb1 <- data.frame(”trat” = LETTERS[1:n],


aval1 = rpois(n, 4),
aval2 = rpois(n, 4),
aval3 = rpois(n, 4))

tb1

## trat aval1 aval2 aval3


## 1 A 2 3 5
## 2 B 7 6 2
## 3 C 4 6 8

Neste caso temos que as observações da variável de interesse estão em três colunas. Além
disso, a variável avaliação, que deveria ser uma única coluna, está no título de três outras colunas.
Este é um exemplo típico de dados desorganizados que estão no formato amplo (wide). Nós queremos
transformá-los para o formato longo (long), de modo que cada variável esteja em uma coluna e cada
observação em uma linha.

Podemos realizar esta operação utilizando o pacote tidyr. Para o caso de empilhar colunas
temos a função pivot_longer().

library(magrittr)

tb1_long <- tb1 %>% pivot_longer(names_to = 'avaliação',


values_to = 'resposta',
cols = -trat)

tb1_long

## # A tibble: 9 x 3
## trat avaliação resposta
## <chr> <chr> <int>
## 1 A aval1 2
## 2 A aval2 3
## 3 A aval3 5
## 4 B aval1 7
## 5 B aval2 6
## 6 B aval3 2
## 7 C aval1 4
## 8 C aval2 6
## 9 C aval3 8

Ômega · Escola de Data Science omegadatascience.com.br


114 Capítulo 7. Lidando com dados com o tidyverse

A sintaxe é bastante simples:

▶ O argumento names_to nomeia a coluna que vai converter os nomes das colunas para um fator.

▶ O argumento values_to nomeia a coluna que vai receber os valores empilhados das colunas de
interesse.

▶ Por fim especificamos quais as colunas envolvidas na operação. Este argumento pode ser de-
clarado de formas diversas formas. Por exemplo, no lugar de -trat, bastaria utilizar alguma
destas opções: aval1:aval3, 2:4, c(aval1,aval2,aval3) ou ainda c(2,3,4). Note, basta es-
pecificar as colunas que desejamos empilhar por nome, posição ou apenas as colunas que não
estão envolvidas na operação.

Note que introduzimos um novo operador: o %>%, chamado de pipe. O objetivo do operador
é encaminhar um valor para uma expressão ou chamada de função. Neste caso, utilizamos o %>%
para dizer que na função pivot_longer() o objeto de interesse é o nosso data.frame tb1. É importante
ressaltar que dentro da função pivot_longer() podemos especificar diretamente o data.frame por meio
do argumento data, contudo o código fica mais organizado e elegante quando usamos o %>%.

Podemos também fazer a operação inversa, ou seja, desempilhar caso seja de interesse. Isso
pode ser feito com a função pivot_wider() do tidyr.

tb1_long %>% pivot_wider(names_from = 'avaliação',


values_from = 'resposta')

## # A tibble: 3 x 4
## trat aval1 aval2 aval3
## <chr> <int> <int> <int>
## 1 A 2 3 5
## 2 B 7 6 2
## 3 C 4 6 8

Outra operação que pode ser necessária é separar uma variável em várias outras. Isso é comum
quando um campo de texto é a união de várias informações. Considere o seguinte data.frame.

tb <- data.frame(veiculo = c(”Celta”, ”Gol”, ”Uno”),


ano_mod = c(”2011/2012”, ”2012/2012”, ”2015/2016”),
local = c(”Curitiba-PR”, ”Santos-SP”, ”Viçosa-MG”))

tb

## veiculo ano_mod local


## 1 Celta 2011/2012 Curitiba-PR
## 2 Gol 2012/2012 Santos-SP
## 3 Uno 2015/2016 Viçosa-MG

A coluna ano_mod é a mistura das variáveis ano do veículo e modelo do veículo. De forma
similar, a coluna local é a mistura de duas variáveis: município e unidade federativa (UF). Assim,
precisamos separar estas informações. Note que o caracter / é quem separa as informações na coluna
ano_mod enquanto que na coluna local o caracter - é o separador.

Ômega · Escola de Data Science omegadatascience.com.br


7.2 115

Uma alternativa simples e que exige poucos tratamentos para separação de variáveis é a função
separate() do pacote tidyr. Para esta função passamos como argumentos o data.frame, a coluna de
interesse, quais colunas novas serão criadas e qual o separador.

tb_nova1 <- tb %>% separate(col = ano_mod,


into = c('Ano', 'Modelo'),
sep = '/')

tb_nova1

## veiculo Ano Modelo local


## 1 Celta 2011 2012 Curitiba-PR
## 2 Gol 2012 2012 Santos-SP
## 3 Uno 2015 2016 Viçosa-MG

tb_nova2 <- tb_nova1 %>% separate(col = local,


into = c('Município', 'UF'),
sep = '-')

tb_nova2

## veiculo Ano Modelo Município UF


## 1 Celta 2011 2012 Curitiba PR
## 2 Gol 2012 2012 Santos SP
## 3 Uno 2015 2016 Viçosa MG

Da mesma forma que podemos separar variáveis que estão em uma mesma coluna pode ser
necessário criar novas variáveis unindo os valores de duas ou mais colunas. Por exemplo, suponha que
em um data.frame os campos dia, mês e ano estão cada um em uma coluna. Porém, você precisa de
apenas uma coluna que represente a data da observação. Assim, precisamos juntar essas três colunas
em uma nova.

tb <- data.frame(dia = c(1, 5, 23, 16),


mes = c(3, 6, 2, 9),
ano = 2018)

Esta tarefa pode ser realizada com a função unite() do pacote tidyr em que especifica-se o
data.frame, o nome da coluna que receberá a união das outras, o separador de interesse e quais colunas
serão unidas. Neste caso, com intuito de manter as variáveis originais acrescentamos o argumento
remove = FALSE.

tb <- tb %>% unite(col = 'data',


sep = '/',
c('dia', 'mes', 'ano'),
remove = FALSE)

tb

## data dia mes ano


## 1 1/3/2018 1 3 2018
## 2 5/6/2018 5 6 2018
## 3 23/2/2018 23 2 2018
## 4 16/9/2018 16 9 2018

Ômega · Escola de Data Science omegadatascience.com.br


116 Capítulo 7. Lidando com dados com o tidyverse

Podemos ainda converter esta coluna para o tipo data.

tb$data <- as.Date(tb$data, format = ”%d/%m/%Y”)


tb

## data dia mes ano


## 1 2018-03-01 1 3 2018
## 2 2018-06-05 5 6 2018
## 3 2018-02-23 23 2 2018
## 4 2018-09-16 16 9 2018

Por fim, teremos frequentemente que lidar com dados faltantes. Algumas vezes podemos
simplesmente querer remover todas as linhas que tenham algum NA. Outras vezes queremos preencher
com algum valor específico. O pacote tidyr dispõe de funções bastante úteis para tratamento de dados
ausentes. Veja o seguinte conjunto de dados

tb <- data.frame(jogador = 1:5,


jogos = c(0, 1, 3, 1, 2),
gols = c(NA, 0, 0, 2, 1),
faltas = c(NA, 1, 1, 0, 0))

Para excluir todas as linhas que contenham pelo menos um NA temos a função drop_na()

drop_na(tb)

## jogador jogos gols faltas


## 1 2 1 0 1
## 2 3 3 0 1
## 3 4 1 2 0
## 4 5 2 1 0

Para substituir os campos iguais a NA por algum valor o pacote tidyr dispõe da função
replace_na(). Esta função recebe como argumento o data.frame e uma lista com o nome da variável
no dataframe e que valor um dado ausente encontrado naquela variável deve assumir.

tb %>% replace_na(list(gols = 0,
faltas = 0))

## jogador jogos gols faltas


## 1 1 0 0 0
## 2 2 1 0 1
## 3 3 3 0 1
## 4 4 1 2 0
## 5 5 2 1 0

É importante salientar que tratar dados ausentes de forma estatisticamente coerente nem sem-
pre é uma tarefa fácil. Assim, pense muito bem o que os dados faltantes significam no contexto que
você está trabalhando e se faz sentido substituir por algum número ou mesmo excluir da base de
dados.

Ômega · Escola de Data Science omegadatascience.com.br


7.3 117

7.3 Manipulando dados

Uma vez que os dados estejam arrumados é a hora de começar a conhecê-los. Seguindo os
princípios do tidy data para manipular um conjunto de dados temos cinco ações essenciais:

▶ Ordenar observações de acordo com os seus valores.

▶ Selecionar variáveis de acordo com o seu nome e/ou características.

▶ Filtrar observações de acordo com os seus valores.

▶ Criar/transformar variáveis a partir de variáveis já existentes.

▶ Resumir ou sumarizar dados. Essa ação é a mais complexa e em geral envolve o uso de medidas
estatísticas como média, mediana, desvio-padrão entre outros para criar resumo dos dados.

Existem diversas alternativas em R para manipulação de dados. Uma delas é o pacote dplyr.

library(dplyr)
help(dplyr)

Para ilustrar o uso de cada uma das ações de manipulação vamos considerar os dados apresen-
tados na Figura 7.2.

Figura 7.2: Uma tabela com dados fictícios sobre alunos e seus desempenhos.

Podemos entrar com esses dados diretamente em R conforme abaixo.

Ômega · Escola de Data Science omegadatascience.com.br


118 Capítulo 7. Lidando com dados com o tidyverse

df1 <- data.frame(


matricula = c(256, 487, 965,
125, 458, 874, 963),
nome = c(”João”, ”Vanessa”, ”Tiago”,
”Luana”, ”Gisele”, ”Pedro”,
”André”),
curso = c(”Mat”, ”Mat”, ”Est”, ”Est”,
”Est”, ”Mat”, ”Est”),
prova1 = c(80, 75, 95, 70, 45, 55, 30),
prova2 = c(90, 75, 80, 85, 50, 75, NA),
prova3 = c(80, 75, 75, 50, NA, 90, 30),
faltas = c(4, 4, 0, 8, 16, 0, 20))

A ação mais simples é a de ordenação, ilustrada na Figura 7.3. A ordenação pode ser feita de
acordo com os valores de uma ou mais variáveis.

Figura 7.3: Ordenação dos registros de uma tabela.

Por exemplo, podemos ordenar os alunos pelo número de matrícula, como ilustrado na Fi-
gura 7.3 (linha 1). No dplyr a função destinada para ordenação é a arrange().

df1 %>% arrange(matricula)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 125 Luana Est 70 85 50 8
## 2 256 João Mat 80 90 80 4
## 3 458 Gisele Est 45 50 NA 16
## 4 487 Vanessa Mat 75 75 75 4
## 5 874 Pedro Mat 55 75 90 0
## 6 963 André Est 30 NA 30 20
## 7 965 Tiago Est 95 80 75 0

Ômega · Escola de Data Science omegadatascience.com.br


7.3 119

Note que a variável matrícula foi ordenada de forma crescente. Para ordenar de maneira
descrescente:

df1 %>% arrange(desc(matricula))

## matricula nome curso prova1 prova2 prova3 faltas


## 1 965 Tiago Est 95 80 75 0
## 2 963 André Est 30 NA 30 20
## 3 874 Pedro Mat 55 75 90 0
## 4 487 Vanessa Mat 75 75 75 4
## 5 458 Gisele Est 45 50 NA 16
## 6 256 João Mat 80 90 80 4
## 7 125 Luana Est 70 85 50 8

Podemos ordenar por duas ou mais colunas.

df1 %>% arrange(curso, prova1)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 963 André Est 30 NA 30 20
## 2 458 Gisele Est 45 50 NA 16
## 3 125 Luana Est 70 85 50 8
## 4 965 Tiago Est 95 80 75 0
## 5 874 Pedro Mat 55 75 90 0
## 6 487 Vanessa Mat 75 75 75 4
## 7 256 João Mat 80 90 80 4

A próxima ação é de seleção e pode ser feita de várias formas:

▶ Pelo nome das colunas.


▶ Pela posição das linhas ou das colunas.
▶ Condicional ao valor de uma ou mais variáveis.
▶ Por extremidades cabeça (head) e cauda (tail).

Suponha que temos interesse apenas nas colunas nome, curso e faltas. Podemos selecionar
as colunas pelos seus nomes. Utilizando a função select do dplyr, temos

df1 %>% select(c(”nome”, ”curso”, ”faltas”))

## nome curso faltas


## 1 João Mat 4
## 2 Vanessa Mat 4
## 3 Tiago Est 0
## 4 Luana Est 8
## 5 Gisele Est 16
## 6 Pedro Mat 0
## 7 André Est 20

Pelas posições das colunas.

df1 %>% select(c(2,3,7))

Ômega · Escola de Data Science omegadatascience.com.br


120 Capítulo 7. Lidando com dados com o tidyverse

## nome curso faltas


## 1 João Mat 4
## 2 Vanessa Mat 4
## 3 Tiago Est 0
## 4 Luana Est 8
## 5 Gisele Est 16
## 6 Pedro Mat 0
## 7 André Est 20

Podemos selecionar apenas os alunos com mais de dez faltas utilizando a função filter() do
dplyr.

df1 %>% filter(faltas > 10)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 458 Gisele Est 45 50 NA 16
## 2 963 André Est 30 NA 30 20

Podemos também selecionar pelo número das linhas usando a função slice() do dplyr.

df1 %>% slice(3:5)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 965 Tiago Est 95 80 75 0
## 2 125 Luana Est 70 85 50 8
## 3 458 Gisele Est 45 50 NA 16

Além disso podemos selecionar apenas as extremidades cabeça (head) ou cauda (tail).

# Cabeça
df1 %>% slice_head(n = 6)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 6 874 Pedro Mat 55 75 90 0

# Cauda
df1 %>% slice_tail(n = 6)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 487 Vanessa Mat 75 75 75 4
## 2 965 Tiago Est 95 80 75 0
## 3 125 Luana Est 70 85 50 8
## 4 458 Gisele Est 45 50 NA 16
## 5 874 Pedro Mat 55 75 90 0
## 6 963 André Est 30 NA 30 20

Entre as diversas ações possíveis, a de filtrar observações de acordo com suas características é
uma das mais importantes. Já vimos a função filter() do dplyr, que permite fazer filtros ou obter
subconjuntos que tenham características de interesse. Similar a ação de seleção, a ação de filtro pode

Ômega · Escola de Data Science omegadatascience.com.br


7.3 121

ser realizada por uma ou mais características. Por exemplo, podemos selecionar só os alunos do curso
de estatística.

df1 %>% filter(curso == ”Est”)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 965 Tiago Est 95 80 75 0
## 2 125 Luana Est 70 85 50 8
## 3 458 Gisele Est 45 50 NA 16
## 4 963 André Est 30 NA 30 20

Outro exemplo é selecionar alunos do curso de estatística e que a soma das notas das provas
1, 2 e 3 seja maior que 180.

df1 %>% filter(curso == ”Est” & (prova1 + prova2 + prova3) > 180)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 965 Tiago Est 95 80 75 0
## 2 125 Luana Est 70 85 50 8

Alunos que tenham alguma falta.

df1 %>% filter(faltas != 0)

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 125 Luana Est 70 85 50 8
## 4 458 Gisele Est 45 50 NA 16
## 5 963 André Est 30 NA 30 20

Pelo nome dos alunos.

df1 %>% filter(nome %in% c(”Aline”, ”Vanessa”))

## matricula nome curso prova1 prova2 prova3 faltas


## 1 487 Vanessa Mat 75 75 75 4

O operador %in% implica na seleção de qualquer um que se encaixar em c(”Aline”,


”Vanessa”). Como não temos nenhuma Aline, a saída retornou apenas a linha da aluna Vanessa.

As operações de criar/transformar nos permitem por exemplo renomear as colunas do con-


junto de dados. Veja a ilustração da Figura 7.4.

Para renomear as colunas de um data.frame basta atribuir novos nomes. Para esta tarefa o
dplyr possui a função rename().

df1 <- df1 %>% rename(mat. = 'matricula',


nome = 'nome',
curso = 'curso',
p1 = 'prova1',
p2 = 'prova2',
p3 = 'prova3',
fl = 'faltas')

Ômega · Escola de Data Science omegadatascience.com.br


122 Capítulo 7. Lidando com dados com o tidyverse

Figura 7.4: Formas de renomear as colunas de uma tabela.

Trocar a ordem das colunas para que as notas das provas apareçam primeiro pode ser feito
tanto pelo nome como pelos números associados às colunas.

df1[,c(4,5,6,1,2,3)]

## p1 p2 p3 mat. nome curso


## 1 80 90 80 256 João Mat
## 2 75 75 75 487 Vanessa Mat
## 3 95 80 75 965 Tiago Est
## 4 70 85 50 125 Luana Est
## 5 45 50 NA 458 Gisele Est
## 6 55 75 90 874 Pedro Mat
## 7 30 NA 30 963 André Est

A ação de transformação consiste em criar novas variáveis a partir das variáveis existentes. A
ideia é ilustrada na Figura 7.5.

Por exemplo, podemos calcular a média dos alunos. Para isso é possível utilizar a função
mutate() do dplyr

df1 %>% mutate(media = (p1 + p2 + p3)/3)

Ômega · Escola de Data Science omegadatascience.com.br


7.3 123

Figura 7.5: Criação e deleção de variáveis em uma tabela.

## mat. nome curso p1 p2 p3 fl media


## 1 256 João Mat 80 90 80 4 83.3
## 2 487 Vanessa Mat 75 75 75 4 75.0
## 3 965 Tiago Est 95 80 75 0 83.3
## 4 125 Luana Est 70 85 50 8 68.3
## 5 458 Gisele Est 45 50 NA 16 NA
## 6 874 Pedro Mat 55 75 90 0 73.3
## 7 963 André Est 30 NA 30 20 NA

Note que, onde os alunos não tem nota na prova, o cálculo da média resultou em NA. Vamos
supor que se o aluno não realizou a prova a nota dele será zero.

df1 <- df1 %>% replace_na(list(p1 = 0,


p2 = 0,
p3 = 0))

df1

## mat. nome curso p1 p2 p3 fl


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 0 16
## 6 874 Pedro Mat 55 75 90 0
## 7 963 André Est 30 0 30 20

Ômega · Escola de Data Science omegadatascience.com.br


124 Capítulo 7. Lidando com dados com o tidyverse

df1 <- df1 %>% mutate(media = (p1 + p2 + p3)/3)

df1

## mat. nome curso p1 p2 p3 fl media


## 1 256 João Mat 80 90 80 4 83.3
## 2 487 Vanessa Mat 75 75 75 4 75.0
## 3 965 Tiago Est 95 80 75 0 83.3
## 4 125 Luana Est 70 85 50 8 68.3
## 5 458 Gisele Est 45 50 0 16 31.7
## 6 874 Pedro Mat 55 75 90 0 73.3
## 7 963 André Est 30 0 30 20 20.0

Podemos criar uma coluna para verificar se o aluno está aprovado (média > 70), em exame
(40 < média < 70) ou reprovado (média < 40) usando a função cut() temos

breaks <- c(0, 40, 70, 100)

df1$condicao <- cut(df1$media,


breaks = breaks,
labels = c(”Reprovado”, ”Exame”, ”Aprovado”))
df1

## mat. nome curso p1 p2 p3 fl media condicao


## 1 256 João Mat 80 90 80 4 83.3 Aprovado
## 2 487 Vanessa Mat 75 75 75 4 75.0 Aprovado
## 3 965 Tiago Est 95 80 75 0 83.3 Aprovado
## 4 125 Luana Est 70 85 50 8 68.3 Exame
## 5 458 Gisele Est 45 50 0 16 31.7 Reprovado
## 6 874 Pedro Mat 55 75 90 0 73.3 Aprovado
## 7 963 André Est 30 0 30 20 20.0 Reprovado

A última ação que vamos discutir é a de resumo ou sumarização. Esta ação está muito ligada
com a ideia de dados no formato longo e amplo. No exemplo das notas dos alunos o conjunto de
dados está no formato amplo. Se desejarmos calcular a média de cada prova precisamos percorrer as
colunas prova1, prova2 e prova3 uma a uma calculando a média. Se os dados estiverem no formato
longo poderíamos mais facilmente usar a ideia de resumir uma variável condicional aos valores de
uma outra, neste caso: a prova. A Figura 7.6 ilustra como é o processo de tornar um conjunto de
dados do formato amplo para o longo ou empilhado.

Usando a função pivot_longer() podemos facilmente passar um conjunto de dados do for-


mato amplo para longo. Note que vamos remover as colunas mat., fl, media e condicao antes de
fazer a manipulação.

df1_temp <- df1 %>% select(-c(mat., fl, media, condicao))

df1_long <- df1_temp %>% pivot_longer(names_to = 'exame',


values_to = 'notas',
cols = -c(nome, curso))

df1_long

Ômega · Escola de Data Science omegadatascience.com.br


7.3 125

Figura 7.6: Modificação da disposição com empilhamento.

## # A tibble: 21 x 4
## nome curso exame notas
## <chr> <chr> <chr> <dbl>
## 1 João Mat p1 80
## 2 João Mat p2 90
## 3 João Mat p3 80
## 4 Vanessa Mat p1 75
## 5 Vanessa Mat p2 75
## 6 Vanessa Mat p3 75
## 7 Tiago Est p1 95
## 8 Tiago Est p2 80
## 9 Tiago Est p3 75
## 10 Luana Est p1 70
## # ... with 11 more rows

Agora suponha que queremos saber qual é a nota média por prova. Estamos fazendo um

Ômega · Escola de Data Science omegadatascience.com.br


126 Capítulo 7. Lidando com dados com o tidyverse

resumo da coluna notas porém de acordo com os valores da coluna exame. Informalmente, dizemos
que estamos agrupando pela coluna exame ou fazendo um group by por exame. Este resultado pode
ser obtido por meio da função summarise() do dplyr

df1_long %>%
group_by(exame) %>%
summarise(media = mean(notas))

## # A tibble: 3 x 2
## exame media
## <chr> <dbl>
## 1 p1 64.3
## 2 p2 65
## 3 p3 57.1

Podemos agrupar por mais de uma coluna. Por exemplo, a nota média de cada curso para
cada exame.

df1_long %>%
group_by(curso, exame) %>%
summarise(media = mean(notas))

## # A tibble: 6 x 3
## # Groups: curso [2]
## curso exame media
## <chr> <chr> <dbl>
## 1 Est p1 60
## 2 Est p2 53.8
## 3 Est p3 38.8
## 4 Mat p1 70
## 5 Mat p2 80
## 6 Mat p3 81.7

Outra opção é calcular mais do que uma medida resumo. No caso da função summarise()
basta acrescentar uma linha especificando que temos interesse em obter outra medida.

df1_long %>%
group_by(curso, exame) %>%
summarise(media = mean(notas),
sd = sd(notas))

## # A tibble: 6 x 4
## # Groups: curso [2]
## curso exame media sd
## <chr> <chr> <dbl> <dbl>
## 1 Est p1 60 28.6
## 2 Est p2 53.8 39.0
## 3 Est p3 38.8 31.7
## 4 Mat p1 70 13.2
## 5 Mat p2 80 8.66
## 6 Mat p3 81.7 7.64

Este tipo de tarefa é também chamada de split-apply-combine. A Figura 7.7 mostra em detalhes
o que foi realizado.

Ômega · Escola de Data Science omegadatascience.com.br


7.4 127

Figura 7.7: Agregação de uma tabela.

Primeiro nós dividimos (split) o conjunto de dados pelas variáveis curso e exame. Para cada
pedaço foram calculadas as medidas resumo (apply). Finalmente, combinamos os resultados em um
novo data.frame (combine).

7.4 Combinando dados


Em algumas situações pode ser necessário combinar diversos conjuntos de dados. A situação
mais comum é quando você já tem um conjunto de dados, como por exemplo o nosso df1, e um novo
conjunto de dados chega. Assim, precisamos combinar os dados que já temos com o novo. Suponha
que o novo conjunto de dados é o seguinte.

df2 <- data.frame(


matricula = c(505, 658, 713),
nome = c(”Bia”, ”Carlos”, ”Cris”),
curso = c(”Eng”, ”Eng”, ”Eng”),
prova1 = c(65, 75, 75),
prova2 = c(85, 80, 90),
faltas = c(0, 0, 2))

Ômega · Escola de Data Science omegadatascience.com.br


128 Capítulo 7. Lidando com dados com o tidyverse

Para combinar o novo conjunto de dados com o antigo a primeira coisa a fazer é deixá-los
compatíveis. Isso significa que devem ter os mesmos dados e as colunas devem ter os mesmos nomes.
Como fizemos diversos cálculos com o df1, vamos recriá-lo.

df1 <- data.frame(


matricula = c(256, 487, 965,
125, 458, 874, 963),
nome = c(”João”, ”Vanessa”, ”Tiago”,
”Luana”, ”Gisele”, ”Pedro”,
”André”),
curso = c(”Mat”, ”Mat”, ”Est”, ”Est”,
”Est”, ”Mat”, ”Est”),
prova1 = c(80, 75, 95, 70, 45, 55, 30),
prova2 = c(90, 75, 80, 85, 50, 75, NA),
prova3 = c(80, 75, 75, 50, NA, 90, 30),
faltas = c(4, 4, 0, 8, 16, 0, 20))

Note que no conjunto df2 não temos uma coluna chamada de prova3. Assim, primeiro
precisamos criar esta coluna.

df2$prova3 <- NA

Uma vez que os conjuntos de dados são compatíveis, podemos simplesmente concatenar suas
linhas usando a função rbind().

df <- rbind(df1, df2)


df

## matricula nome curso prova1 prova2 prova3 faltas


## 1 256 João Mat 80 90 80 4
## 2 487 Vanessa Mat 75 75 75 4
## 3 965 Tiago Est 95 80 75 0
## 4 125 Luana Est 70 85 50 8
## 5 458 Gisele Est 45 50 NA 16
## 6 874 Pedro Mat 55 75 90 0
## 7 963 André Est 30 NA 30 20
## 8 505 Bia Eng 65 85 NA 0
## 9 658 Carlos Eng 75 80 NA 0
## 10 713 Cris Eng 75 90 NA 2

Figura 7.8 ilustra a operação realizada.

Por fim, uma outra operação que aparece com frequência ao analisar dados é a de juntar/parear
duas tabelas que possuem uma chave primária. Essas operações são geralmente chamadas de junções
( join ) e existem diversas versões, as mais comuns são:

▶ Junção por interseção (inner join).


▶ Junção por união (full join).
▶ Junção à esquerda (left join).
▶ Junção à direita (right join).
▶ Existem também os chamados exclusive joins.

Ômega · Escola de Data Science omegadatascience.com.br


7.4 129

Figura 7.8: Concatenação de duas tabelas.

Cada uma destas versões são ilustradas na Figura 7.10.

Para praticarmos este tipo de operação considere o seguinte conjunto de dados.

df_extra <- data.frame(


”matricula” = c(256, 965, 285, 125, 874, 321, 669, 963),
”nome” = c(”João”, ”Tiago”, ”Tiago”, ”Luana”,
”Pedro”, ”Mia”, ”Luana”, ”André”),
”idade” = c(18, 18, 22, 21, 19, 18, 19, 20),
”bolsista” = c(”S”, ”N”, ”N”, ”S”, ”N”, ”N”, ”S”, ”N”))

O pacote dplyr() possui funções específicar para cada tipo de junção

# Left join
left_join(df1, df_extra, by = ”matricula”)

# Right join
right_join(df1, df_extra, by = ”matricula”)

# inner join
inner_join(df1, df_extra, by = ”matricula”)

# full join
full_join(df1, df_extra, by = ”matricula”)

A diferença entre os diferentes join é bastante simples:

▶ left join: mantém todos os registros da tabela a esquerda (df1) e completa com os corresponden-
tes na tabela da direita (df_extra).

▶ right join: mantém todos os registros da tabela da direita (df_extra) e completa com os dados
da tabela da esquerda (df1).

Ômega · Escola de Data Science omegadatascience.com.br


130 Capítulo 7. Lidando com dados com o tidyverse

Figura 7.9: Tipos de junções de tabelas ilustrado com diagramas de Veen.

▶ inner join: mantém apenas os registros que estão em ambas tabelas.

▶ full join: mantém todos os registros e preenche com NA onde não tem correspondência entre
as tabelas.

Figura 7.10 ilustra os diferentes tipos de join para um subconjunto dos dados das notas dos
alunos.

7.5 Exportando dados


Após realizar as análises é bastante provável que você precise exportar um conjunto de dados
organizado ou mesmo uma tabela com estatísticas. O R tem uma longa lista de funções para exportar
dados. Assim como leitura, o pacote readr dispõe de uma série de funções de escrita.

A forma mais comum é exportar um arquivo de texto pleno nos formatos .csv ou .txt. Para
esta tarefa as funções write_tsv() e write_csv() podem ser usadas. Podemos exportar o resultado da
junção das tabelas df1 e df_extra como o resultado final de nossa análise, conforme ilustra o Código
7.3.

Código 7.3. Exemplo de uso da função write_csv() para exportar arquivos de texto pleno.

Ômega · Escola de Data Science omegadatascience.com.br


7.5 131

Figura 7.10: Junções de tabelas do tipo inclusivas.

final <- inner_join(df1,


df_extra,
by = ”matricula”)

write_csv(final,
file = ”Nome_do_arquivo.csv”)

Os argumentos básicos são o data.frame que você quer salvar em disco e o nome desejado. A
maioria dos argumentos de escrita são iguais ou muito similares aos argumentos de leitura. Assim,
exportação de dados não gera mais complexidade e tudo que você já aprendeu para leitura se aplica
imediatamente.

Sem dúvida, exportar dados em texto pleno é muito fácil e simples. No entanto, existem
algumas desvantagens. A principal é que as classes das colunas podem ser perdidas ao ler novamente
o conjunto de dados em R. Por ser um texto pleno o arquivo não carrega metadados que foram criados
em R. Caso seja de interesse, é possível salvar o próprio objeto R que contém o seu data.frame usando
a função save().

save(final,
file = ”Nome_do_arquivo.RData”)

A principal vantagem é que tudo que você fez no objeto final será mantido. Outra vanta-
gem é que você pode salvar outros formatos de dados como listas, matrizes e arrays. Para carregar
novamente o data.frame você deve usar a função load().

load(”Nome_do_arquivo.RData”)

Caso você tenha um objeto mais complicado, como por exemplo uma série de listas, a função
dput() é uma opção interessante. Ela permite salvar um objeto R como um texto simples que pode
ser copiado e colado.

Ômega · Escola de Data Science omegadatascience.com.br


132 Capítulo 7. Lidando com dados com o tidyverse

dput(final)

É possível também escrever um arquivo com extensão .R que pode ser posteriormente carre-
gado no R.

dput(final,
file = ”Nome_do_arquivo.R”)

Para carregar os dados basta usar a função dget().

dget(”Nome_do_arquivo.R”)

Essa estratégia pode ser usada para múltiplos objetos usando a função dump().

dump(c(”final”, ”df1”),
file = ”Nome_do_arquivo.R”)

Que agora deve ser carregado em R usando a função source().

source(”Nome_do_arquivo.R”)

Um outro formato que o R exporta é o formato binário com a extensão .rda. As vantagens
deste formato são que ocupa pouco espaço em disco e preserva as propriedades do objeto R.

save(final,
file = ”Nome_do_arquivo.rda”)

Neste caso, podemos usar novamente a função load() para fazer a leitura em R.

Por fim, você pode salvar todos os objetos e instruções que você usou em sua sessão R usando
a função save.image().

Lembre-se: sempre que você não especificar o caminho de escrita explicitamente, o R vai
escrever no diretório de trabalho atual. Algumas funções úteis para você ter controle de onde o R está
escrevendo os arquivos são:

▶ file.info(): mostra o tamanho do arquivo, data de criação e outros detalhes do arquivo.


▶ dir(): mostra todos os arquivos presentes em um diretório.
▶ file.exists(): verifica se um arquivo já existe (TRUE) ou não (FALSE) no diretório de trabalho.
▶ getwd() e setwd(): verifica e altera o diretório de trabalho, respectivamente.

Neste Capítulo foram vistas as principais operações com dados tabulares. A esta altura, esta-
mos prontos para falar sobre análise descritiva e exploratória de dados.

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 8

Estatística descritiva e exploratória com


o R base

No Capítulo 6 foi apresentado como lidar com dados desde a sua importação, até arrumação,
manipulação e exportação usando os princípios do tidy data. No entanto, apenas ter os dados organi-
zados não significa ter informações sobre o problema de interesse. Para realmente tirar o melhor dos
nossos dados precisamos analisá-los usando métodos estatísticos apropriados.

A etapa elementar de qualquer análise estatística de dados é a chamada análise descritiva e


exploratória. O objetivo desta etapa é sintetizar e apresentar um conjunto de dados de forma fácil
de entender. Neste Capítulo serão apresentados os aspectos básicos da análise exploratória de dados
e como executá-los em R. É importante enfatizar que este livro não é sobre estatística descritiva, mas
sim sobre como realizar análises descritivas usando o software R. No entanto sempre que possível será
discutida a pertinência e o melhor uso das diversas técnicas.

A melhor forma de aprender a fazer uma análise descritiva é fazendo uma análise descri-
tiva. Neste Capítulo vamos explorar um conjunto de dados de uma área muito interessante cha-
mada de people analytics (análise de pessoas). Os dados são uma adaptação do conjunto de dados
Human Resources Data Set disponível na plataforma kaggle. As adaptações foram foitas para tor-
nar o conjunto de dados mais simples por meio da retirada de algumas variáveis e também da tra-
dução e adaptação dos dados para o contexto brasileiro. Os dados estão disponíveis no endereço
www.leg.ufpr.br/~wagner/data/people_analytics.csv. O caracterer delimitador é ; e podemos facil-
mente ler essa base de dados usando a função read.table().

dados <- read.table(”data/people_analytics.csv”, header = TRUE, sep = ”;”)


str(dados)

133
134 Capítulo 8. Estatística descritiva e exploratória com o R base

## ’data.frame’: 311 obs. of 14 variables:


## $ cod_colaborador : int 1 2 3 4 5 6 7 8 9 10 ...
## $ salario : int 62506 104437 64955 64991 50825 57568 95660 59365 47837 50178 ...
## $ posicao : chr ”Técnico de produção I” ”DBA senior” ”Técnico de produção II” ”Técnico de produ
## $ genero : chr ”masculino” ”masculino” ”feminino” ”feminino” ...
## $ estado_civil : chr ”solteiro” ”casado” ”casado” ”casado” ...
## $ departamento : chr ”producao” ”TI” ”producao” ”producao” ...
## $ forma_recrutamento: chr ”LinkedIn” ”Indeed” ”LinkedIn” ”Indeed” ...
## $ performance_score : chr ”excede” ”atende totalmente” ”atende totalmente” ”atende totalmente” ...
## $ engajamento : num 4.6 4.96 3.02 4.84 5 5 3.04 5 4.46 5 ...
## $ faltas : int 1 17 3 15 2 15 19 19 4 16 ...
## $ admissao : chr ”7/5/2011” ”3/30/2015” ”7/5/2011” ”1/7/2008” ...
## $ demissao : chr ”” ”6/16/2016” ”9/24/2012” ”” ...
## $ razao_demissao : chr ”ainda empregado” ”mudou de carreira” ”horário” ”ainda empregado” ...
## $ status : chr ”ativo” ”pediu demissão” ”pediu demissão” ”ativo” ...

O conjunto de dados corresponde a 311 observações de 14 variáveis. Ao começar a análise


é importante saber qual o conteúdo de cada variável. Fazer um dicionário é altamente recomendável
neste etapa. Lembre-se: pode ser que outra pessoa vá repetir sua análise no futuro e ter claro o que
cada variável significa é imprescindível. Um dicionário nada mais é do que uma lista com o nome de
cada variável e o que ela representa/significa. Por exemplo, para o conjunto de dados people analytics
o dicionário é o seguinte.

▶ cod_colaborador: código do colaborador. É apenas um número único para cada trabalhador.


Não existe interesse analítico para esta variável.

▶ salario: salário anual do colaborador em reais.

▶ posicao: nome do cargo que o colaborador ocupa.

▶ genero: gênero do colaborador.

▶ estado_civil: estado civil do colaborador.

▶ departamento: departamento no qual o colaborador atua.

▶ forma_recrutamento: forma pela qual o colaborador foi recrutado.

▶ performance_score: escore dado pelo recrutador que indica o grau de compatibilidade entre o
candidato e a vaga.

▶ engajamento: escore entre 1 e 5 para o engajamento do colaborador.

▶ faltas: número de faltas do colaborador no período que está na empresa.

▶ admissao: data de admissão do colaborador.

▶ demissao: data de demissão do colaborador. No caso do colaborador ainda estar empregado a


data está em branco.

▶ razao_demissao: razão pela qual o colaborador foi demitido. No caso de não ter sido demitido
é colocado como ainda empregado.

Ômega · Escola de Data Science omegadatascience.com.br


8.1 135

▶ status: situação do colaborar dentro da empresa.

8.1 Tipos de variáveis


Um bom primeiro passo para uma análise descritiva é identificar o tipo de cada uma das variá-
veis sendo analisadas. A Figura 8.1 resume os tipos de variáveis que lidamos em estatística descritiva.

Figura 8.1: Principais tipos de variáveis.

Podemos classificar variáveis como qualitativas e quantitativas. Como o nome já sugere,


variáveis qualitativas representam qualidades. Se a qualidade apresentar uma ordem natural entre seus
níveis, dizemos que temos uma variável qualitativa ordinal. Caso contrário, não existe uma ordem
e temos uma variável qualitativa nominal. Variáveis qualitativas são, em geral, nomes que damos
a níveis de uma variável, ou seja, tratam-se de rótulos. Por exemplo: gênero, estado civil, grau de
satisfação com o trabalho.

Por outro lado, variáveis quantitativas representam medidas numéricas. Se essas medidas
puderem assumir apenas um número finito ou contável de valores, dizemos que se trata de uma
variável quantitativa discreta. Se as medidas puderem assumir um número infinito de valores então
temos uma variável quantitativa contínua. Uma dica para diferenciar entre variáveis discretas e
contínuas é: se puder contar é discreta, se medir é contínua.

Olhando para o conjunto de dados people analytics podemos facilmente classificar cada uma
de suas variáveis usando as diretrizes apresentadas na Figura 8.1.

▶ Quantitativas: salario, engajamento e faltas.

Ômega · Escola de Data Science omegadatascience.com.br


136 Capítulo 8. Estatística descritiva e exploratória com o R base

▶ Quantitativas contínuas: salario e engajamento.

▶ Quantitativa discreta: faltas.

▶ Qualitativas: posicao, genero, estado_civil, departamento, forma_recrutamento,


performance_score, razao_demissao e status.

▶ Qualitativas nominais: posicao, genero, estado_civil, departamento, forma_recrutamento,


razao_demissao e status.

▶ Qualitativa ordinal: performance_score.

As variáveis referentes a datas (datas de admissão e demissão) não se encaixam perfeitamente


na classificação proposta mas também trazem informações relevantes para a análise. Por enquanto
vamos deixar as datas de lado e lidar apenas com as variáveis qualitativas e quantitativas. Considerando
a classificação das variáveis podemos proceder com as análises específicas para cada tipo de variável.

8.2 Análise univariada


Chamamos de análise univariada a descrição de cada uma das variáveis de forma indepen-
dente. Em termos de técnicas descritivas, basicamente usamos tabelas de frequência para variáveis
qualitativas e resumos numéricos como média, mediana, moda e desvio-padrão para variáveis quan-
titativas. Em termos de análises gráficas o gráfico de barras e suas variações são os mais indicados
para representar variáveis qualitativas. Já para variáveis quantitativas, o histograma e suas variações
são boas escolhas para representar as variáveis.

8.2.1 Variável qualitativa nominal


Conforme mencionado, para variáveis qualitativas nominais a melhor forma de resumir os
dados é por meio de uma tabela de frequência absoluta. Uma tabela de frequência se resume a nada
mais do que contar o número de ocorrências de cada opção (nível) da variável qualitativa e organizar
essas contagens em uma tabela que associa o nível da variável à quantas vezes o nível aparece. Em
R a função table() faz este trabalho. Como exemplo considere as variáveis gênero e estado civil,
conforme ilustrado no Código 8.1.

Código 8.1. Exemplo de tabelas de frequência absoluta.

# Tabela genero
table(dados$genero)

##
## feminino masculino
## 176 135

Ômega · Escola de Data Science omegadatascience.com.br


8.2 137

# Tabela estado civil


table(dados$estado_civil)

##
## casado divorciado separado solteiro viúvo
## 124 30 12 137 8

Podemos também apresentar as distribuições de frequência em termos relativos, ou seja, di-


vidimos cada frequência absoluta pelo total conforme ilustrado no Código 8.2. É comum multiplicar
a frequência relativa por cem para obter um percentual. O objetivo é apenas facilitar a interpretação.

Código 8.2. Exemplos de tabela com frequência relativa.

## Tabela frequencia relativa


prop.table(table(dados$departamento))*100

##
## administracao engenharia de software executivo
## 2.894 3.537 0.322
## producao TI vendas
## 67.203 16.077 9.968

##
prop.table(table(dados$forma_recrutamento))*100

##
## aplicação online careerbuilder google Indeed
## 0.322 7.395 15.756 27.974
## indicação LinkedIn outros vagas inclusivas
## 9.968 24.437 0.643 9.325
## website
## 4.180

Interpretando os resultados das tabelas, notamos que, em termos de departamento, a maioria


dos colaboradores trabalham no departamento de produção. A forma de recrutamento mais popular
é o site Indeed seguido pelo LinkedIn e Google.

Para representação gráfica, o mais indicado para variáveis qualitativas nominais é o gráfico
de barras e de setores. O gráfico de setores apesar de seu aspecto histórico não é recomendado por ser
de difícil interpretação. Em geral nossos olhos têm dificuldade em diferenciar o tamanho das fatias.
Vamos ilustrar o seu uso, porém sugerimos o uso cauteloso desta opção. Em R as funções barplot()
e pie() são as mais simples para obter os gráficos de barras e setores, conforme ilustrado no Código
8.3. O comando par(mfrow = c(1,2)) serve para particionar a janela gráfica em duas para que os
gráficos apareçam lado a lado, após o uso desta opção retornamos a partição da janela gráfica para a
configuração original com o comando par(mfrow = c(1,1)).

Código 8.3. Gráfico de barras e setor.

par(mfrow = c(1,2))
barplot(table(dados$estado_civil))
pie(table(dados$estado_civil))

Ômega · Escola de Data Science omegadatascience.com.br


138 Capítulo 8. Estatística descritiva e exploratória com o R base

casado
100

divorciado
80

separado viúvo
60
40

solteiro
20
0

casado separado viúvo

par(mfrow = c(1,1))

No caso de uma variável qualitativa com vários níveis, como o estado civil, é interessante
ordenar o gráfico do maior para o menor. Isso ajuda a identificar pontos extremos e estabelecer
comparações de forma mais rápida. Para isso, precisamos trocar a classe da variável estado_civil
para fator e dizer qual a ordem de seus níveis. O Código 8.4 ilustra este processo.

Código 8.4. Ordenando os níveis de uma variável qualitativa nominal.

tab_est_civil <- table(dados$estado_civil)


ordem <- order(tab_est_civil, decreasing = TRUE)
dados$estado_civil <- as.factor(dados$estado_civil)
dados$estado_civil <- factor(dados$estado_civil,
levels = levels(dados$estado_civil)[ordem])

Veja a ordem lógica das operações:

1. Construímos a tabela de frequência para saber qual será a ordem de apresentação.


2. Obtemos a ordem descrescente dos níveis da variável.
3. Transformamos a classe da variável estado_civil para factor.
4. Reordenamos os níveis (levels) da variável estado_civil seguindo a ordem obtida no passo 2.

Agora podemos plotar o gráfico de barras.

barplot(table(dados$estado_civil))

Ômega · Escola de Data Science omegadatascience.com.br


8.2 139

100
80
60
40
20
0

solteiro casado divorciado separado viúvo

Da mesma forma que as tabelas de frequência, o gráfico de barras pode ser feito usando a
frequência absoluta ou relativa.

par(mfrow = c(1,2))
barplot(table(dados$estado_civil), main = ”Freq. Absoluta”)
barplot(prop.table(table(dados$estado_civil)), main = ”Freq. Relativa”)

Freq. Absoluta Freq. Relativa


0.4
100

0.3
80

0.2
60
40

0.1
20

0.0
0

solteiro separado solteiro separado

8.2.2 Variável qualitativa ordinal


Existem casos em que variáveis qualitativas apresentam uma ordem natural, como é o caso
da variável performance_score. É recomendável apresentar a tabela de frequência, seja absoluta ou
relativa, respeitando a ordem natural da variável. Por exemplo,

Ômega · Escola de Data Science omegadatascience.com.br


140 Capítulo 8. Estatística descritiva e exploratória com o R base

table(dados$performance_score)

##
## atende totalmente excede insuficiente
## 243 37 13
## precisa melhorar
## 18

Se optarmos por apresentar a variável performance_score de forma ascendente, a ordem


natural seria: insuficiente, precisa melhorar, atende totalmente e excede. Para dizermos ao R que essa
variável é qualitativa e ordinal precisamos transformá-la para a classe factor e indicar a ordem que
queremos que seja apresentada. Veja o Código 8.5.

Código 8.5. Exemplo de como definir a ordem de uma variável qualitativa ordinal.

dados$performance_score <- factor(dados$performance_score,


levels = c(”insuficiente”,
”precisa melhorar”,
”atende totalmente”,
”excede”))
prop.table(table(dados$performance_score))*100

##
## insuficiente precisa melhorar atende totalmente
## 4.18 5.79 78.14
## excede
## 11.90

Neste caso também faz sentido incluir a chamada frequência acumulada que nada mais é
do que somar os percentuais até determinado nível da variável qualitativa. Por exemplo, se temos
interesse no percentual de colaborares que tem escore precisa melhorar ou menor precisamos somar
insuficiente e precisa melhorar. Para obter as frequências acumuladas usamos a função cumsum(),
conforme ilustrado no Código 8.6.

Código 8.6. Frequência acumulada.

cumsum(prop.table(table(dados$performance_score))*100)

## insuficiente precisa melhorar atende totalmente


## 4.18 9.97 88.10
## excede
## 100.00

Novamente o gráfico de barras e setores são os mais indicados para análise gráfica.

barplot(table(dados$performance_score))

Ômega · Escola de Data Science omegadatascience.com.br


8.2 141

200
150
100
50
0

insuficiente precisa melhorar excede

Neste caso, precisa ser avaliado se vale a pena mudar a ordem para que as classes mais fre-
quentes apareçam a esquerda do gráfico. Em geral é preferível manter a ordem natural da variável,
mas sempre existem exceções.

Outro aspecto a considerar é quando a variável tem muitos níveis. Por exemplo, a variá-
vel posicao tem 26 níveis. Ao fazer uma tabela com tantos níveis pode ser difícil de visualizar os
resultados.

table(dados$posicao)

Ômega · Escola de Data Science omegadatascience.com.br


142 Capítulo 8. Estatística descritiva e exploratória com o R base

##
## Administrador BD Analista de dados
## 5 8
## Arquiteto de dados Arquiteto de empreendimentos
## 2 1
## Assistente administrativo CEO
## 3 1
## CIO Contador
## 1 3
## Contador senior DBA senior
## 2 2
## Desenvolvedor BI Desenvolvedor BI senior
## 4 3
## Diretor BI Diretor de operações
## 1 1
## Diretor de TI Diretos de vendas
## 1 1
## Engenheiro de rede senior Engenheiro de redes
## 5 5
## Engenheiro de software Gerente de produção
## 10 14
## Gerente de serviços Gerente de TI
## 1 12
## Gerente de vendas Gerente engenheiro de software
## 30 1
## Técnico de produção I Técnico de produção II
## 137 57

Uma dica útil é tentar agrupar os níveis que tenham baixa ocorrência ou que façam sentido
serem agrupados. Por exemplo, poderíamos juntar os níveis Técnico de produção I e Técnico de
produção II, desde que faça sentido prático. Essa é uma decisão que deve ser tomada junto com o
time que vai usar suas análises. Outra opção seria agrupar Contador e Contador Senior. O importante
é que a forma de agrupar deve estar de acordo com os objetivos da análise e alinhada com toda a equipe
que vai se beneficiar dela.

8.2.3 Variável quantitativa discreta

A análise exploratória de variáveis quantitativas discretas com poucos valores é de certa forma
similar a análise de variáveis qualitativas ordinais. Assim, tabelas de frequência absoluta, relativa e
acumulada são ferramentas populares. Os gráficos de barras também são indicados. Em nosso exemplo
a única variável quantitativa discreta é o número de faltas. Podemos fazer uma tabela de frequência
absoluta, relativa e acumulada, conforme ilustra o Código 8.7.

Código 8.7. Tabelas de frequência variável quantitativa discreta.

Ômega · Escola de Data Science omegadatascience.com.br


8.2 143

# Frequencia absoluta
abs <- table(dados$faltas)

# Frequencia relativa
percentual <- prop.table(table(dados$faltas))*100

## Frequencia acumulada
acumulada <- cumsum(prop.table(table(dados$faltas)))

resultado <- data.frame(”Absoluta” = abs,


”Percentual” = percentual,
”Acumulada” = acumulada)

Apesar de ser possível, a tabela gerada ficou grande e de difícil interpretação, pois existem 20
valores distintos para a variável faltas. Nestes casos o mais indicado é tratar as variáveis quantitativas
discretas como quantitativas contínuas, conforme veremos na próxima subseção.

8.2.4 Variável quantitativa contínua


No caso de variáveis quantativas contínuas, fazer uma tabela de frequência é impraticável
pelo grande número de possíveis valores que a variável pode assumir. Assim, a estratégia é criar
faixas de valores e então construir as tabelas de frequência de forma similar ao realizado para variáveis
qualitativas ordinais.

Em R a função cut() é bastante útil para agrupar as observações em faixas. Criar as faixas
é um assunto que requer bastante cuidado. Se você estiver em alguma situação em que as classes
podem ser criadas de acordo com alguma regra de negócio ou mesmo conforme interesse da equipe,
é perfeitamente aceitável usar essa informação para criar as classes. Caso contrário existem algumas
técnicas estatísticas para ajudar com esta tarefa. O importante é ter em mente que essa deve ser uma
decisão pensada de acordo com o negócio que você está lidando.

Vamos supor que um interesse da equipe é comparar as faixas de renda dentro da empresa
com as da população de forma geral. Você consultou o site do IBGE e constatou que para pesquisas
populacionais o IBGE usa as seguintes faixas de renda para obter a classe social de uma pessoa.

Classe Renda

A R$ 20.900,01 ou mais
B R$ 10.450,01 até R$ 20.900,00
C R$ 4.180,01 até R$ 10.450,01
D R$ 2.090,01 até R$ 4.180,00
E até R$ 2.090,01

Podemos então usar a função cut() para criar as faixas de renda.

Ômega · Escola de Data Science omegadatascience.com.br


144 Capítulo 8. Estatística descritiva e exploratória com o R base

faixas <- c(0, 2090.01, 4180.01, 10450.01, 20900.01, Inf)

Note que não precisamos explicitamente seguir a tabela do IBGE, uma vez que podemos
usar intervalos abertos a direita. Isso significa que entre 0 e 2.090, 01 o valor exato 2.090, 01 não será
contado na primeira faixa e assim por diante. Outro aspecto para estar atento é que a classificação do
IBGE é baseada na renda mensal. Por outro lado, nossa base de dados reporta a renda anual. Assim,
vamos primeiro dividir a variável por 12 para ter a renda mensal média. Para definir um intervalo
aberto a direita usamos as opção right = FALSE.

dados$renda_mensal <- dados$salario/12


table(cut(dados$renda_mensal, breaks = faixas))

##
## (0,2.09e+03] (2.09e+03,4.18e+03] (4.18e+03,1.05e+04]
## 0 31 270
## (1.05e+04,2.09e+04] (2.09e+04,Inf]
## 10 0

Novamente, a tabela pode conter a frequência absoluta, relativa e acumulada. Em termos de


gráficos o mais indicado para variáveis quantitativas contínuas é o histograma. Um histograma nada
mais é do que uma representação gráfica da tabela de frequências. Para construção do histograma
podemos usar tanto frequências absolutas quanto relativas. A Figura 8.2 mostra como gerar um
histograma usando as frequências absolutas.

hist(dados$salario, main = ””,


xlab = ”Salário anual”, ylab = ”Frequência absoluta”)
80 100
Frequência absoluta

60
40
20
0

50000 100000 150000 200000 250000

Salário anual

Figura 8.2: Histograma para a variável salário anual.

Neste caso, as observações são agrupadas em faixas usando uma metodologia estatística cha-
mada de regra de Sturges, veja ?hist para detalhes.

Ômega · Escola de Data Science omegadatascience.com.br


8.2 145

Apesar do gráfico da Figura 8.2 ser popularmente chamado de histograma, técnicamente ele
é uma adaptação do histograma original. Note que, no eixo y, temos a representação das frequências
absolutas de cada faixa de valores. Contudo, na concepção original do histograma, o eixo y é usado
para representar o que chamamos de densidade, conforme ilustrado na Figura 8.3.

hist(dados$renda_mensal,
main = ””,
probability = TRUE,
xlab = ”Salário anual”,
ylab = ”Densidade”)
0.00030
0.00020
Densidade

0.00010
0.00000

5000 10000 15000 20000

Salário anual

Figura 8.3: Histograma para a variável salário anual com a densidade representada na eixo y.

A ideia da densidade consiste em pensar qual o valor deve ser colocado no eixo y para que
quando a área de cada retângulo for calculada seja obtida a frequência relativa. Assim, a densidade é
calculada da seguinte forma

limite superior − limite inferior


densidade = .
frequência relativa

Lembre-se que a área de um retângulo é calculada como o tamanho da base vezes a altura,
ou seja,

área = (limite superior − limite inferior) ∗ altura.

Como queremos que a área seja igual a frequência relativa, basta isolar a altura. Chamamos
esta altura de densidade. Para ilustrar, vamos usar como exemplo o cálculo da densidade para a variável
engajamento. O histograma é mostrado na Figura 8.4.

Ômega · Escola de Data Science omegadatascience.com.br


146 Capítulo 8. Estatística descritiva e exploratória com o R base

histograma <- hist(dados$engajamento,


prob = TRUE,
xlab = ”Engajamento”,
ylab = ”Densidade”)

Histogram of dados$engajamento
0.0 0.1 0.2 0.3 0.4 0.5 0.6
Densidade

1 2 3 4 5

Engajamento

Figura 8.4: Histograma variável engajamento.

histograma

## $breaks
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
##
## $counts
## [1] 2 6 11 8 37 46 98 103
##
## $density
## [1] 0.0129 0.0386 0.0707 0.0514 0.2379 0.2958 0.6302 0.6624
##
## $mids
## [1] 1.25 1.75 2.25 2.75 3.25 3.75 4.25 4.75
##
## $xname
## [1] ”dados$engajamento”
##
## $equidist
## [1] TRUE
##
## attr(,”class”)
## [1] ”histogram”

Ao analisar o conteúdo do objeto histograma vemos que temos as classes (breaks), a frequência
absoluta (counts) e as densidades (density). A classe modal (maior frequência) é a que vai de .5 até 5.
Para calcular a densidade desta classe:

Ômega · Escola de Data Science omegadatascience.com.br


8.2 147

1. Calculamos a amplitude da classe, ou seja, o limite superior (5) menos o limite inferior (4.5).
Logo, a amplitude é 5 − 4.5 = 0.5.
2. Calculamos a frequência relativa da classe. Neste caso 103/311 = 0.331.
3. Calculamos a densidade 0.331/0.5 = 0.662.

Note que ao calcular a área do último retângulo temos:

1. A base é 5 − 4.5 = 0.5.


2. A altura (densidade) é 0.662.
3. E a área é a base multipicada pela altura, 0.5 ∗ 0.662 = 0.331 que é a frequência relativa da classe
considerada.

Os cálculos são idênticos para as demais classes. Mas você deve estar se perguntando: por
que complicar o que estava fácil?

A ideia do histograma é fornecer a distribuição de probabilidade empírica de uma variável


aleatória. Isso se deve ao fato de que a área da soma de todos os retângulos que compõem o histograma
deve ser igual a 1. Se você não está familiarizado com conceitos básicos de variáveis aleatórias e
probabilidade recomendamos que avalie o nosso curso de Probabilidade e Estatística para Ciência de
Dados.

No contexto de variáveis quantitativas contínuas a distribuição de frequências por meio do


histograma fornece um resumo da distribuição das observações. Apesar de muito útil e visual pode ser
difícil comparar diversos histogramas em uma mesma análise. Por exemplo, suponha que desejamos
comparar o grau de engajamento dos colaboradores de acordo com o gênero. Esta é uma tarefa
simples, basta fazer um histograma para os colaboradores do gênero feminino e outro para o gênero
masculino, conforme ilustra a Figura 8.5.

par(mfrow = c(1,2))
hist(subset(dados$engajamento, dados$genero == ”feminino”),
main = ”Feminino”, xlab = ”Engajamento”,
ylab = ”Freq. Absoluta”)
hist(subset(dados$engajamento, dados$genero == ”masculino”),
main = ”Masculino”, xlab = ”Engajamento”,
ylab = ”Freq. Absoluta”)

Para variáveis com muitos níveis pode ficar difícil avaliar tantos histogramas. Além disso, os
histogramas podem ter comportamentos parecidos, o que torna difícil encontrar diferenças apenas
visualmente. A estatística nos proporciona um conjunto de medidas numéricas para resumir a distri-
buição de frequências. Em geral olhamos para dois aspectos básicos da distribuição de frequência: a
sua tendência central e sua dispersão ou espalhamento.

As medidas de tendência central ou também chamadas de medidas de posição central mais


populares são a média aritmética, a mediana e a moda. A obtenção destas estatísticas é muito simples:

▶ Média aritmética: para uma variável quantitativa basta somar todos os seus valores e dividir
pelo número de observações. A interpretação física é que a média é o centro de gravidade da

Ômega · Escola de Data Science omegadatascience.com.br


148 Capítulo 8. Estatística descritiva e exploratória com o R base

60 Feminino Masculino

40
50
Freq. Absoluta

Freq. Absoluta

30
40
30

20
20

10
10
0

0
2.0 3.0 4.0 5.0 1 2 3 4 5

Engajamento Engajamento

Figura 8.5: Histograma para os gêneros feminino e masculino.

distribuição empírica. Pense que cada um dos retângulos é uma massa com peso igual a sua
densidade. Imagine que o eixo x é uma régua. O ponto médio é onde você deve colocar uma
agulha para perfeitamente equilibrar as massas sobre a régua.

▶ Mediana: ordene as observações de acordo com os valores de uma variável quantitativa do


menor para o maior. A mediana é o valor que estiver na posição i) (N + 1)/2 se N é ímpar e a
média dos valores das posições (N/2) e (N/2)+1 se N par. A ideia é saber exatamente que 50%
das observações tem valores menores do que a mediana. Óbviamente, 50% das observações tem
valores maiores do que a mediana.

▶ Moda: valor mais frequente. No caso de uma variável onde praticamente só existem valores
únicos, essa medida tem pouca aplicação prática. Você pode reportar a classe modal se for de
interesse. Em geral, a média e a mediana costumam ser suficientes para ter um boa noção da
centralidade da distribuição empírica.

Neste livro não vamos dar ênfase as formulas de como obter tais estatísticas. Nosso objetivo é
mostrar como obtê-las usando o R. Para a variável renda_mensal podemos facilmente calcular a média
e a mediana, conforme ilustra o Código 8.8.

Código 8.8. Medidas de tendência central.

Ômega · Escola de Data Science omegadatascience.com.br


8.2 149

# Média
mean(dados$renda_mensal)

## [1] 5752

# Mediana
median(dados$renda_mensal)

## [1] 5234

A mediana divide o conjunto de observações em dois grupos com o mesmo número de


observações. Porém, podemos pensar em dividir o conjunto de dados em mais partes. Essa ideia
dá origem aos chamados quartis. Os quartis são os valores da variável que dividem as observações
em quatro grupos de mesmo tamanho. Chamamos de primeiro quartil o valor que separa 1/4 dos
valores à sua esquerda e 3/4 à direita; o segundo quartil é a própria mediana e o terceiro quartil é o
valor que tem 3/4 dos valores da distribuição à sua esquerda e 1/4 à direita. Em R a função quantile()
calcula os quartis, conforme ilustra o Código 8.9.

Código 8.9. Cálculo dos quantis.

quantile(dados$renda_mensal)

## 0% 25% 50% 75% 100%


## 3754 4625 5234 6003 20833

Além dos quartis, a função quantile() apresenta os valores mínimos e máximos. Juntos, esses
valores são o chamado resumo de cinco números. É muito comum apresentar o resumo dos cinco
números em um diagrama de caixas ou boxplot, conforme ilustrado na Figura 8.6.

boxplot(dados$renda_mensal)
20000
15000
10000
5000

Figura 8.6: Boxplot para a variável renda mensal.

Analisando o gráfico da Figura 8.6 de baixo para cima, temos:

Ômega · Escola de Data Science omegadatascience.com.br


150 Capítulo 8. Estatística descritiva e exploratória com o R base

▶ A primeira linha horizontal representa o valor mínimo, sem considerar os valores que ultrapas-
sam o desvio interquartílico.
▶ A segunda linha horizontal representa o primeiro quartil.
▶ A linha mais grossa no meio da caixa representa a mediana.
▶ A terceira linha horizontal representa o terceiro quartil.
▶ A última linha horizontal representa o valor máximo, sem considerar os valores que ultrapassam
o desvio interquartílico.

O desvio interquartílico é definido como 1.5 vezes o terceiro quartil menos o primeiro quartil.
É um valor de referência e cria a chamada barreira de valores atípicos. Muitos analistas chamam os
valores além do desvio interquartilico de outliers. Porém, isso não é verdade e a definição exata do
que é um outliers depende de outros aspectos como do modelo que será ajustado. Neste livro não
vamos entrar neste tipo de detalhe. Tenha em mente de que estamos apenas na parte inicial da análise
e a detecção de outliers é uma das etapas finais da modelagem estatística e portanto além dos objetivos
deste livro.

O desvio interquartílico é uma medida de dispersão ou espalhamento da distribuição de


frequências. Existem diversas outras medidas de dispersão, por exemplo:

▶ Amplitude total: diferença entre o maior e menor valor.


▶ Variância: soma dos quadrados dos desvios (diferença entre a observação e a média) dividido
pelo tamanho da amostra menos 1. Em notação matemática, sendo yi os valores da variável e
ȳ a sua média aritmética a variância é dada por
∑n
2 i=1 (yi− ȳ)
s = .
n−1

▶ Desvio-padrão: raiz quadrada positiva da variância. A grande vantagem do desvio-padrão é


que está na mesma escala da variável, sendo de mais fácil interpretação.
▶ Coeficiente de variação: É a relação entre o desvio-padrão e a média. É geralmente expresso
em percentagem, o que facilita a comparação de variabilidade entre variáveis com valores em
unidades diferentes.

Em R é fácil obter todas essas medidas, conforme ilustra o Código 8.10.

Código 8.10. Medidas de dispersão.

amplitude <- max(dados$renda_mensal) - min(dados$renda_mensal)


amplitude

## [1] 17080

# Variância
var(dados$renda_mensal)

## [1] 4394836

Ômega · Escola de Data Science omegadatascience.com.br


8.3 151

# Desvio-padrão
sd(dados$renda_mensal)

## [1] 2096

## Coeficiente de variação
(sd(dados$renda_mensal)/mean(dados$renda_mensal))*100

## [1] 36.4

Existem diversas outras medidas resumo tanto de tendência central quanto de dispersão. Para
mais detalhes considere o curso Probabilidade e Estatística para Ciência de dados e a bibliografia
complementar ao final deste livro.

A vantagem de usar essas medidas resumo é mais facilmente poder comparar diferentes grupos
com relação a tendência central e/ou variabilidade. Por exemplo, podemos estar interessados em
comparar o salário médio dos colaboradores de acordo com o departamento em que trabalham. Já
vimos que a função aggregate() é especialmente útil para este tipo de resumo.

aggregate(x = dados$renda_mensal,
by = list(dados$departamento),
FUN = mean)

## Group.1 x
## 1 administracao 5983
## 2 engenharia de software 7916
## 3 executivo 20833
## 4 producao 4996
## 5 TI 8089
## 6 vendas 5755

Note que agora estamos usando uma variável para condicionar o comportamento de outra.
Isso é o que chamamos de análise descritiva bivariada e será o assunto da próxima subseção.

8.3 Análise bivariada


O principal objetivo da análise univariada é resumir o comportamento de uma variável de
tal modo que o comportamento desta variável se torne mais simples de se entender. Porém, o grande
valor da maioria das análises de dados está em entender e identificar relações entre diferentes variáveis.
Assim, o objetivo da análise bivariada é descrever e mensurar relações entre variáveis. O tipo de
resumo vai depender do tipo das variáveis sendo consideradas. Neste contexto temos as seguintes
possibilidades:

▶ Qualitativa × qualitativa;
▶ Qualitativa × quantitativa;
▶ Quantitativa × quantitativa.

Ômega · Escola de Data Science omegadatascience.com.br


152 Capítulo 8. Estatística descritiva e exploratória com o R base

Novamente, temos gráficos e medidas numéricas para resumir a relação entre as variáveis.
Nesta seção vamos ver apenas as medidas e gráficos mais populares. Para mais detalhes considere o
curso Manipulação e visualização com o R e as referências no final deste livro.

8.3.1 Qualitativa × qualitativa


A forma mais simples de representar a relação entre duas variáveis qualitativas é por meio de
uma tabela de dupla entrada. Considere as variáveis genero e forma_recrutamento. Nosso interesse
pode ser saber se uma determinada forma de recrutamento difere da outra em relação ao gênero dos
colaboradores. O Código 8.11 ilustra a criação de uma tabela de dupla entrada em R.

Código 8.11. Tabela de dupla entrada.

table(dados$forma_recrutamento, dados$genero)

##
## feminino masculino
## aplicação online 0 1
## careerbuilder 16 7
## google 33 16
## Indeed 50 37
## indicação 11 20
## LinkedIn 44 32
## outros 1 1
## vagas inclusivas 15 14
## website 6 7

Para economizar um pouco na digitação dos comandos podemos usar a função with().

with(dados, table(forma_recrutamento, genero))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0 1
## careerbuilder 16 7
## google 33 16
## Indeed 50 37
## indicação 11 20
## LinkedIn 44 32
## outros 1 1
## vagas inclusivas 15 14
## website 6 7

Novamente podemos calcular as frequências relativas, no entanto precisamos tomar cuidado


porque nas tabelas de dupla entrada temos várias opções, podemos obter frequências relativas em
relação:

▶ Ao total geral, ou seja, número total de observações.


▶ Aos totais das linhas (margin = 1).
▶ Aos totais das colunas (margin = 2).

Ômega · Escola de Data Science omegadatascience.com.br


8.3 153

A função prop.table() continua sendo a nossa escolha, conforme ilustra o Código 8.12.

Código 8.12. Tabela de dupla entrada com frequências relativas.

# Relação ao total geral


with(dados, prop.table(table(forma_recrutamento, genero)))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.00000 0.00322
## careerbuilder 0.05145 0.02251
## google 0.10611 0.05145
## Indeed 0.16077 0.11897
## indicação 0.03537 0.06431
## LinkedIn 0.14148 0.10289
## outros 0.00322 0.00322
## vagas inclusivas 0.04823 0.04502
## website 0.01929 0.02251

# Relação aos totais das linhas


with(dados, prop.table(table(forma_recrutamento, genero), margin = 1))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.000 1.000
## careerbuilder 0.696 0.304
## google 0.673 0.327
## Indeed 0.575 0.425
## indicação 0.355 0.645
## LinkedIn 0.579 0.421
## outros 0.500 0.500
## vagas inclusivas 0.517 0.483
## website 0.462 0.538

# Relação aos totais das colunas


with(dados, prop.table(table(forma_recrutamento, genero), margin = 2))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.00000 0.00741
## careerbuilder 0.09091 0.05185
## google 0.18750 0.11852
## Indeed 0.28409 0.27407
## indicação 0.06250 0.14815
## LinkedIn 0.25000 0.23704
## outros 0.00568 0.00741
## vagas inclusivas 0.08523 0.10370
## website 0.03409 0.05185

As vezes pode ser de interesse adicionar o total das linhas e colunas para facilitar a interpreta-
ção. A função addmargins() cumpre esse papel, conforme ilustra o Código 8.13.

Código 8.13. Adiciona os totais marginais (linhas e colunas).

tab <- with(dados, prop.table(table(forma_recrutamento, genero)))


addmargins(tab)

Ômega · Escola de Data Science omegadatascience.com.br


154 Capítulo 8. Estatística descritiva e exploratória com o R base

## genero
## forma_recrutamento feminino masculino Sum
## aplicação online 0.00000 0.00322 0.00322
## careerbuilder 0.05145 0.02251 0.07395
## google 0.10611 0.05145 0.15756
## Indeed 0.16077 0.11897 0.27974
## indicação 0.03537 0.06431 0.09968
## LinkedIn 0.14148 0.10289 0.24437
## outros 0.00322 0.00322 0.00643
## vagas inclusivas 0.04823 0.04502 0.09325
## website 0.01929 0.02251 0.04180
## Sum 0.56592 0.43408 1.00000

Em termos de análise gráfica, o gráfico de barras continua sendo a melhor escolha. No


entanto, agora precisamos representar duas barras e portanto existem diversas formas de representação.

Se o objetivo é enfatizar a composição de cada grupo podemos usar barras empilhadas. Em


geral, mantemos fixa a variável que temos mais interesse e colorimos as barras de acordo com os
valores da outra variável. Veja os exemplos da Figura 8.7.

idx <- order(table(dados$forma_recrutamento), decreasing = TRUE)


dados$forma_recrutamento <- as.factor(dados$forma_recrutamento)
dados$forma_recrutamento <- factor(dados$forma_recrutamento,
levels = levels(dados$forma_recrutamento)[idx])
par(mfrow = c(1,2))
recru_gen <- with(dados, table(genero, forma_recrutamento))
barplot(recru_gen, legend = TRUE, main = ”A”)

status_gen <- with(dados, prop.table(table(status, genero), margin = 2))


barplot(status_gen, legend = TRUE, ylim = c(0, 1.5), main = ”B”)

Na Figura 8.7(A) enfatizamos a variável que representa a forma de recrutamento e por isso é
ela quem aparece formando as barras. A variável gênero tem um papel apenas complementar. Note
que a comparação em termos de composição por gênero deve ser feita dentro de cada coluna, uma
vez que a comparação entre colunas é difícil por não terem a mesma altura.

Por outro lado, na Figura 8.7(B), enfatizamos a composição de cada nível da variável gênero
de acordo com a variável status. Como as barras apresentam a frequência relativa, podemos comparar
as frequências não só dentro de cada barra mas também entre as barras.

Quando o objetivo for comparar os níveis de uma variável de acordo com os níveis de uma
outra variável podemos usar as barras lado a lado, conforme ilustra a Figura 8.8.

tab <- with(dados, prop.table(table(performance_score, status), margin = 2))


barplot(tab, beside = TRUE, legend = TRUE)

Por fim, em casos em que o número de níveis da variável é grande podemos apresentar as
barras na horizontal. A Figura 8.9 ilustra esta opção.

Ômega · Escola de Data Science omegadatascience.com.br


8.3 155

A B
80

masculino pediu demissão

1.2
feminino justa causa
ativo
60

0.8
40

0.4
20

0.0
0

Indeed careerbuilder feminino masculino


Figura 8.7: Exemplos de gráficos com barras empilhadas.

tab <- with(dados, table(forma_recrutamento))


par(mai=c(1,2,1,1))
barplot(tab, main =””, horiz=TRUE, las = 1)

É importante também apresentar os nomes dos níveis da variável na horizontal. Esse é o papel
do argumento las = 1. No entanto ao fazer isso é provável que o texto fique fora das margens do
gráfico. Para corrigir esse problema usamos os parâmetros par(mai=c(1,2,1,1)).

8.3.2 Qualitativa × quantitativa


Quando temos uma variável qualitativa e outra contínua a ideia geral da análise é usar o
que vimos na subseção 7.2.4, porém para cada nível da variável qualitativa. Por exemplo, podemos
comparar o salário médio dos colaboradores de acordo com o departamento em que eles trabalham.
Nós já vimos que para este tipo de tarefa a função aggregate() atende ao propósito. O Código 8.14
ilustra como calcular não apenas a média mas também a mediana e o desvio-padrão da renda mensal
por nível da variável departamento.

Código 8.14. Calculando a média, mediana e desvio-padrão da renda mensal por departamento.

Ômega · Escola de Data Science omegadatascience.com.br


156 Capítulo 8. Estatística descritiva e exploratória com o R base

0.8 insuficiente
precisa melhorar
0.6

atende totalmente
excede
0.4
0.2
0.0

ativo justa causa pediu demissão

Figura 8.8: Exemplos de gráficos com barras lado a lado.

aggregate(x = dados$renda_mensal,
by = list(dados$departamento),
FUN = function(x) {
c(”media” = mean(x),
”mediana” = median(x),
”sd” = sd(x))
})

## Group.1 x.media x.mediana x.sd


## 1 administracao 5983 5250 1809
## 2 engenharia de software 7916 7972 797
## 3 executivo 20833 20833 NA
## 4 producao 4996 4956 952
## 5 TI 8089 7694 2767
## 6 vendas 5755 5442 1773

Tente entender o porquê o desvio-padrão da renda mensal na classe executivo retornou como
NA.

Recomendamos usar o boxplot da variável quantitativa por nível da variável qualitativa para
análise gráfica, conforme ilustrado na Figura 8.10.

with(dados, boxplot(renda_mensal ~ forma_recrutamento,


ylab = ”Renda mensal”, xlab = ”Forma de recrutamento”))

Para melhorar a visualização você pode ordenar as caixas de acordo com a renda mediana
conforme Figura 8.11.

Ômega · Escola de Data Science omegadatascience.com.br


8.3 157

aplicação online
outros
website
careerbuilder
vagas inclusivas
indicação
google
LinkedIn
Indeed

0 20 40 60 80
Figura 8.9: Exemplo de gráfico com barras horizontais.

mediana <- aggregate(x = dados$renda_mensal,


by = list(dados$forma_recrutamento),
FUN = median)
idx <- order(mediana$x, decreasing = TRUE)
dados$forma_recrutamento <- as.factor(dados$forma_recrutamento)
dados$forma_recrutamento <- factor(dados$forma_recrutamento,
levels = levels(dados$forma_recrutamento)[idx])
with(dados, boxplot(renda_mensal ~ forma_recrutamento,
ylab = ”Renda mensal”, xlab = ”Forma de recrutamento”))

Uma outra opção é criar faixas para a variável quantitativa e usar gráficos de barras como na
subseção 7.3.1.

8.3.3 Quantitativa × quantitativa


O gráfico mais popular para visualizar a relação entre duas variáveis quantitativas é o dia-
grama de dispersão, conforme mostra a Figura 8.12 para as variáveis renda mensal e engajamento.

with(dados, plot(renda_mensal ~ engajamento,


ylab = ”Renda mensal”, xlab = ”Engajamento”))

Em geral o que buscamos ao analisar um diagrama de dispersão como o apresentado na Figura


8.12 é identificar algum tipo de padrão de relacionamento. Para interpretar um diagrama de dispersão,
tenha a Figura 8.13 como referência.

Olhando para o diagrama de dispersão da Figura 8.12 tente imaginar uma linha descrevendo
a relação entre as variáveis renda mensal e engajamento. Se a linha que você imaginar for conforme a
da Figura 8.13(A) significa que visualmente as duas variáveis não estão associadas ou tem uma relação

Ômega · Escola de Data Science omegadatascience.com.br


158 Capítulo 8. Estatística descritiva e exploratória com o R base

20000
15000
Renda mensal

10000
5000

Indeed google vagas inclusivas website aplicação online

Forma de recrutamento

Figura 8.10: Boxplot da variável renda mensal por níveis da variável forma de recrutamento.

fraca. Por outro lado, se a linha estiver como na Figura 8.13(B) indica que as duas variáveis estão
positivamente associadas, ou seja, ao aumentar o valor de uma a outra também aumenta. Contudo,
se a linha for como na Figura 8.13(C) indica que a relação é negativa, ou seja, ao aumentar uma das
variáveis a outra diminui.

Para o nosso exemplo vemos uma leve tendência de relação positiva entre engajamento e
renda mensal. Porém a variabilidade (dispersão dos pontos) é bem alta e parece depender dos valores
da variável renda mensal.

Como você pode notar, interpretar um gráfico como o diagrama de dispersão é uma ativi-
dade bastante subjetiva. Existem algumas medidas numéricas que buscam resumir a relação linear
entre duas variáveis quantitativas, são os chamados coeficientes de correlação. Em geral usamos três
coeficientes de correlação: Pearson, Spearman e Kendal. Os três variam entre -1 e 1, sendo que −1
indica correlação perfeita negativa, todos os pontos caem exatamente em cima de uma reta como
da Figura 8.13(C). Uma correlação igual a 1 indica correlação positiva perfeita e neste caso todos os
pontos estariam em cima de uma reta como a apresentada na Figura 8.13(B). Se o valor da correlação
for zero não temos relação entre as variáveis e todos os pontos estariam em cima de uma reta como a
apresentada na Figura 8.13(A).

Na prática, esses valores são apenas referências e o que é considerada uma correlação forte
ou fraca vai depender do contexto. Além disso, um erro comum é dizer que se duas variáveis tem
correlação igual a zero elas são independentes. Essa afirmação em geral é falsa. O conceito de in-
dependência estatística requer a suposição de uma distribuição conjunta de probabilidades e não é

Ômega · Escola de Data Science omegadatascience.com.br


8.3 159

20000
15000
Renda mensal

10000
5000

outros Indeed careerbuilder website aplicação online

Forma de recrutamento

Figura 8.11: Boxplot com caixas ordenadas.

facilmente definido para qualquer distribuição a parte da distribuição normal bivariada. Conceitos de
Teoria das Probabilidades estão além do escopo deste livro. Para referência consulte a bibliografia
no final deste livro.

Por fim, sempre que temos mais do que uma opção, a pergunta natural é “qual é o melhor
coeficiente de correlação?”. Apesar de uma pergunta razoável, a resposta depende da situação e, em
geral, o melhor é calcular dois ou três deles e comparar os resultados. O coeficiente de correlação de
Pearson é o estimador de máxima verossimilhança do parâmetro de correlação de uma distribuição
normal bivariada. Neste contexto, se a distribuição conjunta for uma normal bivariada ele seria o
indicado. Porém, na prática não sabemos qual é a verdadeira distribuição conjunta das variáveis
envolvidas na análise. Uma boa indicação é que a distribuição de frequência empírica de cada variável
é aproximadamente simétrica. Novamente é um critério subjetivo e difícil de se verificar em termos
práticos. Porém, nesta etapa de análise exploratória onde não temos nenhuma suposição distribucional
o coeficiente de correlação de Pearson é uma boa indicação da correlação linear entre as variáveis.

O coeficiente de correlação de Spearman é parecido com o de Pearson porém, ao invés de


usar os valores das variáveis, usa apenas o seu ranking. Isso torna esse coeficiente mais robusto a va-
lores extremos. Já o coeficiente de Kendall é uma medida da dependência entre as duas observações
e, como o de Spearman, é baseado no ranking das variáveis. Os coeficientes de Spearman e Kendall
são chamados de não paramétricos justamente porque não são derivados de nenhuma distribuição de
probabilidade. Em termos práticos eles capturam a força da relação monotônica entre duas variáveis.
Uma recomendação geral é que se o tamanho da amostra é pequena o coeficiente de Kendall é indi-
cado por ser mais eficiente (menor incerteza). Para amostras grandes e distribuições razoavelmente

Ômega · Escola de Data Science omegadatascience.com.br


160 Capítulo 8. Estatística descritiva e exploratória com o R base

20000
15000
Renda mensal

10000
5000

1 2 3 4 5

Engajamento

Figura 8.12: Diagrama de dispersão: renda mensal e engajamento.

(A) (B) (C)


14

40

40
12

20

20
f (x)

f (x)

f (x)
10

0
8

-20

-20
6

-10 -5 0 5 10 -10 -5 0 5 10 -10 -5 0 5 10


x x x

Figura 8.13: Exemplos de forma de relação entre variáveis quantitativas.

simétricas use o de Pearson. Caso contrário use Spearman. É importante ressaltar que essas são re-
comendações práticas para o caso em que o interesse seja obter apenas um. Na prática você pode
facilmente calcular os três, conforme ilustrado no Código 8.15.

Código 8.15. Calculando os coeficientes de correlação de Pearson, Spearman e Kendall.

# Pearson
with(dados, cor(renda_mensal, engajamento, method = ”pearson”))

## [1] 0.065

# Spearman
with(dados, cor(renda_mensal, engajamento, method = ”spearman”))

Ômega · Escola de Data Science omegadatascience.com.br


8.3 161

## [1] 0.0311

# Kendall
with(dados, cor(renda_mensal, engajamento, method = ”kendall”))

## [1] 0.0214

Conforme a Figura 8.12 já havia indicado, a correlação entre as variáveis renda mensal e
engajamento é fraca (valor próximo de zero). Também vemos que o coeficiente de Pearson é um
pouco maior que o de Spearman que por sua vez é um pouco maior que o de Kendall. Em geral essa
ordem vai se manter para a maioria das análises de correlação que você fizer. Isso se deve pela forma
como cada coeficiente é construído. Não vamos entrar em detalhes nas equações, porém mantenha
isso em mente e não se preocupe com o valor exato. O importante é a avaliação de existência ou não
de relação entre variáveis e qual a força desta associação.

Neste capítulo apresentamos uma visão geral das técnicas de estatística descritiva e explora-
tória. Começando pela classificação das variáveis, descrevemos como apresentar e resumir cada uma
delas, bem como, verificar as suas relações por meio das medidas resumo e opções gráficas mais simples
e conhecidas. Ressaltamos que o tópico de análise descritiva e exploratória é um campo sem fim e que
este capítulo apenas fornece o ferramental básico para uma análise mínima. No próximo Capítulo
vamos juntar tudo que aprendemos nos Capítulos anteriores em uma análise de dados real.

Ômega · Escola de Data Science omegadatascience.com.br


162 Capítulo 8. Estatística descritiva e exploratória com o R base

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 9

Estatística descritiva e exploratória com


o tidyverse

No Capítulo 6 foi apresentado como lidar com dados desde a sua importação, até arrumação,
manipulação e exportação usando os princípios do tidy data. No entanto, apenas ter os dados organi-
zados não significa ter informações sobre o problema de interesse. Para realmente tirar o melhor dos
nossos dados precisamos analisá-los usando métodos estatísticos apropriados.

A etapa elementar de qualquer análise estatística de dados é a chamada análise descritiva e


exploratória. O objetivo desta etapa é sintetizar e apresentar um conjunto de dados de forma fácil
de entender. Neste Capítulo serão apresentados os aspectos básicos da análise exploratória de dados
e como executá-los em R. É importante enfatizar que este livro não é sobre estatística descritiva, mas
sim sobre como realizar análises descritivas usando o software R. No entanto sempre que possível será
discutida a pertinência e o melhor uso das diversas técnicas.

A melhor forma de aprender a fazer uma análise descritiva é fazendo uma análise descri-
tiva. Neste Capítulo vamos explorar um conjunto de dados de uma área muito interessante cha-
mada de people analytics (análise de pessoas). Os dados são uma adaptação do conjunto de dados
Human Resources Data Set disponível na plataforma kaggle. As adaptações foram foitas para tor-
nar o conjunto de dados mais simples por meio da retirada de algumas variáveis e também da tra-
dução e adaptação dos dados para o contexto brasileiro. Os dados estão disponíveis no endereço
www.leg.ufpr.br/~wagner/data/people_analytics.csv. O caracterer delimitador é ; e podemos facil-
mente ler essa base de dados usando a função read.table().

dados <- read.table(”data/people_analytics.csv”, header = TRUE, sep = ”;”)


str(dados)

163
164 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

## ’data.frame’: 311 obs. of 14 variables:


## $ cod_colaborador : int 1 2 3 4 5 6 7 8 9 10 ...
## $ salario : int 62506 104437 64955 64991 50825 57568 95660 59365 47837 50178 ...
## $ posicao : chr ”Técnico de produção I” ”DBA senior” ”Técnico de produção II” ”Técnico de produ
## $ genero : chr ”masculino” ”masculino” ”feminino” ”feminino” ...
## $ estado_civil : chr ”solteiro” ”casado” ”casado” ”casado” ...
## $ departamento : chr ”producao” ”TI” ”producao” ”producao” ...
## $ forma_recrutamento: chr ”LinkedIn” ”Indeed” ”LinkedIn” ”Indeed” ...
## $ performance_score : chr ”excede” ”atende totalmente” ”atende totalmente” ”atende totalmente” ...
## $ engajamento : num 4.6 4.96 3.02 4.84 5 5 3.04 5 4.46 5 ...
## $ faltas : int 1 17 3 15 2 15 19 19 4 16 ...
## $ admissao : chr ”7/5/2011” ”3/30/2015” ”7/5/2011” ”1/7/2008” ...
## $ demissao : chr ”” ”6/16/2016” ”9/24/2012” ”” ...
## $ razao_demissao : chr ”ainda empregado” ”mudou de carreira” ”horário” ”ainda empregado” ...
## $ status : chr ”ativo” ”pediu demissão” ”pediu demissão” ”ativo” ...

O conjunto de dados corresponde a 311 observações de 14 variáveis. Ao começar a análise


é importante saber qual o conteúdo de cada variável. Fazer um dicionário é altamente recomendável
neste etapa. Lembre-se: pode ser que outra pessoa vá repetir sua análise no futuro e ter claro o que
cada variável significa é imprescindível. Um dicionário nada mais é do que uma lista com o nome de
cada variável e o que ela representa/significa. Por exemplo, para o conjunto de dados people analytics
o dicionário é o seguinte.

▶ cod_colaborador: código do colaborador. É apenas um número único para cada trabalhador.


Não existe interesse analítico para esta variável.

▶ salario: salário anual do colaborador em reais.

▶ posicao: nome do cargo que o colaborador ocupa.

▶ genero: gênero do colaborador.

▶ estado_civil: estado civil do colaborador.

▶ departamento: departamento no qual o colaborador atua.

▶ forma_recrutamento: forma pela qual o colaborador foi recrutado.

▶ performance_score: escore dado pelo recrutador que indica o grau de compatibilidade entre o
candidato e a vaga.

▶ engajamento: escore entre 1 e 5 para o engajamento do colaborador.

▶ faltas: número de faltas do colaborador no período que está na empresa.

▶ admissao: data de admissão do colaborador.

▶ demissao: data de demissão do colaborador. No caso do colaborador ainda estar empregado a


data está em branco.

▶ razao_demissao: razão pela qual o colaborador foi demitido. No caso de não ter sido demitido
é colocado como ainda empregado.

Ômega · Escola de Data Science omegadatascience.com.br


9.1 165

▶ status: situação do colaborar dentro da empresa.

9.1 Tipos de variáveis


Um bom primeiro passo para uma análise descritiva é identificar o tipo de cada uma das variá-
veis sendo analisadas. A Figura 9.1 resume os tipos de variáveis que lidamos em estatística descritiva.

Figura 9.1: Principais tipos de variáveis.

Podemos classificar variáveis como qualitativas e quantitativas. Como o nome já sugere,


variáveis qualitativas representam qualidades. Se a qualidade apresentar uma ordem natural entre seus
níveis, dizemos que temos uma variável qualitativa ordinal. Caso contrário, não existe uma ordem
e temos uma variável qualitativa nominal. Variáveis qualitativas são, em geral, nomes que damos
a níveis de uma variável, ou seja, tratam-se de rótulos. Por exemplo: gênero, estado civil, grau de
satisfação com o trabalho.

Por outro lado, variáveis quantitativas representam medidas numéricas. Se essas medidas
puderem assumir apenas um número finito ou contável de valores, dizemos que se trata de uma
variável quantitativa discreta. Se as medidas puderem assumir um número infinito de valores então
temos uma variável quantitativa contínua. Uma dica para diferenciar entre variáveis discretas e
contínuas é: se puder contar é discreta, se medir é contínua.

Olhando para o conjunto de dados people analytics podemos facilmente classificar cada uma
de suas variáveis usando as diretrizes apresentadas na Figura 8.1.

▶ Quantitativas: salario, engajamento e faltas.

▶ Quantitativas contínuas: salario e engajamento.

▶ Quantitativa discreta: faltas.

Ômega · Escola de Data Science omegadatascience.com.br


166 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

▶ Qualitativas: posicao, genero, estado_civil, departamento, forma_recrutamento,


performance_score, razao_demissao e status.

▶ Qualitativas nominais: posicao, genero, estado_civil, departamento, forma_recrutamento,


razao_demissao e status.

▶ Qualitativa ordinal: performance_score.

As variáveis referentes a datas (datas de admissão e demissão) não se encaixam perfeitamente


na classificação proposta mas também trazem informações relevantes para a análise. Por enquanto
vamos deixar as datas de lado e lidar apenas com as variáveis qualitativas e quantitativas. Considerando
a classificação das variáveis podemos proceder com as análises específicas para cada tipo de variável.

9.2 Análise univariada


Chamamos de análise univariada a descrição de cada uma das variáveis de forma indepen-
dente. Em termos de técnicas descritivas, basicamente usamos tabelas de frequência para variáveis
qualitativas e resumos numéricos como média, mediana, moda e desvio-padrão para variáveis quan-
titativas. Em termos de análises gráficas o gráfico de barras e suas variações são os mais indicados
para representar variáveis qualitativas. Já para variáveis quantitativas, o histograma e suas variações
são boas escolhas para representar as variáveis.

9.2.1 Variável qualitativa nominal


Conforme mencionado, para variáveis qualitativas nominais a melhor forma de resumir os
dados é por meio de uma tabela de frequência absoluta. Uma tabela de frequência se resume a nada
mais do que contar o número de ocorrências de cada opção (nível) da variável qualitativa e organizar
essas contagens em uma tabela que associa o nível da variável à quantas vezes o nível aparece. Em
R a função table() faz este trabalho. Como exemplo considere as variáveis gênero e estado civil,
conforme ilustrado no Código 9.1.

Código 9.1. Exemplo de tabelas de frequência absoluta.

# Tabela genero
table(dados$genero)

##
## feminino masculino
## 176 135

# Tabela estado civil


table(dados$estado_civil)

##
## casado divorciado separado solteiro viúvo
## 124 30 12 137 8

Ômega · Escola de Data Science omegadatascience.com.br


9.2 167

Podemos também apresentar as distribuições de frequência em termos relativos, ou seja, di-


vidimos cada frequência absoluta pelo total conforme ilustrado no Código 9.2. É comum multiplicar
a frequência relativa por cem para obter um percentual. O objetivo é apenas facilitar a interpretação.

Código 9.2. Exemplos de tabela com frequência relativa.

## Tabela frequencia relativa


prop.table(table(dados$departamento))*100

##
## administracao engenharia de software executivo
## 2.894 3.537 0.322
## producao TI vendas
## 67.203 16.077 9.968

##
prop.table(table(dados$forma_recrutamento))*100

##
## aplicação online careerbuilder google Indeed
## 0.322 7.395 15.756 27.974
## indicação LinkedIn outros vagas inclusivas
## 9.968 24.437 0.643 9.325
## website
## 4.180

Interpretando os resultados das tabelas, notamos que, em termos de departamento, a maioria


dos colaboradores trabalham no departamento de produção. A forma de recrutamento mais popular
é o site Indeed seguido pelo LinkedIn e Google.

Para representação gráfica, o mais indicado para variáveis qualitativas nominais é o gráfico
de barras e de setores. O gráfico de setores apesar de seu aspecto histórico não é recomendado por ser
de difícil interpretação. Em geral nossos olhos têm dificuldade em diferenciar o tamanho das fatias.
Vamos ilustrar o seu uso, porém sugerimos o uso cauteloso desta opção.

Em R existem funções nativas como as funções barplot() e pie() para obter os gráficos de
barras e setores. Contudo vamos ilustrar como obter gráficos utilizando outro pacote do tidyverse:
o ggplot2. Trata-se de um pacote baseado na gramática dos gráficos, ou seja, tem um modelo mental
mais claro para elaboração de gráficos. O pacote permite plotagem multi-painel e mapeamento em
variáveis visuais retinais.

library(ggplot2)
help(ggplot2)

ggplot(data = dados,
mapping = aes(x = estado_civil)) +
geom_bar() +
xlab(”Estado civil”) +
ylab(”Frequência absoluta”)

Ômega · Escola de Data Science omegadatascience.com.br


168 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

100
Frequência absoluta

50

casado divorciado separado solteiro viúvo


Estado civil

Figura 9.2: Gráfico de barras

ggplot(data = dados,
mapping = aes(x = factor(1),
fill = factor(estado_civil))) +
labs(fill = ”Estado civil”) +
geom_bar(width = 0.75,
col = 1) +
coord_polar(theta = ”y”) +
xlab(NULL) +
ylab(NULL)

No caso de uma variável qualitativa com vários níveis, como o estado civil, é interessante
ordenar o gráfico do maior para o menor. Isso ajuda a identificar pontos extremos e estabelecer
comparações de forma mais rápida. Para isso, precisamos trocar a classe da variável estado_civil
para fator e dizer qual a ordem de seus níveis. O Código 9.3 ilustra este processo.

Código 9.3. Ordenando os níveis de uma variável qualitativa nominal.

tab_est_civil <- table(dados$estado_civil)


ordem <- order(tab_est_civil, decreasing = TRUE)
dados$estado_civil <- as.factor(dados$estado_civil)
dados$estado_civil <- factor(dados$estado_civil,
levels = levels(dados$estado_civil)[ordem])

Veja a ordem lógica das operações:

1. Construímos a tabela de frequência para saber qual será a ordem de apresentação.


2. Obtemos a ordem descrescente dos níveis da variável.
3. Transformamos a classe da variável estado_civil para factor.

Ômega · Escola de Data Science omegadatascience.com.br


9.2 169

300 0

1
Estado civil
casado
divorciado
separado
solteiro
viúvo
100

200

Figura 9.3: Gráfico de setores

4. Reordenamos os níveis (levels) da variável estado_civil seguindo a ordem obtida no passo 2.

Agora podemos plotar o gráfico de barras.

ggplot(data = dados,
mapping = aes(x = estado_civil)) +
geom_bar() +
xlab(”Estado civil”) +
ylab(”Frequência absoluta”)

Ômega · Escola de Data Science omegadatascience.com.br


170 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

100
Frequência absoluta

50

solteiro casado divorciado separado viúvo


Estado civil

Da mesma forma que as tabelas de frequência, o gráfico de barras pode ser feito usando a
frequência absoluta ou relativa.

ggplot(data = dados,
mapping = aes(x = estado_civil)) +
geom_bar(aes(y = (..count..)/sum(..count..))) +
xlab(”Estado civil”) +
ylab(”Frequência absoluta”)

0.4

0.3
Frequência absoluta

0.2

0.1

0.0

solteiro casado divorciado separado viúvo


Estado civil

Ômega · Escola de Data Science omegadatascience.com.br


9.2 171

9.2.2 Variável qualitativa ordinal


Existem casos em que variáveis qualitativas apresentam uma ordem natural, como é o caso
da variável performance_score. É recomendável apresentar a tabela de frequência, seja absoluta ou
relativa, respeitando a ordem natural da variável. Por exemplo,

table(dados$performance_score)

##
## atende totalmente excede insuficiente
## 243 37 13
## precisa melhorar
## 18

Se optarmos por apresentar a variável performance_score de forma ascendente, a ordem


natural seria: insuficiente, precisa melhorar, atende totalmente e excede. Para dizermos ao R que essa
variável é qualitativa e ordinal precisamos transformá-la para a classe factor e indicar a ordem que
queremos que seja apresentada. Veja o Código 9.4.

Código 9.4. Exemplo de como definir a ordem de uma variável qualitativa ordinal.

dados$performance_score <- factor(dados$performance_score,


levels = c(”insuficiente”,
”precisa melhorar”,
”atende totalmente”,
”excede”))
prop.table(table(dados$performance_score))*100

##
## insuficiente precisa melhorar atende totalmente
## 4.18 5.79 78.14
## excede
## 11.90

Neste caso também faz sentido incluir a chamada frequência acumulada que nada mais é
do que somar os percentuais até determinado nível da variável qualitativa. Por exemplo, se temos
interesse no percentual de colaborares que tem escore precisa melhorar ou menor precisamos somar
insuficiente e precisa melhorar. Para obter as frequências acumuladas usamos a função cumsum(),
conforme ilustrado no Código 9.5.

Código 9.5. Frequência acumulada.

cumsum(prop.table(table(dados$performance_score))*100)

## insuficiente precisa melhorar atende totalmente


## 4.18 9.97 88.10
## excede
## 100.00

Novamente o gráfico de barras e setores são os mais indicados para análise gráfica.

Ômega · Escola de Data Science omegadatascience.com.br


172 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

ggplot(data = dados,
mapping = aes(x = performance_score)) +
geom_bar() +
xlab(”Escore”) +
ylab(”Frequência absoluta”)

250

200
Frequência absoluta

150

100

50

insuficiente precisa melhorar atende totalmente excede


Escore

Neste caso, precisa ser avaliado se vale a pena mudar a ordem para que as classes mais fre-
quentes apareçam a esquerda do gráfico. Em geral é preferível manter a ordem natural da variável,
mas sempre existem exceções.

Outro aspecto a considerar é quando a variável tem muitos níveis. Por exemplo, a variá-
vel posicao tem 26 níveis. Ao fazer uma tabela com tantos níveis pode ser difícil de visualizar os
resultados.

table(dados$posicao)

Ômega · Escola de Data Science omegadatascience.com.br


9.2 173

##
## Administrador BD Analista de dados
## 5 8
## Arquiteto de dados Arquiteto de empreendimentos
## 2 1
## Assistente administrativo CEO
## 3 1
## CIO Contador
## 1 3
## Contador senior DBA senior
## 2 2
## Desenvolvedor BI Desenvolvedor BI senior
## 4 3
## Diretor BI Diretor de operações
## 1 1
## Diretor de TI Diretos de vendas
## 1 1
## Engenheiro de rede senior Engenheiro de redes
## 5 5
## Engenheiro de software Gerente de produção
## 10 14
## Gerente de serviços Gerente de TI
## 1 12
## Gerente de vendas Gerente engenheiro de software
## 30 1
## Técnico de produção I Técnico de produção II
## 137 57

Uma dica útil é tentar agrupar os níveis que tenham baixa ocorrência ou que façam sentido
serem agrupados. Por exemplo, poderíamos juntar os níveis Técnico de produção I e Técnico de
produção II, desde que faça sentido prático. Essa é uma decisão que deve ser tomada junto com o
time que vai usar suas análises. Outra opção seria agrupar Contador e Contador Senior. O importante
é que a forma de agrupar deve estar de acordo com os objetivos da análise e alinhada com toda a equipe
que vai se beneficiar dela.

9.2.3 Variável quantitativa discreta

A análise exploratória de variáveis quantitativas discretas com poucos valores é de certa forma
similar a análise de variáveis qualitativas ordinais. Assim, tabelas de frequência absoluta, relativa e
acumulada são ferramentas populares. Os gráficos de barras também são indicados. Em nosso exemplo
a única variável quantitativa discreta é o número de faltas. Podemos fazer uma tabela de frequência
absoluta, relativa e acumulada, conforme ilustra o Código 9.6.

Código 9.6. Tabelas de frequência variável quantitativa discreta.

Ômega · Escola de Data Science omegadatascience.com.br


174 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

# Frequencia absoluta
abs <- table(dados$faltas)

# Frequencia relativa
percentual <- prop.table(table(dados$faltas))*100

## Frequencia acumulada
acumulada <- cumsum(prop.table(table(dados$faltas)))

resultado <- data.frame(”Absoluta” = abs,


”Percentual” = percentual,
”Acumulada” = acumulada)

Apesar de ser possível, a tabela gerada ficou grande e de difícil interpretação, pois existem 20
valores distintos para a variável faltas. Nestes casos o mais indicado é tratar as variáveis quantitativas
discretas como quantitativas contínuas, conforme veremos na próxima subseção.

9.2.4 Variável quantitativa contínua


No caso de variáveis quantativas contínuas, fazer uma tabela de frequência é impraticável
pelo grande número de possíveis valores que a variável pode assumir. Assim, a estratégia é criar
faixas de valores e então construir as tabelas de frequência de forma similar ao realizado para variáveis
qualitativas ordinais.

Em R a função cut() é bastante útil para agrupar as observações em faixas. Criar as faixas
é um assunto que requer bastante cuidado. Se você estiver em alguma situação em que as classes
podem ser criadas de acordo com alguma regra de negócio ou mesmo conforme interesse da equipe,
é perfeitamente aceitável usar essa informação para criar as classes. Caso contrário existem algumas
técnicas estatísticas para ajudar com esta tarefa. O importante é ter em mente que essa deve ser uma
decisão pensada de acordo com o negócio que você está lidando.

Vamos supor que um interesse da equipe é comparar as faixas de renda dentro da empresa
com as da população de forma geral. Você consultou o site do IBGE e constatou que para pesquisas
populacionais o IBGE usa as seguintes faixas de renda para obter a classe social de uma pessoa.

Classe Renda

A R$ 20.900,01 ou mais
B R$ 10.450,01 até R$ 20.900,00
C R$ 4.180,01 até R$ 10.450,01
D R$ 2.090,01 até R$ 4.180,00
E até R$ 2.090,01

Podemos então usar a função cut() para criar as faixas de renda.

Ômega · Escola de Data Science omegadatascience.com.br


9.2 175

faixas <- c(0, 2090.01, 4180.01, 10450.01, 20900.01, Inf)

Note que não precisamos explicitamente seguir a tabela do IBGE, uma vez que podemos
usar intervalos abertos a direita. Isso significa que entre 0 e 2.090, 01 o valor exato 2.090, 01 não será
contado na primeira faixa e assim por diante. Outro aspecto para estar atento é que a classificação do
IBGE é baseada na renda mensal. Por outro lado, nossa base de dados reporta a renda anual. Assim,
vamos primeiro dividir a variável por 12 para ter a renda mensal média. Para definir um intervalo
aberto a direita usamos as opção right = FALSE.

dados$renda_mensal <- dados$salario/12


table(cut(dados$renda_mensal, breaks = faixas))

##
## (0,2.09e+03] (2.09e+03,4.18e+03] (4.18e+03,1.05e+04]
## 0 31 270
## (1.05e+04,2.09e+04] (2.09e+04,Inf]
## 10 0

Novamente, a tabela pode conter a frequência absoluta, relativa e acumulada. Em termos de


gráficos o mais indicado para variáveis quantitativas contínuas é o histograma. Um histograma nada
mais é do que uma representação gráfica da tabela de frequências. Para construção do histograma
podemos usar tanto frequências absolutas quanto relativas. A Figura 9.4 mostra como gerar um
histograma usando as frequências absolutas.

ggplot(data = dados,
mapping = aes(x = salario)) +
geom_histogram() +
xlab(”Salário anual”) +
ylab(”Frequência absoluta”)

Apesar do gráfico da Figura 9.4 ser popularmente chamado de histograma, técnicamente ele
é uma adaptação do histograma original. Note que, no eixo y, temos a representação das frequências
absolutas de cada faixa de valores. Contudo, na concepção original do histograma, o eixo y é usado
para representar o que chamamos de densidade, conforme ilustrado na Figura 9.5.

ggplot(data = dados,
mapping = aes(x = salario,
y = ..density..)) +
geom_histogram() +
xlab(”Salário anual”) +
ylab(”Densidade”)

A ideia da densidade consiste em pensar qual o valor deve ser colocado no eixo y para que
quando a área de cada retângulo for calculada seja obtida a frequência relativa. Assim, a densidade é
calculada da seguinte forma

limite superior − limite inferior


densidade = .
frequência relativa

Ômega · Escola de Data Science omegadatascience.com.br


176 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

75
Frequência absoluta

50

25

50000 100000 150000 200000 250000


Salário anual

Figura 9.4: Histograma para a variável salário anual.

Lembre-se que a área de um retângulo é calculada como o tamanho da base vezes a altura,
ou seja,

área = (limite superior − limite inferior) ∗ altura.

Como queremos que a área seja igual a frequência relativa, basta isolar a altura. Chamamos
esta altura de densidade. Para ilustrar, vamos usar como exemplo o cálculo da densidade para a variável
engajamento utilizando a função hist().

histograma <- hist(dados$engajamento,


plot = FALSE)
histograma

Ômega · Escola de Data Science omegadatascience.com.br


9.2 177

4e-05

3e-05
Densidade

2e-05

1e-05

0e+00

50000 100000 150000 200000 250000


Salário anual

Figura 9.5: Histograma para a variável salário anual com a densidade representada na eixo y.

## $breaks
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
##
## $counts
## [1] 2 6 11 8 37 46 98 103
##
## $density
## [1] 0.0129 0.0386 0.0707 0.0514 0.2379 0.2958 0.6302 0.6624
##
## $mids
## [1] 1.25 1.75 2.25 2.75 3.25 3.75 4.25 4.75
##
## $xname
## [1] ”dados$engajamento”
##
## $equidist
## [1] TRUE
##
## attr(,”class”)
## [1] ”histogram”

Ao analisar o conteúdo do objeto histograma vemos que temos as classes (breaks), a frequência
absoluta (counts) e as densidades (density). A classe modal (maior frequência) é a que vai de 4.5 até 5.
Para calcular a densidade desta classe:

1. Calculamos a amplitude da classe, ou seja, o limite superior (5) menos o limite inferior (4.5).
Logo, a amplitude é 5 − 4.5 = 0.5.
2. Calculamos a frequência relativa da classe. Neste caso 103/311 = 0.331.
3. Calculamos a densidade 0.331/0.5 = 0.662.

Ômega · Escola de Data Science omegadatascience.com.br


178 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

Note que ao calcular a área do último retângulo temos:

1. A base é 5 − 4.5 = 0.5.


2. A altura (densidade) é 0.662.
3. E a área é a base multipicada pela altura, 0.5 ∗ 0.662 = 0.331 que é a frequência relativa da classe
considerada.

Os cálculos são idênticos para as demais classes. Mas você deve estar se perguntando: por
que complicar o que estava fácil?

A ideia do histograma é fornecer a distribuição de probabilidade empírica de uma variável


aleatória. Isso se deve ao fato de que a área da soma de todos os retângulos que compõem o histograma
deve ser igual a 1. Se você não está familiarizado com conceitos básicos de variáveis aleatórias e
probabilidade recomendamos que avalie o nosso curso de Probabilidade e Estatística para Ciência de
Dados.

No contexto de variáveis quantitativas contínuas a distribuição de frequências por meio do


histograma fornece um resumo da distribuição das observações. Apesar de muito útil e visual pode ser
difícil comparar diversos histogramas em uma mesma análise. Por exemplo, suponha que desejamos
comparar o grau de engajamento dos colaboradores de acordo com o gênero. Esta é uma tarefa
simples, basta fazer um histograma para os colaboradores do gênero feminino e outro para o gênero
masculino, conforme ilustra a Figura 9.6.

ggplot(data = dados,
mapping = aes(x = engajamento)) +
geom_histogram() +
facet_wrap(facets = ~genero) +
xlab(”Engajamento”) +
ylab(”Freq. Absoluta”)

Para variáveis com muitos níveis pode ficar difícil avaliar tantos histogramas. Além disso, os
histogramas podem ter comportamentos parecidos, o que torna difícil encontrar diferenças apenas
visualmente. A estatística nos proporciona um conjunto de medidas numéricas para resumir a distri-
buição de frequências. Em geral olhamos para dois aspectos básicos da distribuição de frequência: a
sua tendência central e sua dispersão ou espalhamento.

As medidas de tendência central ou também chamadas de medidas de posição central mais


populares são a média aritmética, a mediana e a moda. A obtenção destas estatísticas é muito simples:

▶ Média aritmética: para uma variável quantitativa basta somar todos os seus valores e dividir
pelo número de observações. A interpretação física é que a média é o centro de gravidade da
distribuição empírica. Pense que cada um dos retângulos é uma massa com peso igual a sua
densidade. Imagine que o eixo x é uma régua. O ponto médio é onde você deve colocar uma
agulha para perfeitamente equilibrar as massas sobre a régua.

▶ Mediana: ordene as observações de acordo com os valores de uma variável quantitativa do

Ômega · Escola de Data Science omegadatascience.com.br


9.2 179

feminino masculino

30

20
Freq. Absoluta

10

1 2 3 4 5 1 2 3 4 5
Engajamento

Figura 9.6: Histograma para os gêneros feminino e masculino.

menor para o maior. A mediana é o valor que estiver na posição i) (N + 1)/2 se N é ímpar e a
média dos valores das posições (N/2) e (N/2)+1 se N par. A ideia é saber exatamente que 50%
das observações tem valores menores do que a mediana. Óbviamente, 50% das observações tem
valores maiores do que a mediana.

▶ Moda: valor mais frequente. No caso de uma variável onde praticamente só existem valores
únicos, essa medida tem pouca aplicação prática. Você pode reportar a classe modal se for de
interesse. Em geral, a média e a mediana costumam ser suficientes para ter um boa noção da
centralidade da distribuição empírica.

Neste livro não vamos dar ênfase as formulas de como obter tais estatísticas. Nosso objetivo é
mostrar como obtê-las usando o R. Para a variável renda_mensal podemos facilmente calcular a média
e a mediana, conforme ilustra o Código 9.7.

Código 9.7. Medidas de tendência central.

# Média
mean(dados$renda_mensal)

## [1] 5752

Ômega · Escola de Data Science omegadatascience.com.br


180 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

# Mediana
median(dados$renda_mensal)

## [1] 5234

A mediana divide o conjunto de observações em dois grupos com o mesmo número de


observações. Porém, podemos pensar em dividir o conjunto de dados em mais partes. Essa ideia
dá origem aos chamados quartis. Os quartis são os valores da variável que dividem as observações
em quatro grupos de mesmo tamanho. Chamamos de primeiro quartil o valor que separa 1/4 dos
valores à sua esquerda e 3/4 à direita; o segundo quartil é a própria mediana e o terceiro quartil é o
valor que tem 3/4 dos valores da distribuição à sua esquerda e 1/4 à direita. Em R a função quantile()
calcula os quartis, conforme ilustra o Código 9.8.

Código 9.8. Cálculo dos quantis.

quantile(dados$renda_mensal)

## 0% 25% 50% 75% 100%


## 3754 4625 5234 6003 20833

Além dos quartis, a função quantile() apresenta os valores mínimos e máximos. Juntos, esses
valores são o chamado resumo de cinco números. É muito comum apresentar o resumo dos cinco
números em um diagrama de caixas ou boxplot, conforme ilustrado na Figura 8.10.

ggplot(data = dados,
mapping = aes(x = 1, y = renda_mensal)) +
geom_boxplot() +
xlab(””)+
ylab(”Renda mensal”)

20000

15000
Renda mensal

10000

5000

0.6 0.8 1.0 1.2 1.4

Figura 9.7: Boxplot para a variável renda mensal.

Analisando o gráfico da Figura 8.10 de baixo para cima, temos:

▶ A primeira linha horizontal representa o valor mínimo, sem considerar os valores que ultrapas-
sam o desvio interquartílico.

Ômega · Escola de Data Science omegadatascience.com.br


9.2 181

▶ A segunda linha horizontal representa o primeiro quartil.


▶ A linha mais grossa no meio da caixa representa a mediana.
▶ A terceira linha horizontal representa o terceiro quartil.
▶ A última linha horizontal representa o valor máximo, sem considerar os valores que ultrapassam
o desvio interquartílico.

O desvio interquartílico é definido como 1.5 vezes o terceiro quartil menos o primeiro quartil.
É um valor de referência e cria a chamada barreira de valores atípicos. Muitos analistas chamam os
valores além do desvio interquartilico de outliers. Porém, isso não é verdade e a definição exata do
que é um outliers depende de outros aspectos como do modelo que será ajustado. Neste livro não
vamos entrar neste tipo de detalhe. Tenha em mente de que estamos apenas na parte inicial da análise
e a detecção de outliers é uma das etapas finais da modelagem estatística e portanto além dos objetivos
deste livro.

O desvio interquartílico é uma medida de dispersão ou espalhamento da distribuição de


frequências. Existem diversas outras medidas de dispersão, por exemplo:

▶ Amplitude total: diferença entre o maior e menor valor.


▶ Variância: soma dos quadrados dos desvios (diferença entre a observação e a média) dividido
pelo tamanho da amostra menos 1. Em notação matemática, sendo yi os valores da variável e
ȳ a sua média aritmética a variância é dada por
∑n
2 i=1 (yi− ȳ)
s = .
n−1

▶ Desvio-padrão: raiz quadrada positiva da variância. A grande vantagem do desvio-padrão é


que está na mesma escala da variável, sendo de mais fácil interpretação.
▶ Coeficiente de variação: É a relação entre o desvio-padrão e a média. É geralmente expresso
em percentagem, o que facilita a comparação de variabilidade entre variáveis com valores em
unidades diferentes.

Em R é fácil obter todas essas medidas, conforme ilustra o Código 9.9.

Código 9.9. Medidas de dispersão.

amplitude <- max(dados$renda_mensal) - min(dados$renda_mensal)


amplitude

## [1] 17080

# Variância
var(dados$renda_mensal)

## [1] 4394836

Ômega · Escola de Data Science omegadatascience.com.br


182 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

# Desvio-padrão
sd(dados$renda_mensal)

## [1] 2096

## Coeficiente de variação
(sd(dados$renda_mensal)/mean(dados$renda_mensal))*100

## [1] 36.4

Existem diversas outras medidas resumo tanto de tendência central quanto de dispersão. Para
mais detalhes considere o curso Probabilidade e Estatística para Ciência de dados e a bibliografia
complementar ao final deste livro.

A vantagem de usar essas medidas resumo é mais facilmente poder comparar diferentes grupos
com relação a tendência central e/ou variabilidade. Por exemplo, podemos estar interessados em
comparar o salário médio dos colaboradores de acordo com o departamento em que trabalham. Já
vimos que a função summarise() do pacote dplyr é especialmente útil para este tipo de resumo.

library(dplyr)

dados %>%
group_by(departamento) %>%
summarise(media = mean(renda_mensal))

## # A tibble: 6 x 2
## departamento media
## <chr> <dbl>
## 1 administracao 5983.
## 2 engenharia de software 7916.
## 3 executivo 20833.
## 4 producao 4996.
## 5 TI 8089.
## 6 vendas 5755.

Note que agora estamos usando uma variável para condicionar o comportamento de outra.
Isso é o que chamamos de análise descritiva bivariada e será o assunto da próxima subseção.

9.3 Análise bivariada


O principal objetivo da análise univariada é resumir o comportamento de uma variável de
tal modo que o comportamento desta variável se torne mais simples de se entender. Porém, o grande
valor da maioria das análises de dados está em entender e identificar relações entre diferentes variáveis.
Assim, o objetivo da análise bivariada é descrever e mensurar relações entre variáveis. O tipo de
resumo vai depender do tipo das variáveis sendo consideradas. Neste contexto temos as seguintes
possibilidades:

▶ Qualitativa × qualitativa;

Ômega · Escola de Data Science omegadatascience.com.br


9.3 183

▶ Qualitativa × quantitativa;
▶ Quantitativa × quantitativa.

Novamente, temos gráficos e medidas numéricas para resumir a relação entre as variáveis.
Nesta seção vamos ver apenas as medidas e gráficos mais populares. Para mais detalhes considere o
curso Manipulação e visualização com o R e as referências no final deste livro.

9.3.1 Qualitativa × qualitativa


A forma mais simples de representar a relação entre duas variáveis qualitativas é por meio de
uma tabela de dupla entrada. Considere as variáveis genero e forma_recrutamento. Nosso interesse
pode ser saber se uma determinada forma de recrutamento difere da outra em relação ao gênero dos
colaboradores. O Código 9.10 ilustra a criação de uma tabela de dupla entrada em R.

Código 9.10. Tabela de dupla entrada.

table(dados$forma_recrutamento, dados$genero)

##
## feminino masculino
## aplicação online 0 1
## careerbuilder 16 7
## google 33 16
## Indeed 50 37
## indicação 11 20
## LinkedIn 44 32
## outros 1 1
## vagas inclusivas 15 14
## website 6 7

Para economizar um pouco na digitação dos comandos podemos usar a função with().

with(dados, table(forma_recrutamento, genero))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0 1
## careerbuilder 16 7
## google 33 16
## Indeed 50 37
## indicação 11 20
## LinkedIn 44 32
## outros 1 1
## vagas inclusivas 15 14
## website 6 7

Novamente podemos calcular as frequências relativas, no entanto precisamos tomar cuidado


porque nas tabelas de dupla entrada temos várias opções, podemos obter frequências relativas em
relação:

▶ Ao total geral, ou seja, número total de observações.

Ômega · Escola de Data Science omegadatascience.com.br


184 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

▶ Aos totais das linhas (margin = 1).


▶ Aos totais das colunas (margin = 2).

A função prop.table() continua sendo a nossa escolha, conforme ilustra o Código 9.11.

Código 9.11. Tabela de dupla entrada com frequências relativas.

# Relação ao total geral


with(dados, prop.table(table(forma_recrutamento, genero)))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.00000 0.00322
## careerbuilder 0.05145 0.02251
## google 0.10611 0.05145
## Indeed 0.16077 0.11897
## indicação 0.03537 0.06431
## LinkedIn 0.14148 0.10289
## outros 0.00322 0.00322
## vagas inclusivas 0.04823 0.04502
## website 0.01929 0.02251

# Relação aos totais das linhas


with(dados, prop.table(table(forma_recrutamento, genero), margin = 1))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.000 1.000
## careerbuilder 0.696 0.304
## google 0.673 0.327
## Indeed 0.575 0.425
## indicação 0.355 0.645
## LinkedIn 0.579 0.421
## outros 0.500 0.500
## vagas inclusivas 0.517 0.483
## website 0.462 0.538

# Relação aos totais das colunas


with(dados, prop.table(table(forma_recrutamento, genero), margin = 2))

## genero
## forma_recrutamento feminino masculino
## aplicação online 0.00000 0.00741
## careerbuilder 0.09091 0.05185
## google 0.18750 0.11852
## Indeed 0.28409 0.27407
## indicação 0.06250 0.14815
## LinkedIn 0.25000 0.23704
## outros 0.00568 0.00741
## vagas inclusivas 0.08523 0.10370
## website 0.03409 0.05185

As vezes pode ser de interesse adicionar o total das linhas e colunas para facilitar a interpreta-
ção. A função addmargins() cumpre esse papel, conforme ilustra o Código 9.12.

Código 9.12. Adiciona os totais marginais (linhas e colunas).

Ômega · Escola de Data Science omegadatascience.com.br


9.3 185

tab <- with(dados, prop.table(table(forma_recrutamento, genero)))


addmargins(tab)

## genero
## forma_recrutamento feminino masculino Sum
## aplicação online 0.00000 0.00322 0.00322
## careerbuilder 0.05145 0.02251 0.07395
## google 0.10611 0.05145 0.15756
## Indeed 0.16077 0.11897 0.27974
## indicação 0.03537 0.06431 0.09968
## LinkedIn 0.14148 0.10289 0.24437
## outros 0.00322 0.00322 0.00643
## vagas inclusivas 0.04823 0.04502 0.09325
## website 0.01929 0.02251 0.04180
## Sum 0.56592 0.43408 1.00000

Em termos de análise gráfica, o gráfico de barras continua sendo a melhor escolha. No


entanto, agora precisamos representar duas barras e portanto existem diversas formas de representação.

Se o objetivo é enfatizar a composição de cada grupo podemos usar barras empilhadas. Em


geral, mantemos fixa a variável que temos mais interesse e colorimos as barras de acordo com os
valores da outra variável. Veja os exemplos da Figuras 9.8 e 9.9.

idx <- order(table(dados$forma_recrutamento), decreasing = TRUE)


dados$forma_recrutamento <- as.factor(dados$forma_recrutamento)
dados$forma_recrutamento <- factor(dados$forma_recrutamento,
levels = levels(dados$forma_recrutamento)[idx])

ggplot(data = dados,
mapping = aes(x = forma_recrutamento,
fill = genero)) +
geom_bar(position = ”stack”) +
xlab(”Recrutamento”)+
ylab(”Freq. absoluta”) +
theme(legend.position = ”bottom”)

ggplot(data = dados,
mapping = aes(x = genero,
fill = status)) +
geom_bar(position = ”stack”) +
xlab(”Gênero”)+
ylab(”Freq. absoluta”)

Na Figura 9.8 enfatizamos a variável que representa a forma de recrutamento e por isso é ela
quem aparece formando as barras. A variável gênero tem um papel apenas complementar. Note que
a comparação em termos de composição por gênero deve ser feita dentro de cada coluna, uma vez
que a comparação entre colunas é difícil por não terem a mesma altura.

Por outro lado, na Figura 9.9, enfatizamos a composição de cada nível da variável gênero de
acordo com a variável status. Como as barras apresentam a frequência relativa, podemos comparar as
frequências não só dentro de cada barra mas também entre as barras.

Quando o objetivo for comparar os níveis de uma variável de acordo com os níveis de uma

Ômega · Escola de Data Science omegadatascience.com.br


186 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

75
Freq. absoluta

50

25

Indeed LinkedIn google indicaçãovagas inclusivas


careerbuilder website outros aplicação online
Recrutamento

genero feminino masculino

Figura 9.8: Exemplo 1 de gráfico com barras empilhadas.

outra variável podemos usar as barras lado a lado, conforme ilustra a Figura 9.10.

ggplot(data = dados,
mapping = aes(x = status,
fill = performance_score)) +
geom_bar(position = ”dodge”) +
xlab(”Status”)+
ylab(”Freq. absoluta”)

Por fim, em casos em que o número de níveis da variável é grande podemos apresentar as
barras na horizontal. A Figura 9.11 ilustra esta opção.

ggplot(data = dados,
mapping = aes(x = forma_recrutamento)) +
geom_bar(position = ”dodge”) +
xlab(”Recrutamento”)+
ylab(”Freq. absoluta”) +
coord_flip()

9.3.2 Qualitativa × quantitativa


Quando temos uma variável qualitativa e outra contínua a ideia geral da análise é usar o
que vimos na subseção 7.2.4, porém para cada nível da variável qualitativa. Por exemplo, podemos

Ômega · Escola de Data Science omegadatascience.com.br


9.3 187

150
Freq. absoluta

status
100
ativo
justa causa
pediu demissão

50

feminino masculino
Gênero

Figura 9.9: Exemplo 2 de gráfico com barras empilhadas.

comparar o salário médio dos colaboradores de acordo com o departamento em que eles trabalham.
Nós já vimos que para este tipo de tarefa a função summarise() atende ao propósito. O Código 9.13
ilustra como calcular não apenas a média mas também a mediana e o desvio-padrão da renda mensal
por nível da variável departamento.

Código 9.13. Calculando a média, mediana e desvio-padrão da renda mensal por departamento.

dados %>%
group_by(departamento) %>%
summarise(media = mean(renda_mensal),
mediana = median(renda_mensal),
sd = sd(renda_mensal))

## # A tibble: 6 x 4
## departamento media mediana sd
## <chr> <dbl> <dbl> <dbl>
## 1 administracao 5983. 5250. 1809.
## 2 engenharia de software 7916. 7972. 797.
## 3 executivo 20833. 20833. NA
## 4 producao 4996. 4956 952.
## 5 TI 8089. 7694. 2767.
## 6 vendas 5755. 5442. 1773.

Tente entender o porquê o desvio-padrão da renda mensal na classe executivo retornou como
NA.

Recomendamos usar o boxplot da variável quantitativa por nível da variável qualitativa para
análise gráfica, conforme ilustrado na Figura 9.12.

Ômega · Escola de Data Science omegadatascience.com.br


188 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

150

performance_score
Freq. absoluta

100
insuficiente
precisa melhorar
atende totalmente
excede
50

ativo justa causa pediu demissão


Status

Figura 9.10: Exemplos de gráficos com barras lado a lado.

ggplot(data = dados,
mapping = aes(x = forma_recrutamento,
y = renda_mensal)) +
geom_boxplot() +
xlab(”Recrutamento”)+
ylab(”Renda”)

Para melhorar a visualização você pode ordenar as caixas de acordo com a renda mediana
conforme Figura 9.13.

mediana <- aggregate(x = dados$renda_mensal,


by = list(dados$forma_recrutamento),
FUN = median)
idx <- order(mediana$x, decreasing = TRUE)
dados$forma_recrutamento <- as.factor(dados$forma_recrutamento)
dados$forma_recrutamento <- factor(dados$forma_recrutamento,
levels = levels(dados$forma_recrutamento)[idx])

ggplot(data = dados,
mapping = aes(x = forma_recrutamento,
y = renda_mensal)) +
geom_boxplot() +
xlab(”Recrutamento”)+
ylab(”Renda”)

Uma outra opção é criar faixas para a variável quantitativa e usar gráficos de barras como na
subseção 7.3.1.

Ômega · Escola de Data Science omegadatascience.com.br


9.3 189

aplicação online

outros

website

careerbuilder
Recrutamento

vagas inclusivas

indicação

google

LinkedIn

Indeed

0 25 50 75
Freq. absoluta

Figura 9.11: Exemplo de gráfico com barras horizontais.

9.3.3 Quantitativa × quantitativa


O gráfico mais popular para visualizar a relação entre duas variáveis quantitativas é o dia-
grama de dispersão, conforme mostra a Figura 9.14 para as variáveis renda mensal e engajamento.

ggplot(data = dados,
mapping = aes(x = engajamento,
y = renda_mensal)) +
geom_point() +
xlab(”Engajamento”)+
ylab(”Renda”)

Em geral o que buscamos ao analisar um diagrama de dispersão como o apresentado na Figura


9.14 é identificar algum tipo de padrão de relacionamento. Para interpretar um diagrama de dispersão,
tenha a Figura 9.15 como referência.

Olhando para o diagrama de dispersão da Figura 9.14 tente imaginar uma linha descrevendo
a relação entre as variáveis renda mensal e engajamento. Se a linha que você imaginar for conforme a
da Figura 9.15(A) significa que visualmente as duas variáveis não estão associadas ou tem uma relação
fraca. Por outro lado, se a linha estiver como na Figura 9.15(B) indica que as duas variáveis estão
positivamente associadas, ou seja, ao aumentar o valor de uma a outra também aumenta. Contudo,
se a linha for como na Figura 9.15(C) indica que a relação é negativa, ou seja, ao aumentar uma das
variáveis a outra diminui.

Para o nosso exemplo vemos uma leve tendência de relação positiva entre engajamento e
renda mensal. Porém a variabilidade (dispersão dos pontos) é bem alta e parece depender dos valores

Ômega · Escola de Data Science omegadatascience.com.br


190 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

20000

15000
Renda

10000

5000

Indeed LinkedIn google indicação


vagas inclusivas
careerbuilder website outros aplicação online
Recrutamento

Figura 9.12: Boxplot da variável renda mensal por níveis da variável forma de recrutamento.

da variável renda mensal.

Como você pode notar, interpretar um gráfico como o diagrama de dispersão é uma ativi-
dade bastante subjetiva. Existem algumas medidas numéricas que buscam resumir a relação linear
entre duas variáveis quantitativas, são os chamados coeficientes de correlação. Em geral usamos três
coeficientes de correlação: Pearson, Spearman e Kendal. Os três variam entre -1 e 1, sendo que −1
indica correlação perfeita negativa, todos os pontos caem exatamente em cima de uma reta como
da Figura 9.15(C). Uma correlação igual a 1 indica correlação positiva perfeita e neste caso todos os
pontos estariam em cima de uma reta como a apresentada na Figura 9.15(B). Se o valor da correlação
for zero não temos relação entre as variáveis e todos os pontos estariam em cima de uma reta como a
apresentada na Figura 9.15(A).

Na prática, esses valores são apenas referências e o que é considerada uma correlação forte
ou fraca vai depender do contexto. Além disso, um erro comum é dizer que se duas variáveis tem
correlação igual a zero elas são independentes. Essa afirmação em geral é falsa. O conceito de in-
dependência estatística requer a suposição de uma distribuição conjunta de probabilidades e não é
facilmente definido para qualquer distribuição a parte da distribuição normal bivariada. Conceitos de
Teoria das Probabilidades estão além do escopo deste livro. Para referência consulte a bibliografia
no final deste livro.

Ômega · Escola de Data Science omegadatascience.com.br


9.3 191

20000

15000
Renda

10000

5000

outros indicação Indeedvagas inclusivas


careerbuilder LinkedIn website googleaplicação online
Recrutamento

Figura 9.13: Boxplot com caixas ordenadas.

Por fim, sempre que temos mais do que uma opção, a pergunta natural é “qual é o melhor
coeficiente de correlação?”. Apesar de uma pergunta razoável, a resposta depende da situação e, em
geral, o melhor é calcular dois ou três deles e comparar os resultados. O coeficiente de correlação de
Pearson é o estimador de máxima verossimilhança do parâmetro de correlação de uma distribuição
normal bivariada. Neste contexto, se a distribuição conjunta for uma normal bivariada ele seria o
indicado. Porém, na prática não sabemos qual é a verdadeira distribuição conjunta das variáveis
envolvidas na análise. Uma boa indicação é que a distribuição de frequência empírica de cada variável
é aproximadamente simétrica. Novamente é um critério subjetivo e difícil de se verificar em termos
práticos. Porém, nesta etapa de análise exploratória onde não temos nenhuma suposição distribucional
o coeficiente de correlação de Pearson é uma boa indicação da correlação linear entre as variáveis.

O coeficiente de correlação de Spearman é parecido com o de Pearson porém, ao invés de


usar os valores das variáveis, usa apenas o seu ranking. Isso torna esse coeficiente mais robusto a va-
lores extremos. Já o coeficiente de Kendall é uma medida da dependência entre as duas observações
e, como o de Spearman, é baseado no ranking das variáveis. Os coeficientes de Spearman e Kendall
são chamados de não paramétricos justamente porque não são derivados de nenhuma distribuição de
probabilidade. Em termos práticos eles capturam a força da relação monotônica entre duas variáveis.
Uma recomendação geral é que se o tamanho da amostra é pequena o coeficiente de Kendall é indi-
cado por ser mais eficiente (menor incerteza). Para amostras grandes e distribuições razoavelmente

Ômega · Escola de Data Science omegadatascience.com.br


192 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

20000

15000
Renda

10000

5000

1 2 3 4 5
Engajamento

Figura 9.14: Diagrama de dispersão: renda mensal e engajamento.

simétricas use o de Pearson. Caso contrário use Spearman. É importante ressaltar que essas são re-
comendações práticas para o caso em que o interesse seja obter apenas um. Na prática você pode
facilmente calcular os três, conforme ilustrado no Código 9.14.

Código 9.14. Calculando os coeficientes de correlação de Pearson, Spearman e Kendall.

# Pearson
with(dados, cor(renda_mensal, engajamento, method = ”pearson”))

## [1] 0.065

# Spearman
with(dados, cor(renda_mensal, engajamento, method = ”spearman”))

## [1] 0.0311

# Kendall
with(dados, cor(renda_mensal, engajamento, method = ”kendall”))

## [1] 0.0214

Conforme a Figura 9.14 já havia indicado, a correlação entre as variáveis renda mensal e
engajamento é fraca (valor próximo de zero). Também vemos que o coeficiente de Pearson é um
pouco maior que o de Spearman que por sua vez é um pouco maior que o de Kendall. Em geral essa
ordem vai se manter para a maioria das análises de correlação que você fizer. Isso se deve pela forma
como cada coeficiente é construído. Não vamos entrar em detalhes nas equações, porém mantenha

Ômega · Escola de Data Science omegadatascience.com.br


9.3 193

(A) (B) (C)


14

40

40
12

20

20
f (x)

f (x)

f (x)
10

0
8

-20

-20
6

-10 -5 0 5 10 -10 -5 0 5 10 -10 -5 0 5 10


x x x

Figura 9.15: Exemplos de forma de relação entre variáveis quantitativas.

isso em mente e não se preocupe com o valor exato. O importante é a avaliação de existência ou não
de relação entre variáveis e qual a força desta associação.

Neste capítulo apresentamos uma visão geral das técnicas de estatística descritiva e explora-
tória. Começando pela classificação das variáveis, descrevemos como apresentar e resumir cada uma
delas, bem como, verificar as suas relações por meio das medidas resumo e opções gráficas mais simples
e conhecidas. Ressaltamos que o tópico de análise descritiva e exploratória é um campo sem fim e que
este capítulo apenas fornece o ferramental básico para uma análise mínima. No próximo Capítulo
vamos juntar tudo que aprendemos nos Capítulos anteriores em uma análise de dados real.

Ômega · Escola de Data Science omegadatascience.com.br


194 Capítulo 9. Estatística descritiva e exploratória com o tidyverse

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 10

Praticando com o R base

10.1 Análise exploratória de crimes contra criança e ado-


lescentes no Brasil
Para fecharmos este livro vamos apresentar uma análise completa que vai desde a coleta, ma-
nipulação, resumo de dados até a apresentação por meio de gráficos, tabelas e mapas.

Nosso exemplo corresponde a um conjunto de dados coletado do site tabsus, mantido pelo
Ministério da Saúde. Os dados referem-se a episódios de violência contra crianças e adolescentes
por ano, faixa etária e tipo de crime (violência sexual, assédio sexual, estupro, pornografia infantil e
atentado violento ao pudor). O conjunto de dados está disponível no link no formato .csv (comma-
separated value).

Os dados foram mantidos da forma mais crua possível para que você vivencie todos os desafios
nas etapas de importar, manipular, analisar e apresentar os resultados de uma análise de dados.

10.2 Importando o conjunto de dados


O arquivo com a base de dados que desejamos importar é chamado de ano-faixa-crime.csv.
Como o arquivo foi criado diretamente no R, ele usa o padrão inglês e portanto o caracter separador
é ,. Além disso, temos um título para cada coluna. O Código 10.1 ilustra como importar a base de
dados para o R.

Código 10.1. Importando o conjunto de dados.

dados <- read.table(”data/ano-faixa-crime.csv”, header = TRUE, sep = ”,”, quote = ””)

Se a leitura foi executada com sucesso você não deve receber nenhuma mensagem. Assim,
é hora de inspecionar o que foi carregado. Recomendamos usar a função str() para ter uma visão

195
196 Capítulo 10. Praticando com o R base

geral do arquivo de dados.

str(dados)

## ’data.frame’: 70115 obs. of 11 variables:


## $ cod : int 120020 130060 130260 130260 130260 130260 140010 150140 150140 150140 ...
## $ mun : chr ”Cruzeiro do Sul” ”Benjamin Constant” ”Manaus” ”Manaus” ...
## $ ano : int 2015 2015 2015 2015 2015 2015 2015 2015 2015 2015 ...
## $ mes : chr ”Set” ”Ago” ”Fev” ”Set” ...
## $ faixa_etaria : chr ”<1 Ano” ”<1 Ano” ”<1 Ano” ”<1 Ano” ...
## $ casos : int 1 1 1 1 1 1 1 1 1 2 ...
## $ violencia_sexual : chr ”Sim” ”Sim” ”Sim” ”Sim” ...
## $ assedio_sexual : chr ”Sim” ”Sim” ”Sim” ”Sim” ...
## $ estupro : chr NA NA NA NA ...
## $ pornografia_infantil: chr NA NA NA NA ...
## $ atentado_viol_pudor : chr NA NA NA NA ...

A função str() começa mostrando quantas observações e quantas colunas a base de dados
contém. Neste caso temos 70115 observações (linhas) e 11 variáveis (colunas). Na sequência é apre-
sentado o nome de cada coluna e o tipo de dado que ela representa. Neste exemplo, temos variáveis
do tipo int e chr que são abreviações dos tipos de vetores integer e character. Apesar do nome das
colunas ser auto explicativo é sempre interessante manter um dicionário da sua base de dados. Um
dicionário nada mais é do que uma lista com o nome de cada coluna e o que ela representa. Por
exemplo,

▶ cod: código do município onde o episódio aconteceu.


▶ mun: município onde o episódio aconteceu.
▶ ano: ano do episódio.
▶ mes: mês calendário do episódio.
▶ faixa_etaria: faixa etária da criança ou adolescente envolvida no episódio.
▶ casos: número de episódios.
▶ violencia_sexual_: indicadora (sim ou NA) se o episódio envolveu violência sexual.
▶ assedio_sexual: indicadora (sim ou NA) se o episódio envolveu assédio sexual.
▶ estupro: indicadora (sim ou NA) se o episódio envolveu estupro.
▶ pornografia_infantil: indicadora (sim ou NA) se o episódio envolveu pornografia infantil.
▶ atentado_viol_pudor: indicadora (sim ou NA) se o episódio envolveu atentado violento ao
pudor.

É importante notar que o mesmo episódio pode envolver mais de um tipo de crime. Cada
linha corresponde a características de episódios sendo que a coluna casos diz quantos episódios tive-
ram as características. Na colunas correspondentes aos crimes temos apenas os valores sim caso aquele
crime fez parte do episódio, caso contrário teremos o valor NA. Lembre-se, essa é uma base de dados
real e foi assim que a captura dos dados os armazenou.

Ao se deparar com um conjunto de dados como este precisamos nos perguntar o que quere-
mos mostrar/saber. Nem sempre o objetivo é claro e precisamos investigar os aspectos dos dados para
saber quais são as possibilidades. É neste momento que precisamos saber como manipular a base de

Ômega · Escola de Data Science omegadatascience.com.br


10.3 197

dados para entendê-la e investigar possíveis análises.

10.3 Preparando a base de dados


Seguindo os princípios do tidy data para manipular um conjunto de dados temos cinco ações
essenciais:

▶ Filtrar observações de acordo com os seus valores.


▶ Ordenar observações de acordo com os seus valores.
▶ Selecionar variáveis de acordo com o seu nome e/ou características.
▶ Criar novas variáveis a partir de variáveis já existentes.
▶ Resumir ou sumarizar dados. Essa ação é a mais complexa e em geral envolve o uso de medidas
estatísticas como média, mediana, desvio-padrão entre outros para criar resumo dos dados.

Vamos começar a explorar a nossa base de dados acessando as variáveis e verificando quais
são os seus possíveis valores. Por exemplo, podemos fazer uma tabela de frequência para saber a quais
anos os dados se referem e quantos registros temos em cada ano.

table(dados$ano)

##
## 2015 2016 2017 2018 2019
## 10973 11625 13872 16370 17275

Neste caso vemos que os dados são de 2015 a 2019 e o ano com maior número de registros é
o ano de 2018 com 17275 registros. É importante notar que o número de registros não é o número
de episódios, mas sim o número de episódios que foram devidamente reportados.

Neste exemplo, nós usamos o operador $ para acessar os dados da variável ano e a função
table() para obter a tabela de frequências. Podemos usar a mesma ideia para conhecer as outras
variáveis. Por exemplo, para a faixa etária temos

table(dados$faixa_etaria)

##
## <1 Ano 1-4 10-14 15-19 5-9
## 1759 11694 25312 15004 16346

Aqui temos um resultado interessante. A variável faixa etária tem uma ordenação natural,
porém da forma como a tabela foi feita, essa ordem não foi respeitada.

Para informar ao R que a variável faixa_etaria é um fator devemos converter a sua classe
para factor e indicar a sua ordem natural.

dados$faixa_etaria <- factor(dados$faixa_etaria,


levels = c(”<1 Ano”, ”1-4”, ”5-9”, ”10-14”, ”15-19”))
table(dados$faixa_etaria)

Ômega · Escola de Data Science omegadatascience.com.br


198 Capítulo 10. Praticando com o R base

##
## <1 Ano 1-4 5-9 10-14 15-19
## 1759 11694 16346 25312 15004

Deixamos como sugestão ao leitor investigar as outras variáveis da base de dados.

Com isso, temos uma ideia inicial dos dados. Mas para realmente fazer uma análise precisamos
definir qual será o nosso objetivo. Vamos supor que o objetivo da análise é comparar o número de
episódios de cada crime em cada estado por ano de ocorrência.

Assim, precisamos contar quantos episódios de cada crime ocorreu em cada estado e em cada
ano. Porém, não temos uma variável estado em nossa base de dados. Neste caso vamos precisar obter
esta informação por meio de outra base de dados. O arquivo Pop_2018.csv traz a lista de municipios
com a sua população estimada para 2018 e também a qual unidade federativa ele pertence. Vamos
importá-lo e ver o seu conteúdo

pop2018 <- read.table(”data/Pop_2019.csv”, header = TRUE,


colClasses = c(rep(”character”, 4), ”integer”),
sep = ”,”)

str(pop2018)

## ’data.frame’: 5570 obs. of 5 variables:


## $ UF : chr ”RO” ”RO” ”RO” ”RO” ...
## $ COD : chr ”11” ”11” ”11” ”11” ...
## $ COD_MUNI : chr ”00015” ”00023” ”00031” ”00049” ...
## $ MUNICIPIO: chr ”Alta Floresta D Oeste” ”Ariquemes” ”Cabixi” ”Cacoal” ...
## $ POP : int 22945 107863 5312 85359 16323 15882 7391 18331 32374 46174 ...

O conjunto de dados é bem simples e tem uma coluna chamada UF para representar a unidade
federativa. Além disso, temos duas colunas: uma chamada COD e outra chamada COD_MUNI que juntas
vão nos ajudar a unir as bases de dados pop2018 e dados. Neste passo precisamos fazer a junção das
duas bases de dados para sabermos a qual estado cada município pertence. Para isso vamos usar a
função merge(). Porém, antes disso, precisamos garantir que existe um código único para cruzar as
bases. O primeiro passo nesta direção é criar uma nova coluna em pop2018 juntando as colunas COD
e COD_MUNI.

pop2018$cod <- paste0(pop2018$COD, pop2018$COD_MUNI)

No conjunto de dados dados a coluna cod tem 6 dígitos, enquanto que juntando as colunas
COD e COD_MUNI temos 7 dígitos. Após uma busca na documentação das fontes dos dados percebemos
que o último dígito da coluna cod na base de dados pop2018 é desnecessário. Assim, precisamos
eliminá-lo para então poder fazer a junção. A função substring() nos permite extrair os seis primeiros
dígitos de uma string.

pop2018$cod <- substring(pop2018$cod, 1, 6)


head(pop2018[,c(1,4,6)])

Ômega · Escola de Data Science omegadatascience.com.br


10.3 199

## UF MUNICIPIO cod
## 1 RO Alta Floresta D Oeste 110001
## 2 RO Ariquemes 110002
## 3 RO Cabixi 110003
## 4 RO Cacoal 110004
## 5 RO Cerejeiras 110005
## 6 RO Colorado do Oeste 110006

Com as colunas de código único corretas precisamos pensar no tipo de junção que deseja-
mos fazer. No data.frame pop2018 temos todos os munícipios brasileiros. Por outro lado, no data.frame
dados temos apenas aqueles munícipios onde houve um episódio de crime contra criança ou adoles-
cente.

Neste caso é mais fácil primeiro calcularmos o número de episódios por tipo de crime, mu-
nicípio e ano. Assim, podemos resumir um pouco a base de dados antes de fazer a junção. Outro
aspecto complicador é que nós não temos números nas colunas que indicam os crimes. Assim, não
podemos simplesmente somar. A estratégia que vamos adotar aqui será a seguinte:

▶ Primeiro transformar cada coluna dos crimes em binárias (1 se o crime ocorreu e 0 caso contrá-
rio).
▶ Criar novas colunas multiplicando a indicadora de cada crime pela coluna casos.
▶ Fazer a agregação por municipio, ano e tipo de crime.

dados$violencia_sexual[dados$violencia_sexual == ”Sim”] <- 1


dados$violencia_sexual <- as.numeric(dados$violencia_sexual)*dados$casos

dados$assedio_sexual[dados$assedio_sexual == ”Sim”] <- 1


dados$assedio_sexual <- as.numeric(dados$assedio_sexual)*dados$casos

dados$estupro[dados$estupro == ”Sim”] <- 1


dados$estupro <- as.numeric(dados$estupro)*dados$casos

dados$pornografia_infantil[dados$pornografia_infantil == ”Sim”] <- 1


dados$pornografia_infantil <- as.numeric(dados$pornografia_infantil)*dados$casos

dados$atentado_viol_pudor[dados$atentado_viol_pudor == ”Sim”] <- 1


dados$atentado_viol_pudor <- as.numeric(dados$atentado_viol_pudor)*dados$casos

Temos as contagens de cada tipo de crime, porém para fazer a agregação o ideal é que haja
uma coluna com as observações de todos os crimes para que se torne mais fácil fazer a agregação por
crime, ou seja, precisamos que o conjunto de dados esteja no formato longo. Neste caso vamos fazer
manualmente para deixar o processo bem explícito.

Ômega · Escola de Data Science omegadatascience.com.br


200 Capítulo 10. Praticando com o R base

nomes <- c(”violencia_sexual”, ”assedio_sexual”,


”estupro”, ”pornografia_infantil”,
”atentado_viol_pudor”)
n <- dim(dados)[1]
dados_long <- data.frame(”cod” = rep(dados$cod, 5),
”mun” = rep(dados$mun, 5),
”ano” = rep(dados$ano, 5),
”contagem” = c(dados$violencia_sexual,
dados$assedio_sexual,
dados$estupro,
dados$pornografia_infantil,
dados$atentado_viol_pudor),
”crime” = rep(nomes, each = n))

Com os dados no formato longo, podemos finalmente fazer o resumo por ano, município e
tipo de crime.

resumo_casos <- aggregate(dados_long$contagem,


by = list(dados_long$cod, dados_long$ano, dados_long$crime),
FUN = function(x) sum(x, na.rm = TRUE))
names(resumo_casos) <- c(”cod”, ”ano”, ”crime”, ”contagem”)

Podemos fazer a junção com a base pop2018.

estado <- merge(pop2018, resumo_casos, by = ”cod”, all.x = TRUE)

Agora temos a coluna UF para finalmente fazer a agregação por estado, ano e tipo de crime.

estado <- aggregate(estado$contagem,


by = list(estado$UF, estado$ano, estado$crime),
FUN = function(x) sum(x, na.rm = TRUE))
names(estado) <- c(”UF”, ”ano”, ”crime”, ”contagem”)

Com os dados arrumados podemos pensar em formas de apresentá-los. Esta é a etapa da


análise descritiva e exploratória.

10.4 Análise descritiva e exploratória


Para evitar replicar as análises para cada ano vamos focar apenas em 2018.

dados <- subset(estado, ano == 2018)

Lembrando que o nosso objetivo é comparar os estados em relação ao número de episódios de


cada tipo de crime. Um gráfico de barras é uma ferramenta razoável para este objetivo. Por exemplo,
para o tipo de crime estupro, o gráfico é apresentado na Figura 10.1.

Ômega · Escola de Data Science omegadatascience.com.br


10.4 201

tab <- subset(dados, crime == ”estupro”)


tab <- tab[order(tab$contagem, decreasing = FALSE),]
par(mai=c(1,2,1,1))
barplot(tab$contagem, names.arg = tab$UF, main =””, horiz=TRUE, las = 1)

SP
PR
MG
RS
RJ
AM
PA
PE
DF
SC
GO
BA
ES
TO
CE
PI
MA
AC
MT
MS
AL
SE
RO
RN
PB
RR
AP

0 1000 2000 3000


Figura 10.1: Gráfico de barras para o crime estupro.

Temos um gráfico, mas o que exatamente esse gráfico está representando? Note que os
estados em que mais temos episódios são aqueles com maior população. Para termos uma análise que
leve isso em conta precisamos do tamanho da população. Para nossa sorte o data.frame pop2018 já
tem a população para o ano de 2018, porém por município. Assim, se somarmos a população de cada
município que compõe os estados, teremos a população do estado. Posteriormente, poderemos juntar

Ômega · Escola de Data Science omegadatascience.com.br


202 Capítulo 10. Praticando com o R base

com o data.frame tab e calcular a taxa de episódios, por exemplo, por cada 100.000 habitantes. Assim,
precisamos apenas juntar

pop_estado <- aggregate(pop2018$POP,


by = list(pop2018$UF),
FUN = function(x) sum(x, na.rm = TRUE))
names(pop_estado) <- c(”UF”, ”Populacao”)

Com a população de cada estado agora juntamos com os dados de episódios e calculamos a
taxa por cem mil habitantes.

tab <- merge(tab, pop_estado, by = ”UF”)


tab$taxa <- (tab$contagem/tab$Populacao)*100000

Finalmente, refazemos o gráfico de barras.

tab <- tab[order(tab$taxa, decreasing = FALSE),]


par(mai=c(1,2,1,1))
barplot(tab$taxa, names.arg = tab$UF, main =””, horiz=TRUE, las = 1)

Ômega · Escola de Data Science omegadatascience.com.br


10.4 203

AC
TO
AM
DF
PR
RR
PA
RS
ES
PE
SC
PI
MS
AP
RO
MG
RJ
MT
GO
SE
SP
AL
CE
MA
RN
BA
PB

0 5 10 15 20 25 30 35
Podemos notar que as taxas são consideravelmente diferentes. Não é de interesse entrar
em discussões a respeito dos dados, porém ressaltamos que as taxas são calculadas baseadas nos casos
reportados. Logo, estados que promovem um ambiente favorável ao reporte tendem a ter um número
de episódios maior que estados que não tem o aparato para tanto. Em resumo, muito cuidado ao
interpretar esses resultados.

O gráfico de barras é sem dúvida uma ferramenta muito útil. Entretanto, neste exemplo os
estados tem uma localização geográfica e seria interessante trazer esse componente espacial para a
análise descritiva. A forma mais simples de fazer isso é por meio de um mapa coropédico, ou seja, um
mapa que colore o poligono de cada estado de acordo com os valores das suas taxas de episódios.

O pacote geobr torna muito fácil fazer mapas em R uma vez que traz os mapas do Brasil por

Ômega · Escola de Data Science omegadatascience.com.br


204 Capítulo 10. Praticando com o R base

estado e também por município. O primeiro passo é instalar o pacote.

install.packages(”geobr”)

O pacote geobr tem muitas dependências e pode ser demorada a instalação de todas elas. Após
a instalação carregamos o pacote e o mapa do Brasil por estado.

library(geobr)
mapa_estado <- read_state(year = 2018)
names(mapa_estado)[2] <- ”UF”

O pacote geobr tem uma forma de implementação compatível com os pacotes do chamado
tidyverse. Portanto, para usá-lo de forma simples precisamos instalar e carregar os pacotes ggplot2
que será o responsável por desenhar o mapa e o pacote dplyr que fará a junção da base de dados tab
com o mapa.

library(ggplot2)
library(dplyr)
mapa <- left_join(mapa_estado, tab, by = ”UF”)
ggplot() +
geom_sf(data = mapa, aes(fill = taxa))+
scale_fill_distiller(palette = ”Blues”)

taxa
10°S
30

20

20°S 10

30°S

70°W 60°W 50°W 40°W 30°W

Ômega · Escola de Data Science omegadatascience.com.br


10.4 205

Com isso, encerramos este capítulo que teve como ideia fazer um apanhado geral de boa
parte dos conteúdos vistos anteriormente. De uma forma mais prática, focada em um problema
real, abordamos apenas os aspectos mais básicos da análise deste conjunto de dados. Convidamos o
leitor a explorar os outros tipos de crimes, anos e também análises que não foram feitas. Note que,
para chegar a um resultado apresentável, por mais simples que seja, foi necessário manipular, juntar
e resumir os diversos conjuntos de dados até a forma adequada para realizar uma análise descritiva.
Assim, ilustramos a maior parte do que precisa ser feito para trabalhar com dados em situações reais.

Ômega · Escola de Data Science omegadatascience.com.br


206 Capítulo 10. Praticando com o R base

Ômega · Escola de Data Science omegadatascience.com.br


Capítulo 11

Praticando com o tidyverse

11.1 Análise exploratória de crimes contra criança e ado-


lescentes no Brasil
Para fecharmos este livro vamos apresentar uma análise completa que vai desde a coleta, ma-
nipulação, resumo de dados até a apresentação por meio de gráficos, tabelas e mapas.

Nosso exemplo corresponde a um conjunto de dados coletado do site tabsus, mantido pelo
Ministério da Saúde. Os dados referem-se a episódios de violência contra crianças e adolescentes
por ano, faixa etária e tipo de crime (violência sexual, assédio sexual, estupro, pornografia infantil e
atentado violento ao pudor). O conjunto de dados está disponível no link no formato .csv (comma-
separated value).

Os dados foram mantidos da forma mais crua possível para que você vivencie todos os desafios
nas etapas de importar, manipular, analisar e apresentar os resultados de uma análise de dados.

11.2 Importando o conjunto de dados


O arquivo com a base de dados que desejamos importar é chamado de ano-faixa-crime.csv.
Como o arquivo foi criado diretamente no R, ele usa o padrão inglês e portanto o caracter separador
é ,. Além disso, temos um título para cada coluna. O Código 11.1 ilustra como importar a base de
dados para o R.

Código 11.1. Importando o conjunto de dados.

library(readr)
dados <- read_csv(”data/ano-faixa-crime.csv”)

Agora é hora de inspecionar o que foi carregado. Recomendamos usar a função str() para

207
208 Capítulo 11. Praticando com o tidyverse

ter uma visão geral do arquivo de dados.

str(dados)

## spec_tbl_df [70,115 x 11] (S3: spec_tbl_df/tbl_df/tbl/data.frame)


## $ cod : num [1:70115] 120020 130060 130260 130260 130260 ...
## $ mun : chr [1:70115] ”Cruzeiro do Sul” ”Benjamin Constant” ”Manaus” ”Manaus” ...
## $ ano : num [1:70115] 2015 2015 2015 2015 2015 ...
## $ mes : chr [1:70115] ”Set” ”Ago” ”Fev” ”Set” ...
## $ faixa_etaria : chr [1:70115] ”<1 Ano” ”<1 Ano” ”<1 Ano” ”<1 Ano” ...
## $ casos : num [1:70115] 1 1 1 1 1 1 1 1 1 2 ...
## $ violencia_sexual : chr [1:70115] ”Sim” ”Sim” ”Sim” ”Sim” ...
## $ assedio_sexual : chr [1:70115] ”Sim” ”Sim” ”Sim” ”Sim” ...
## $ estupro : chr [1:70115] NA NA NA NA ...
## $ pornografia_infantil: chr [1:70115] NA NA NA NA ...
## $ atentado_viol_pudor : logi [1:70115] NA NA NA NA NA NA ...
## - attr(*, ”spec”)=
## .. cols(
## .. cod = col_double(),
## .. mun = col_character(),
## .. ano = col_double(),
## .. mes = col_character(),
## .. faixa_etaria = col_character(),
## .. casos = col_double(),
## .. violencia_sexual = col_character(),
## .. assedio_sexual = col_character(),
## .. estupro = col_character(),
## .. pornografia_infantil = col_character(),
## .. atentado_viol_pudor = col_logical()
## .. )
## - attr(*, ”problems”)=<externalptr>

A função str() começa mostrando quantas observações e quantas colunas a base de dados
contém. Neste caso temos 70115 observações (linhas) e 11 variáveis (colunas). Na sequência é apre-
sentado o nome de cada coluna e o tipo de dado que ela representa. Neste exemplo, temos variáveis
do tipo num e chr que são abreviações dos tipos de vetores numeric e character. Apesar do nome das
colunas ser auto explicativo é sempre interessante manter um dicionário da sua base de dados. Um
dicionário nada mais é do que uma lista com o nome de cada coluna e o que ela representa. Por
exemplo,

▶ cod: código do município onde o episódio aconteceu.


▶ mun: município onde o episódio aconteceu.
▶ ano: ano do episódio.
▶ mes: mês calendário do episódio.
▶ faixa_etaria: faixa etária da criança ou adolescente envolvida no episódio.
▶ casos: número de episódios.
▶ violencia_sexual_: indicadora (sim ou NA) se o episódio envolveu violência sexual.
▶ assedio_sexual: indicadora (sim ou NA) se o episódio envolveu assédio sexual.
▶ estupro: indicadora (sim ou NA) se o episódio envolveu estupro.
▶ pornografia_infantil: indicadora (sim ou NA) se o episódio envolveu pornografia infantil.
▶ atentado_viol_pudor: indicadora (sim ou NA) se o episódio envolveu atentado violento ao

Ômega · Escola de Data Science omegadatascience.com.br


11.3 209

pudor.

É importante notar que o mesmo episódio pode envolver mais de um tipo de crime. Cada
linha corresponde a características de episódios sendo que a coluna casos diz quantos episódios tive-
ram as características. Na colunas correspondentes aos crimes temos apenas os valores sim caso aquele
crime fez parte do episódio, caso contrário teremos o valor NA. Lembre-se, essa é uma base de dados
real e foi assim que a captura dos dados os armazenou.

Ao se deparar com um conjunto de dados como este precisamos nos perguntar o que quere-
mos mostrar/saber. Nem sempre o objetivo é claro e precisamos investigar os aspectos dos dados para
saber quais são as possibilidades. É neste momento que precisamos saber como manipular a base de
dados para entendê-la e investigar possíveis análises.

11.3 Preparando a base de dados


Seguindo os princípios do tidy data para manipular um conjunto de dados temos cinco ações
essenciais:

▶ Filtrar observações de acordo com os seus valores.


▶ Ordenar observações de acordo com os seus valores.
▶ Selecionar variáveis de acordo com o seu nome e/ou características.
▶ Criar novas variáveis a partir de variáveis já existentes.
▶ Resumir ou sumarizar dados. Essa ação é a mais complexa e em geral envolve o uso de medidas
estatísticas como média, mediana, desvio-padrão entre outros para criar resumo dos dados.

Vamos começar a explorar a nossa base de dados acessando as variáveis e verificando quais
são os seus possíveis valores. Por exemplo, podemos fazer uma tabela de frequência para saber a quais
anos os dados se referem e quantos registros temos em cada ano.

table(dados$ano)

##
## 2015 2016 2017 2018 2019
## 10973 11625 13872 16370 17275

Neste caso vemos que os dados são de 2015 a 2019 e o ano com maior número de registros é
o ano de 2019 com 17275 registros. É importante notar que o número de registros não é o número
de episódios, mas sim o número de episódios que foram devidamente reportados.

Neste exemplo, nós usamos o operador $ para acessar os dados da variável ano e a função
table() para obter a tabela de frequências. Podemos usar a mesma ideia para conhecer as outras
variáveis. Por exemplo, para a faixa etária temos

table(dados$faixa_etaria)

Ômega · Escola de Data Science omegadatascience.com.br


210 Capítulo 11. Praticando com o tidyverse

##
## <1 Ano 1-4 10-14 15-19 5-9
## 1759 11694 25312 15004 16346

Aqui temos um resultado interessante. A variável faixa etária tem uma ordenação natural,
porém da forma como a tabela foi feita, essa ordem não foi respeitada.

Para informar ao R que a variável faixa_etaria é um fator devemos converter a sua classe
para factor e indicar a sua ordem natural.

dados$faixa_etaria <- factor(dados$faixa_etaria,


levels = c(”<1 Ano”, ”1-4”, ”5-9”, ”10-14”, ”15-19”))
table(dados$faixa_etaria)

##
## <1 Ano 1-4 5-9 10-14 15-19
## 1759 11694 16346 25312 15004

Deixamos como sugestão ao leitor investigar as outras variáveis da base de dados.

Com isso, temos uma ideia inicial dos dados. Mas para realmente fazer uma análise precisamos
definir qual será o nosso objetivo. Vamos supor que o objetivo da análise é comparar o número de
episódios de cada crime em cada estado por ano de ocorrência.

Assim, precisamos contar quantos episódios de cada crime ocorreu em cada estado e em cada
ano. Porém, não temos uma variável estado em nossa base de dados. Neste caso vamos precisar obter
esta informação por meio de outra base de dados. O arquivo Pop_2018.csv traz a lista de municipios
com a sua população estimada para 2018 e também a qual unidade federativa ele pertence. Vamos
importá-lo e ver o seu conteúdo

pop2018 <- read_csv(”data/Pop_2019.csv”)

str(pop2018)

## spec_tbl_df [5,570 x 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)


## $ UF : chr [1:5570] ”RO” ”RO” ”RO” ”RO” ...
## $ COD : num [1:5570] 11 11 11 11 11 11 11 11 11 11 ...
## $ COD_MUNI : chr [1:5570] ”00015” ”00023” ”00031” ”00049” ...
## $ MUNICIPIO: chr [1:5570] ”Alta Floresta D Oeste” ”Ariquemes” ”Cabixi” ”Cacoal” ...
## $ POP : num [1:5570] 22945 107863 5312 85359 16323 ...
## - attr(*, ”spec”)=
## .. cols(
## .. UF = col_character(),
## .. COD = col_double(),
## .. COD_MUNI = col_character(),
## .. MUNICIPIO = col_character(),
## .. POP = col_double()
## .. )
## - attr(*, ”problems”)=<externalptr>

O conjunto de dados é bem simples e tem uma coluna chamada UF para representar a unidade
federativa. Além disso, temos duas colunas: uma chamada COD e outra chamada COD_MUNI que juntas

Ômega · Escola de Data Science omegadatascience.com.br


11.3 211

vão nos ajudar a unir as bases de dados pop2018 e dados. Neste passo precisamos fazer a junção das
duas bases de dados para sabermos a qual estado cada município pertence. Para isso vamos usar a
função merge(). Porém, antes disso, precisamos garantir que existe um código único para cruzar as
bases. O primeiro passo nesta direção é criar uma nova coluna em pop2018 juntando as colunas COD
e COD_MUNI.

pop2018$cod <- paste0(pop2018$COD, pop2018$COD_MUNI)

No conjunto de dados dados a coluna cod tem 6 dígitos, enquanto que juntando as colunas
COD e COD_MUNI temos 7 dígitos. Após uma busca na documentação das fontes dos dados percebemos
que o último dígito da coluna cod na base de dados pop2018 é desnecessário. Assim, precisamos
eliminá-lo para então poder fazer a junção. A função str_sub(), do pacote stringr nos permite
extrair os seis primeiros dígitos de uma string.

library(stringr)
pop2018$cod <- str_sub(pop2018$cod, 1, 6)
head(pop2018[,c(1,4,6)])

## # A tibble: 6 x 3
## UF MUNICIPIO cod
## <chr> <chr> <chr>
## 1 RO Alta Floresta D Oeste 110001
## 2 RO Ariquemes 110002
## 3 RO Cabixi 110003
## 4 RO Cacoal 110004
## 5 RO Cerejeiras 110005
## 6 RO Colorado do Oeste 110006

Com as colunas de código único corretas precisamos pensar no tipo de junção que deseja-
mos fazer. No data.frame pop2018 temos todos os munícipios brasileiros. Por outro lado, no data.frame
dados temos apenas aqueles munícipios onde houve um episódio de crime contra criança ou adoles-
cente.

Neste caso é mais fácil primeiro calcularmos o número de episódios por tipo de crime, mu-
nicípio e ano. Assim, podemos resumir um pouco a base de dados antes de fazer a junção. Outro
aspecto complicador é que nós não temos números nas colunas que indicam os crimes. Assim, não
podemos simplesmente somar. A estratégia que vamos adotar aqui será a seguinte:

▶ Primeiro transformar cada coluna dos crimes em binárias (1 se o crime ocorreu e 0 caso contrá-
rio).
▶ Criar novas colunas multiplicando a indicadora de cada crime pela coluna casos.
▶ Fazer a agregação por municipio, ano e tipo de crime.

Ômega · Escola de Data Science omegadatascience.com.br


212 Capítulo 11. Praticando com o tidyverse

dados$violencia_sexual[dados$violencia_sexual == ”Sim”] <- 1


dados$violencia_sexual <- as.numeric(dados$violencia_sexual)*dados$casos

dados$assedio_sexual[dados$assedio_sexual == ”Sim”] <- 1


dados$assedio_sexual <- as.numeric(dados$assedio_sexual)*dados$casos

dados$estupro[dados$estupro == ”Sim”] <- 1


dados$estupro <- as.numeric(dados$estupro)*dados$casos

dados$pornografia_infantil[dados$pornografia_infantil == ”Sim”] <- 1


dados$pornografia_infantil <- as.numeric(dados$pornografia_infantil)*dados$casos

dados$atentado_viol_pudor[dados$atentado_viol_pudor == ”Sim”] <- 1


dados$atentado_viol_pudor <- as.numeric(dados$atentado_viol_pudor)*dados$casos

Temos as contagens de cada tipo de crime, porém para fazer a agregação o ideal é que haja
uma coluna com as observações de todos os crimes para que se torne mais fácil fazer a agregação por
crime, ou seja, precisamos que o conjunto de dados esteja no formato longo. Neste caso vamos fazer
manualmente para deixar o processo bem explícito.

nomes <- c(”violencia_sexual”, ”assedio_sexual”,


”estupro”, ”pornografia_infantil”,
”atentado_viol_pudor”)
n <- dim(dados)[1]
dados_long <- data.frame(”cod” = rep(dados$cod, 5),
”mun” = rep(dados$mun, 5),
”ano” = rep(dados$ano, 5),
”contagem” = c(dados$violencia_sexual,
dados$assedio_sexual,
dados$estupro,
dados$pornografia_infantil,
dados$atentado_viol_pudor),
”crime” = rep(nomes, each = n))

Com os dados no formato longo, podemos finalmente fazer o resumo por ano, município e
tipo de crime.

resumo_casos <- dados_long %>%


group_by(cod, ano, crime) %>%
summarise(contagem = sum(contagem, na.rm = TRUE))

resumo_casos$cod <- as.character(resumo_casos$cod)

Podemos fazer a junção com a base pop2018.

library(dplyr)
estado <- left_join(pop2018, resumo_casos, by = ”cod”)

Agora temos a coluna UF para finalmente fazer a agregação por estado, ano e tipo de crime.

estado <- estado %>%


group_by(UF, ano, crime) %>%
summarise(contagem = sum(contagem, na.rm = TRUE))

Ômega · Escola de Data Science omegadatascience.com.br


11.4 213

Com os dados arrumados podemos pensar em formas de apresentá-los. Esta é a etapa da


análise descritiva e exploratória.

11.4 Análise descritiva e exploratória


Para evitar replicar as análises para cada ano vamos focar apenas em 2018.

dados <- subset(estado, ano == 2018)

Lembrando que o nosso objetivo é comparar os estados em relação ao número de episódios de


cada tipo de crime. Um gráfico de barras é uma ferramenta razoável para este objetivo. Por exemplo,
para o tipo de crime estupro, o gráfico é apresentado na Figura 11.1.

library(ggplot2)

tab <- subset(dados, crime == ”estupro”)


tab <- tab[order(tab$contagem, decreasing = FALSE),]

ggplot(data=tab, aes(x=reorder(UF, contagem),


y=contagem)) +
geom_bar(stat=”identity”)+
ylab(””) +
xlab(””) +
coord_flip()

Temos um gráfico, mas o que exatamente esse gráfico está representando? Note que os
estados em que mais temos episódios são aqueles com maior população. Para termos uma análise que
leve isso em conta precisamos do tamanho da população. Para nossa sorte o data.frame pop2018 já
tem a população para o ano de 2018, porém por município. Assim, se somarmos a população de cada
município que compõe os estados, teremos a população do estado. Posteriormente, poderemos juntar
com o data.frame tab e calcular a taxa de episódios, por exemplo, por cada 100.000 habitantes. Assim,
precisamos apenas juntar

pop_estado <- pop2018 %>%


group_by(UF) %>%
summarise(Populacao = sum(POP, na.rm = TRUE))

Com a população de cada estado agora juntamos com os dados de episódios e calculamos a
taxa por cem mil habitantes.

tab <- inner_join(tab, pop_estado, by = ”UF”)


tab$taxa <- (tab$contagem/tab$Populacao)*100000

Finalmente, refazemos o gráfico de barras.

Ômega · Escola de Data Science omegadatascience.com.br


214 Capítulo 11. Praticando com o tidyverse

SP
PR
MG
RS
RJ
AM
PA
PE
DF
SC
GO
BA
ES
TO
CE
PI
MA
AC
MT
MS
AL
SE
RO
RN
PB
RR
AP
0 1000 2000 3000 4000

Figura 11.1: Gráfico de barras para o crime estupro.

tab <- tab[order(tab$taxa, decreasing = FALSE),]

ggplot(data=tab, aes(x=reorder(UF, taxa),


y=taxa)) +
geom_bar(stat=”identity”)+
ylab(””) +
xlab(””) +
coord_flip()

Ômega · Escola de Data Science omegadatascience.com.br


11.4 215

AC
TO
AM
DF
PR
RR
PA
RS
ES
PE
SC
PI
MS
AP
RO
MG
RJ
MT
GO
SE
SP
AL
CE
MA
RN
BA
PB
0 10 20 30

Podemos notar que as taxas são consideravelmente diferentes. Não é de interesse entrar
em discussões a respeito dos dados, porém ressaltamos que as taxas são calculadas baseadas nos casos
reportados. Logo, estados que promovem um ambiente favorável ao reporte tendem a ter um número
de episódios maior que estados que não tem o aparato para tanto. Em resumo, muito cuidado ao
interpretar esses resultados.

O gráfico de barras é sem dúvida uma ferramenta muito útil. Entretanto, neste exemplo os
estados tem uma localização geográfica e seria interessante trazer esse componente espacial para a
análise descritiva. A forma mais simples de fazer isso é por meio de um mapa coropédico, ou seja, um
mapa que colore o poligono de cada estado de acordo com os valores das suas taxas de episódios.

O pacote geobr torna muito fácil fazer mapas em R uma vez que traz os mapas do Brasil por
estado e também por município. O primeiro passo é instalar o pacote.

install.packages(”geobr”)

O pacote geobr tem muitas dependências e pode ser demorada a instalação de todas elas. Após
a instalação carregamos o pacote e o mapa do Brasil por estado.

library(geobr)
mapa_estado <- read_state(year = 2018)
names(mapa_estado)[2] <- ”UF”

Ômega · Escola de Data Science omegadatascience.com.br


216 Capítulo 11. Praticando com o tidyverse

O pacote geobr tem uma forma de implementação compatível com os pacotes do chamado
tidyverse. Portanto, para usá-lo de forma simples precisamos instalar e carregar os pacotes ggplot2
que será o responsável por desenhar o mapa e o pacote dplyr que fará a junção da base de dados tab
com o mapa.

library(ggplot2)
library(dplyr)
mapa <- left_join(mapa_estado, tab, by = ”UF”)
ggplot() +
geom_sf(data = mapa, aes(fill = taxa))+
scale_fill_distiller(palette = ”Blues”)

taxa
10°S
30

20

20°S 10

30°S

70°W 60°W 50°W 40°W 30°W

Com isso, encerramos este capítulo que teve como ideia fazer um apanhado geral de boa
parte dos conteúdos vistos anteriormente. De uma forma mais prática, focada em um problema
real, abordamos apenas os aspectos mais básicos da análise deste conjunto de dados. Convidamos o
leitor a explorar os outros tipos de crimes, anos e também análises que não foram feitas. Note que,
para chegar a um resultado apresentável, por mais simples que seja, foi necessário manipular, juntar
e resumir os diversos conjuntos de dados até a forma adequada para realizar uma análise descritiva.
Assim, ilustramos a maior parte do que precisa ser feito para trabalhar com dados em situações reais.

Ômega · Escola de Data Science omegadatascience.com.br


11.4 217

Ômega · Escola de Data Science omegadatascience.com.br

Você também pode gostar