Linguagem R: Um Tutorial Interativo

Este é um trabalho em construção associado a um projeto de pesquisa desenvolvido no âmbito do Mestrado Profissional em Administração do IFMG - Campus Formiga. Ele será continuamente modificado nos próximos meses. Agradecemos o envio de sugestões e correções.

Data de Publicação

5 fevereiro 2024

1 Introdução

Seja bem-vindo(a) a “Linguagem R: Um Tutorial Interativo”!

Este tutorial foi criado especialmente para estudantes e profissionais das áreas de administração, economia e contabilidade, que buscam aprimorar suas habilidades na análise e modelagem de dados com a linguagem R.

O que você encontrará neste tutorial?:

  • Uma introdução completa à linguagem R, incluindo Tipos e Estruturas de Dados. Técnicas para sumarização, visualização e modelagem de dados.

  • Você não precisará instalar nenhum software em seu computador! Por que utilizaremos WebR, que é uma versão da linguagem R compilada para navegadores, que possibilita a execução de código R no seu navegador, sem a necessidade de um servidor para executar o código.

  • Aplicações práticas da linguagem R em estudos de caso reais nas áreas de administração, economia e contabilidade.

Público-alvo:

  • Alunos do Mestrado Profissional em Administração e do Bacharelado em Administração do IFMG - Campus Formiga.

  • Estudantes e profissionais de administração, economia e contabilidade que desejam aprender a utilizar a linguagem R para a análise de dados.

Pré-requisitos:

  • Acesso a um computador
  • Acesso à internet

Esperamos que este tutorial seja uma ferramenta relevante para o seu aprendizado e desenvolvimento profissional.

2 Algumas dicas

Uma pergunta que nos é feita com frequência é “qual é a melhor forma de aprender R?”. Infelizmente, não temos uma resposta pronta para essa pergunta, pois, em geral, todos tendem a aprender R (ou qualquer outra linguagem) à sua maneira e no seu próprio ritmo.

Dito isso, aqui estão algumas coisas a ter em mente que podem ajudar:

  • Use R com frequência e regularmente - encontre qualquer desculpa para ativar o interpretador da linguagem R ou algum Ambiente de Desenvolvimento Integrado adequado para a linguagem R.

  • Aprender R não é um teste de memória. Uma das vantagens de uma linguagem como R é que você sempre terá seu código para se referir quando inevitavelmente esquecer como fazer algo.

  • Você não precisa saber tudo sobre R para usá-la de forma produtiva. Se você ficar preso, pesquise no Google, não é trapaça, e escrever uma boa consulta de pesquisa é uma habilidade muito importante. Apenas certifique-se de verificar cuidadosamente se o código que você encontra está fazendo o que você quer que ele faça.

  • Se você se encontrar olhando para o código por horas tentando descobrir por que não está funcionando, então faça uma pausa. Perdemos a conta do número de vezes que conseguimos identificar erros quase imediatamente depois de voltar de uma pequena pausa.

  • Em qualquer linguagem e em R, há muitas maneiras de resolver um problema específico. Se o seu código não se parece com o de outra pessoa, mas faz o que você quer que ele faça em um tempo razoável e de forma robusta, então não se preocupe com isso - trabalho feito.

  • Relacionado ao ponto anterior, lembre-se de que R é apenas uma ferramenta para ajudá-lo a responder às suas perguntas interessantes. Embora possa ser divertido mergulhar em uma linguagem, não perca de vista o que é importante - sua(s) pergunta(s) de pesquisa e seus dados. Nenhuma quantidade de habilidade usando R ajudará se sua pergunta for vaga e os dados forem de baixa qualidade.

  • Aceite que haverá momentos em que as coisas ficarão um pouco difíceis ou frustrantes, isso acontece com todos nós. Tente aceitar esses períodos como parte do processo natural de aprender uma nova habilidade, lembre-se de que o tempo e a energia que você investir agora serão mais do que pagos em um futuro não muito distante.

3 A Linguagem R

Conforme VENABLES; SMITH; R CORE TEAM (2023), a linguagem R pode ser considerada uma implementação da linguagem S, que foi desenvolvida nos Laboratórios Bell por Rick Becker, John Chambers e Allan Wilks, e que também serviu como base para os sistemas S-PLUS.

A linguagem S foi iniciada em 1976 como uma linguagem para análise estatística originalmente implementada como um conjunto de bibliotecas Fortran. O objetivo da linguagem S, conforme expresso por John Chambers, era “traduzir ideias em software, de forma rápida e fiel”.

A evolução da linguagem S é caracterizada por três livros de John Chambers e coautores. Para R, a referência básica é BECKER; CHAMBERS; WILKS (1988). As novas características da versão de 1991 da linguagem S são abordadas em CHAMBERS; HASTIE (1992). Os métodos e classes formais do pacote methods são baseados em CHAMBERS (1998).

R é uma linguagem de programação para computação estatística e visualização de dados, sendo adotada em diversas áreas do conhecimento e na indústria. A linguagem principal é aumentada por um grande número de pacotes, os quais contém, em geral, código reutilizável, documentação e dados.

A linguagem R é de código aberto e livre. É licenciada pelo Projeto GNU e disponível sob a General Public Licnce (GPL). A linguagem é escrita principalmente em C, Fortran e R. Existem executáveis pré-compilados para vários sistemas operacionais.

A sessão de informações a seguir contém um breve histórico do desenvolvimento das linguagens S e R, clique na caixa para que o conteúdo seja expandido.

  • 1976: A linguagem S é iniciada nos Laboratórios Bell por Rick Becker, John Chambers e Allan Wilks como uma linguagem para análise estatística originalmente implementada como um conjunto de bibliotecas Fortran.

  • 1988: a linguagem S é reescrita em C e começa a se parecer com o sistema atual (S3).

  • 1991: A linguagem R é iniciada pelos professores Ross Ihaka e Robert Gentleman como uma linguagem de programação para ensinar estatística introdutória na Universidade de Auckland, Nova Zelândia. A linguagem foi inspirada na linguagem S, com a maioria dos programas S capazes de ser executadas inalteradas em R. A linguagem também foi inspirada no escopo léxico da linguagem Scheme, permitindo variáveis locais.

  • 1993: Primeiro anúnico da linguagem R ao Público.

  • 1995: Martin Machler convence Ross e Robert a usarem a licença GNU para tornar R um software Livre.

  • 1997: The R Core Group é criado. Este grupo controla o código fonte da linguagem.

  • 1998: A versão 4 (S4) da linguagem S foi lançada, esta é a versão que usada atualmente hoje. John Chambers recebe o Association for Computing Machinery’s Software System Award pela linguagem S.

  • 2000: A versão R 1.0.0 é lançada.

  • 2023: R version 4.3.2 é lançada.

4 WebR: R no Navegador

Neste tutorial utilizaremos WebR. WebR é uma versão da linguagem R compilada para navegadores e Node.js usando WebAssembly, via Emscripten.

O WebR possibilita a execução de código R no navegador, sem a necessidade de um servidor para executar o código. O interpretador R é executado diretamente no seu navegador.

Na sequência deste tutorial, você irá encontrar diversas “caixas” como a exibida a seguir. Na verdade, essa “caixa” é a interface de linha de comando da linguagem R, que em geral recebe o nome de console.

Para executar um código, basta clicar em Run Code. Experimente executar o código a seguir:

Você pode editar os comandos exibidos no console e testar outros, faça alguns experimentos, analise e tente entender os resultados, é assim que se aprende.

Na linguagem R, o símbolo # representa comentários da linguagem, assim, tudo que está após # é ignorado quando executamos o código. Na sessão de dicas a seguir, explicamos a importância de inserirmos comentários em nossos códigos R e damos dicas sobre como usá-los.

Enumeramos a seguir algumas razões da importância de inserir comentários em códigos da linguagem R (e de qualquer linguagem de programação).

  1. Compreensão:
  • Explicam o que o código faz: facilitam o entendimento do código para você mesmo e para outros, mesmo após um tempo.

  • Descrevem a lógica: esclarecem as decisões e os métodos utilizados no código.

  1. Manutenção:
  • Facilitam a atualização: tornam o código mais fácil de modificar e adaptar no futuro.

  • Documentam o código: servem como um guia para quem precisa entender ou modificar o código.

  1. Depuração:
  • Identificam problemas: facilitam a localização de erros e falhas no código.

  • Ajudam na correção: fornecem informações sobre o que o código deveria fazer e como ele está funcionando.

  1. Colaboração:
  • Melhoram a comunicação: permitem que outros programadores compreendam suas ideias e intenções.

  • Facilitam o trabalho em equipe: tornam o código mais legível e acessível para todos os envolvidos.

Dicas para comentários:

  • Use frases curtas e concisas.
  • Evite comentários óbvios ou redundantes.
  • Explique o “porquê”, não apenas o “como”.
  • Atualize os comentários ao modificar o código.

Vários pacotes R também foram portados para uso com o webR e podem ser carregados da maneira usual usando a função library().

No exemplo que veremos na sequência, utilizamos o pacote xts, que é um pacote que define uma classe muito útil para a representação de dados em séries temporais, que é um dos tipos de dados mais comuns nas áreas de administração, contabilidade e economia.

O código do exemplo consiste em simular um processo aleatório conhecido como movimento browniano, que representa muito bem o comportamento de ativos financeiros arriscados, e define a série simulada como um objeto da classe xts, em seguida, fazemos um gráfico de linha dos preços simulados.

Fique calmo, ao longo do tutorial estudaremos com certo detalhe todos os conceitos destacados neste exemplo.

Execute o código do exemplo clicando em Run Code:

Repare quantos procedimentos relativamente sofisticados podem ser realizados com apenas 3 linhas de código!

Script

O código que você acabou de executar é um exemplo de um script, ainda que muito pequeno em termos do número de linhas de código. Um script em linguagem R é um arquivo contendo uma sequência de comandos ou instruções que são executados de maneira sequencial quando o script é executado.

Pode-se pensar em um script como uma receita passo a passo para realizar tarefas específicas utilizando a linguagem R. Em alguns exercícios, você será solicitado a criar um script, agora já sabe que você precisa criar uma sequência de comandos, de forma sequencial para realizar uma tarefea específica.

5 Objetos

Para entender os cálculos em R, dois slogans são úteis: 1) Tudo o que existe é um objeto e 2) Tudo o que acontece é uma chamada de função. — John Chambers (tradução livre).

No coração de quase tudo o que você fará (ou provavelmente fará) em R está o conceito de que tudo na linguagem R é um objeto. Isso não significa que estamos fazendo programação orientada a objetos (POO) sobre a qual você pode ter ouvido falar, um paradigma de programação associado a algunas linguagems, como C++. Objetos R não são como objetos C++.

Esses objetos podem ser quase qualquer coisa, desde um único número ou sequência de caracteres (como uma palavra) até estruturas muito complexas, como o resultado de um gráfico, um resumo de sua análise estatística ou um conjunto de comandos R que executam uma tarefa específica.

Entender como você cria objetos e atribui valores a objetos é uma das chaves para entender a linguagem.

Objetos R não são como objetos C++. Em R, tudo é um objeto. Em C++, apenas coisas muito especiais que são instâncias de classes C++ criadas com o operador new são objetos. Em R, números, funções, bits da linguagem R (expressões R) também são objetos. Em C++, essas coisas definitivamente não são objetos. A linguagem de programação C não tem nenhum objeto, seja no sentido C++ ou no sentido R.

R não é uma linguagem particularmente orientada a objetos. R tem três sistemas de programaçõa orientada a objetos diferentes em seu núcleo (Base R): S3, S4 e R6. Além disso, há vários outros sistemas de POO em pacotes encontrados no CRAN. Mas nenhum desses sistemas de POO funciona como o sistema de programação orientada a objetos de C++. Além disso, nenhum dos sistemas de POO é necessário para a maioria da programação R.

R é uma linguagem funcional. Isso significa que as funções são objetos de primeira classe com os quais você pode fazer qualquer coisa que possa fazer com qualquer outro objeto. Você pode atribuí-los a nomes de variáveis, ou pode atribuí-los para serem partes de objetos compostos (como listas), ou pode usá-los como argumentos ou valores de outras funções.

Neste aspecto, R se parece muito com Lisp, Scheme, Haskell, Scala, Clojure e com outras linguagens de programação funcionais.

5.1 Criando objetos

Para criar um objeto, simplesmente damos um nome ao objeto. Podemos então atribuir um valor a este objeto usando o operador de atribuição <-.

O operador de atribuição é um símbolo composto composto por um símbolo ’menor que < e um hífen -.

No código acima, criamos um objeto chamado meu_obj e atribuímos a ele o número 48 usando o operador de atribuição. Ao executar o código acima, nenhuma informação é exibida, pois apenas foi feita uma atribuição, caso houvesse um erro seria exibida uma mensagem de erro.

Você provavelmente descobrirá que que ambos os operadores <- e =, são usados para atribuir valores a variáveis, e isso tende a causar alguma confusão.

Tecnicamente, R irá aceitar qualquer um deles ao atribuir variáveis, entretanto, isso é considerado uma má prática e nós o desencorajamos a usar = como um operador de atribuição. Podem ocorrer problemas com = no uso de algumas funções em alguns contextos.

Ambientes de Desenvolvimento integrado, como o RStudio, oferecem atalhos para a inserção de <-. No RStudio, para inserir <-, basta clicar em Alt e -, em sequência.

Para visualizar o valor do objeto, basta digitar o nome do objeto e executá-lo. Em Windows/Linux, aperte Enter, para MacOs: aperte Return

Em nosso caso, clique em Run Code em uma janela de comando contendo o nome do objeto:

Outras possibilidades para visualizar o conteúdo de um objeto são, usar a função print:

Ou, envolver a expressão que criou o objeto com parênteses:

Podemos utilizar a função ls() (de list) para listar os nomes dos objetos ativos no ambiente atual:

Existem muitos tipos diferentes de valores que você pode atribuir a um objeto. Por exemplo:

Criamos um objeto chamado meu_obj2 e atribuímos a ele o texto "R é legal", que é uma string de caracteres. Observe que envolvemos o texto entre aspas. Se você esquecer de usar as aspas, receberá uma mensagem de erro:

Nosso workspace agora contém os dois objetos que criamos até agora:

Para alterar o valor de um objeto existente, simplesmente atribuímos um novo valor a ele. Por exemplo, para alterar o valor de meu_obj2 de “R é legal” para o número 1024 fazemos:

Depois de criarmos alguns objetos, podemos fazer coisas com nossos objetos. Por exemplo, o código a seguir cria um novo objeto meu_obj3 e atribui a ele o valor de meu_obj adicionado a meu_obj2, que é 1072 (48 + 1024 = 1072):

Observe que, para exibir o valor de meu_obj3, também precisamos escrever o nome do objeto.

O código acima funciona porque os valores de meu_obj e meu_obj2 são numéricos (ou seja, números). Se você tentar fazer isso com objetos com valores de caracteres, receberá uma erro:

A mensagem de erro está essencialmente dizendo que um ou ambos os objetos, x e/ou y, não é um número e, portanto, não pode ser somado.

Quando você começa a aprender R, lidar com Error (mensagens de erro) e warnings (avisos) pode ser frustrante, pois muitas vezes são difíceis de entender: o que é um argumento? O que é um operador binário?.

Uma maneira de descobrir mais informações sobre um erro específico é pesquisar no Google uma versão generalizada da mensagem de erro. Para o erro acima, tente pesquisar no Google non-numeric argument to binary operator erro + R ou commom r error messages.

Outra mensagem de erro que você receberá bastante quando começar a usar R pela é:

Error: object 'XXX' not found. 

Por exemplo, dê uma olhada no código abaixo:

R retorna uma mensagem de erro porque ainda não criamos (definimos) o objeto no_obj. Outra pista de que há um problema com este código é que, se você verificar seu ambiente, verá que o objeto my_obj4 não foi criado:

Podemos apagar os objetos criados anteriormente na sessão usando a função rm() (de remove):

Ao apagar um objeto, não será mais possível efetuar operações com o mesmo. Para isso, será necssário criar novamente o objeto. Vejamos se os objetos foram apagados:

O resultado character(0) indica que não há nenhum objetivo ativo na sessão.

R é uma linguagem de programação com tipagem dinâmica (dynamic typing), ou fracamente tipada (weakly typed). Isso significa duas coisas basicamente:

  • Ao contrário de C e C++, você não precisa “declarar” o tipo de objeto que está sendo criado ou utilizado.

  • Não é necessário compilar código R como em C e C++. Você pode simplesmente digitar R e ver o que acontece.

Isso torna a linguagem R infinitamente mais fácil de programar do que em C/C++. A principal desvantagem dessa facilidade é a velocidade de execução do código, o que pode ser imperceptível em muitos casos. Ainda assim, R é uma linguagem muito poderosa e pode ser facilmente estendida e combinada com códigos escritos em C/C++, Java, Fortran, Python entre outras.

5.2 Nomeando objetos

Nomear seus objetos é uma das coisas mais difíceis que você fará em R, estamos falando sério. Idealmente, seus nomes de objetos devem ser curtos e informativos, o que nem sempre é fácil.

Se você precisar criar objetos com várias palavras em seu nome, use um sublinhado ou um ponto entre as palavras ou capitalize as diferentes palavras (estilo chamado camel case). Nós preferimos usar o estilo camel case neste tutorial.

Recomendamos a leitura das dicas para nomear objetos contidas na seção de dicas a seguir. Clique na caixa para expandir seu conteúdo.

1. Descritivo e informativo:

  • Use nomes que descrevam claramente o conteúdo do objeto.
  • Evite abreviações e termos técnicos obscuros.
  • Exemplos:
    • dados_clientes
    • modelo_regressao_linear
    • media_salarial_por_genero

-2. Consistente e conciso:

  • Use um padrão de nomenclatura consistente para objetos relacionados.
  • Evite nomes muito longos ou redundantes.
  • Exemplos:
    • df_clientes, df_vendas, df_produtos
    • media_idade, mediana_idade, desvio_padrao_idade

3. Legível e Fácil de lembrar:

  • Use nomes que sejam fáceis de ler e lembrar.
  • Evite caracteres especiais e símbolos.
  • Exemplos:
    • lista_compras
    • matriz_covariância
    • funcao_calcula_media

5.3 Maus exemplos de nomes de objetos em R:

  • Nomes muito curtos ou genéricos: x, y, data, df.

  • Nomes com abreviações ou termos técnicos obscuros: reg_lin, coef_est, rmse

  • Nomes inconsistentes: clientes_df, vendas_data, produtos_dataFrame

  • Nomes ilegíveis ou com caracteres especiais: $#dados, média_idade_2023, função_complexa

Dicas para escolher bons nomes de objetos:

  • Pense no que o objeto representa e como ele será usado.
  • Use um nome que seja informativo e descritivo.
  • Seja consistente no uso de um estilo, recomendamos o snake_case ou CamelCase.
  • Evite nomes muito longos, redundantes ou com caracteres especiais.

Lembre-se:

  • Bons nomes de objetos facilitam a leitura, o entendimento e a manutenção do seu código R.

  • Invista tempo na escolha de nomes adequados para seus objetos.

  • Recursos adicionais:

6 Operadores e Funções Matemáticas

Alguns dos principais operadores e funções matemáticas da linguagem R são descritos na Tabela 1.

Tabela 1. Alguns Operadores e Funções Matemáticas
operacao sintaxe
Adição +
Subtração -
Multiplicação *
Divisão /
Potenciação ^ ou **
Logaritmo Natural log()
Exponencial exp()
Valor absoluto abs()
Raíz Quadrada sqrt()
Resto de Divisão %%
Quociente %/%

Recomendamos fortemente que você estude a sessão de informações a seguir sbore o uso de funções em R, será importante para você entender o uso das funções matemáticas apresentadas nesta sessão. Clique na caixa a seguir para que o conteúdo seja expandido.

  1. Sintaxe básica:

Em R, a chamada de uma função é realizada através da sintaxe nome_da_funcao(argumentos).

  • Exemplo: log(10) utiliza a função log para calcular o logaritmo natural de 10.
  1. Argumentos:

Funções em R podem ter argumentos, que são parâmetros fornecidos para realizar operações específicas.

Exemplos incluem x em log(x) ou x em exp(x).

  1. Argumentos padrão:

Muitas funções têm argumentos padrão, permitindo que sejam omitidos se desejar utilizar os valores padrão.

Exemplo: round(3.1415, digits = 0) pode ser simplificado para round(3.1415), pois o valor padrão do argumento digits é definido como sendo zero.

É fundamental estudar a documentação da função utilizada para saber quais são seus argumentos e quais os argumentos contém valores padrão.

  1. Ajuda e documentação:

Para obter informações detalhadas sobre uma função, utilize ?nome_da_funcao ou help(nome_da_funcao). Isso oferece descrições, exemplos e informações sobre cada argumento.

  1. Funções vetoriais:

Muitas funções em R são vetoriais, o que significa que podem operar em vetores sem a necessidade de loops.

Exemplo: sqrt(c(1, 4, 9)) calcula a raiz quadrada de cada elemento do vetor.

  1. Funções de ordem superior:

R suporta funções de ordem superior, permitindo a passagem de funções como argumentos para outras funções.

Exemplo: sapply(data, mean) aplica a função mean a cada coluna de um data frame.

Ao explorar funções internas em R, é crucial consultar a documentação associada para compreender completamente seus recursos. Experimentar com diferentes argumentos e entender o comportamento da função ajuda a utilizar eficazmente as poderosas funcionalidades disponíveis na linguagem.

Vejamos alguns exemplos:

  • Adição:
  • Subtração
  • Multiplicação
  • Divisão
  • Potenciação
  • Logaritmo Natural: use a função log()
  • Logaritmo na base 10: use a função log10()

Na verdade pode-se calcular o logaritmo de um número em uma determinada base usando o argumento base da função log:

  • Exponencial: use a função exp()
  • Raíz Quadrada: use a função sqrt()
  • Valor absoluto (ou módulo): use a função abs()
  • Arredondamento: use a função round(x, digits = 0)

A função round arredonda os valores em seu primeiro argumento (x) para o número especificado de casas decimais:

Por padrão, o argumento digits = 0

  • Resto da divisão

o operador %%é usado para calcular o resto da divisão entre dois valores.

  • Divisão Inteira

P operador %/% é usado para realizar a divisão inteira entre dois valores. A divisão inteira é diferente da divisão normal (operador /) porque o resultado é sempre um número inteiro, e a parte decimal é truncada:

6.1 Precedência de Operações Aritméticas

A linguagem R segue regras específicas de precedência de operações aritméticas para determinar a ordem em que as operações são avaliadas. A precedência refere-se à prioridade que cada operador tem em relação aos outros.

A seguir são descritas as principais regras de precedência na linguagem R, da mais alta para a mais baixa:

  1. Parênteses:
    • As operações dentro de parênteses têm a mais alta prioridade.
    • Quando parênteses são usados, as operações dentro deles são avaliadas primeiro.
  2. Potenciação:
    • A potenciação tem a segunda maior prioridade.
    • Por exemplo, 2^3 é avaliado antes de outras operações.
  3. Multiplicação e Divisão:
    • Multiplicação e divisão têm a mesma prioridade e são avaliadas da esquerda para a direita. Veja dois exemplos:

No primeiro exemplo, a multiplicação é realizada antes da divisão, resultando em 1.5. No segundo exemplo, a divisão é realizada antes da multiplicação, resultando em 2.666667.

  1. Adição e Subtração:
    • Adição e subtração têm a menor prioridade entre as operações aritméticas e também são avaliadas da esquerda para a direita.

Ao usar expressões aritméticas em R, é importante entender essas regras de precedência para garantir que as operações sejam avaliadas na ordem desejada. Se necessário, o uso de parênteses pode ser empregado para explicitamente indicar a ordem de avaliação desejada.

Por exemplo:

Neste caso, a exponenciação (4^2) será avaliada primeiro, seguida pela multiplicação (3 * 16). Se a ordem desejada for diferente, parênteses podem ser usados para modificar a precedência:

Nesse caso, a adição (2 + 3) é avaliada primeiro devido aos parênteses.

6.1.1 O que é um número de ponto flutuante?

Em qualquer linguagem de programação, os dados são armazenados pelo computador na memória usando valores binários. Um valor binário tem apenas dois estados possíveis, 1 e 0. Na memória do computador, estes estados representam a presença ou ausência de carga elétrica, portanto também estão ON e OFF.

Um número de ponto flutuante é um tipo de dado numérico que representa números reais em um computador usando notação científica binária, ou seja, na base 2, assim, números são representados apenas por 1 e 0. O nome ponto flutuante refere-se à vírgula decimal, que pode “flutuar” para diferentes posições dentro do número. Isso permite representar uma ampla gama de valores numéricos, tanto muito grandes quanto muito pequenos.

A representação de números em ponto flutuante é fundamental para o funcionamento dos computadores. Essa representação permite armazenar e manipular números reais com diferentes magnitudes e precisões.

Por exemplo, podemos ver o número 42 na tela, mas isso é graças ao computador que traduz o que foi armazenado no que esperamos ver. Isto pode é extremamente útil, mas também um tanto perigoso, como discutiremos a seguir.

6.1.2 Importância de entender a representação de números

Compreender como os números são representados em um computador é fundamental para:

  • Interpretar os resultados de cálculos.
  • Evitar erros de arredondamento e perda de precisão.
  • Escolher o tipo de dado numérico adequado para cada situação.

6.1.3 Padrão IEEE 754

O padrão IEEE 754 define um formato binário para representar números de ponto flutuante. Este padrão é utilizado pela maioria dos computadores e garante a interoperabilidade entre diferentes sistemas.

O padrão define diferentes tipos de dados de ponto flutuante, como float, double e long double, com diferentes precisões e faixas de valores.

As arquiteturas de computadores de 32 e 64 bits diferem na forma como representam números de ponto flutuante, impactando a precisão, a faixa de valores e o desempenho das operações matemáticas.

  • Padrão IEEE 754 - precisão simples (32 bits):

Nesta arquitetura, um número de ponto flutuante é composto por três partes:

  • Sinal: Indica se o número é positivo ou negativo (1 bit).

  • Expoente: Determina a ordem de grandeza do número (8 bits).

  • Mantissa: Representa a parte decimal do número (23 bits).

  • Padrão IEEE 754 - precisão dupla (64 bits):

Nesta arquitetura, um número de ponto flutuante também é composto por três partes, mas há diferenças:

  • Sinal: Indica se o número é positivo ou negativo (1 bit).

  • Expoente: Determina a ordem de grandeza do número (11 bits).

  • Mantissa: Representa a parte decimal do número (52 bits em 32 bits).

6.1.4 Consequências

Um computador tem uma capacidade limitada para armazenar informações, inclusive números, cuja representação é definida pelo Padrão IEEE 754. Além disso, muitos números decimais não possuem uma representação binária exata.

Assim, coisas estranhas e problemas graves podem ocorrer há um cientista de dados iletrado na representaçào em ponto flutuante.

Por exemplo: Qual seria o resultado da seguinte subtração no sistema decimal?

Como vimos, a representação em ponto flutante é uma variação binária (base-dois) da notação científica, sendo esta a representação utilizada por computadores para armazenar números.

Por exemplo, podemos escrever o número 0,0006926 com quatro dígitos significativos em notação científica como 6,926 × 10^{-4}. Esta representação pode representar qualquer valor entre 0,00069255 e 0,00069265.

As representações em ponto flutuante em computadores são semelhantes, exceto que uma potência de 2 é usada em vez de uma potência de 10, e a fração é escrita em notação binária.

O número 0,0006926 é escrito como 1,0112 \times 2^{-11} se a precisão de quatro dígitos binários for usada. .0112 representa a mantissa e 11 o expoente.

No entanto, 6,926 × 10^{−4} e 1,0112 × 2^{−11} não são idênticos.

Quatro dígitos binários fornecem menos precisão que quatro dígitos decimais. Uma faixa de valores entre 0,000641 a 0,000702 obteria a mesma representação com precisão de quatro dígitos binários.

De fato, 6,926 × 10^{−4} não pode ser representado exatamente em notação binária em um número finito de dígitos.

O problema é semelhante a tentar representar 1/3 como um decimal: 0,3333 é apenas uma aproximação.

.Machine é uma variável que contém informações sobre as características numéricas da máquina em que a linguagem R está sendo executada, como o maior double ou inteiro e a precisão da máquina.

A constante double.eps representa o menor número positivo que pode ser representado no tipo double antes que a precisão seja perdida. Vejamos se o valor absoluto de (0.3 - 0.2) - 0.1 é menor que double.eps:

Ou seja, a precisão padrão da linguagem R (e náo apenas da linguagem R) é de 53 bits (dígitos binários), o que equivale a cerca de 15 ou 16 dígitos decimais.

Assim, a aritmética com números inteiros será exata para valores entre −(2^{53} − 1) e 2^{53} − 1 (aproximadamente −10^{16} a 10^{16}), mas assim que começamos a usar números fora desse intervalo, ou frações, podemos perder precisão devido a erros de arredondamento.

Por exemplo, 1.1 não possui uma expansão binária finita, portanto, em precisão dupla (64 bits), sua expansão binária é arredondada para 1,00011001100\ldots001 , com um erro de aproximadamente 2^{-53} .

O erro de arredondamento tende a se acumular na maioria dos cálculos, então geralmente uma longa série de cálculos resultará em erros maiores do que uma sequência curta.

Algumas operações são particularmente propensas a erros de arredondamento, por exemplo, subtração de dois números quase iguais, ou (equivalentemente) adição de dois números com quase a mesma magnitude, mas sinais opostos.

Isso ocorre por que os bits principais nas expansões binárias de números quase iguais serão correspondentes, assim serão cancelados na subtração, e o resultado vai depender do que está armazenado nos bits posteriores.

6.1.5 Cancelamento Catastrófico

O cancelamento catastrófico ocorre quando subtrai-se dois números muito próximos, resultando em uma perda significativa de precisão devido aos limites da representação numérica em computadores.

6.2 Exercícios

Vamos praticar a manipulação de objetos, o uso de operadores matemáticos e de algumas funções matemáticas básicas da linguagem R resolvendo alguns exercícios simples de Finanças:

Exercício 1

Considere um investimento de R$ 10.000,00 com uma taxa de retorno anual de 8%. Crie um script em R que armazene o valor inicial do investimento em um objeto, calcule o valor após 5 anos usando a fórmula de juro composto e exiba o resultado.

Exercício 2

Suponha que você está analisando dois investimentos: o primeiro gera fluxos de caixa de R$ 2.000,00 por ano durante 4 anos, e o segundo, R$ 3.000,00 por ano durante 3 anos. Ambos têm uma taxa de desconto de 10%. Crie um script em R que calcule e compare os VPLs dos dois investimentos, indicando qual é mais atrativo.

Dica para o Ex. 2

Estude a ajuda das funções sum, length e seq, elas são úteis para implementar a fórmula de cálculo do VPL.

7 Operadores Relacionais

Operadores relacionais são aqueles que determinam a relação entre dois objetos que lhes são dados. O resultado de uma operação relacional é sempre booleano (ou seja, TRUE ou FALSE) para todos os operadores relacionais.

A Tabela 2 exibe as seis operações relacionais suportadas pela linguagem R.

Tabela 2. Operadores Relacionais da linguagem R
operador significado
a < b a é menor que b?
a <= b a é menor ou igual b?
a > b a é maior que b?
a >= b a é maior ou igual a b?
a == b a é exatamente igual a b?
a != b a é diferente de b?

Grande parte de análises de dados resume-se à comparação de valores. Há menos y do que há uma década? z cresceu esta semana? j é mais rápido que k? Algum dos m efeitos é significativo? Se não exigíssemos comparações entre dados, a codificação das análises seriam bastante diretas - sempre faça isso, depois aquilo, depois outra coisa.

Porém, como exigimos comparações, devemos saber como dizer a R para comparar valores. O resultado de uma comparação será sempre um valor lógico, TRUE ou FALSE (ou NA).

As comparações mais simples que você pode fazer são:

  • “x é maior que y?”: (x > y)

  • “x é menor que y?”: (x < y),

usando os operadores “maior que” (>) e “menor que” (<):

Também podemos testar se:

  • “x é maior ou igual a y?” (x >= y) e;
  • “x é menor ou igual a y?” (x <= y).

Podemos testar se dois números são iguais entre si com um “duplo igual” (==), que pergunta “x tem o mesmo valor que y?”, x == y.

A pergunta oposta pode ser feita também: “x é um valor diferente de y?” ou “x não é igual a y?”, x != y.

Alguns cuidados precisam ser tomados com esses operadores. Em alguns casos, eles testam se dois valores parecem ser os mesmos, mas não se são precisamente os mesmos.

Embora você possa especificar um valor semelhante a um número inteiro como um número inteiro ou um número real, eles são armazenados de forma diferente. Entretanto, eles representam o mesmo valor, então o operador == os trata como iguais ao testar:

Se você realmente deseja testar se são a mesma coisa, a função idêntical() verifica os tipos dos objetos antes de declarar se são idênticas:

Tenha muito cuidado ao comparar números não inteiros (reais) entre si. Lembra-se da sessão sobre como computadores armazenam dados usando um sistema binário (ou seja, como uns e zeros)? E que não é possível representar exatamente números decimais nesse sistema?

Por causa disso, há uma limitação na precisão com que os números decimais podem ser armazenados. Você pode inserir o valor 0.3, mas o computador tenta, como pode, armazenar tantos dígitos (zeros neste caso) no final.

Da mesma forma que não podemos escrever 1/3 =0,33333\ldots exatamente, os computadores não podem armazenar valores que não sejam potências exatas de 2 sem alguma perda de precisão.

Podemos ver isso solicitando mais dígitos na saída da função print():

Quando ocorrem operações matemáticas, esses bits extras ou ausentes também contribuem. Então, embora você possa ver um bom valor arredondado como resultado, em termos dos dígitos que o computador pode armazenar, pode ser um pouco diferente disso, levando a resultados inesperados:

Essa característica não é exclusiva da linguagem, é inerente a qualquer linguagem de programação.

Ao comparar objetos do tipo character, R usa o alfabeto para classificá-los. Portanto, “R” > “Python” seria avaliado como TRUE, pois “R” vem depois de “P” no alfabeto:

8 Tipos Primitivos de Dados

Conhecer os tipos de dados é crucial para realizar a análise correta e evitar erros. Este sessão irá equipá-lo com as habilidades para verificar os tipos primitivos de dados em R.

Uma operação ubíqua para um analista ou cientista de dados é a importação de arquivos externos de dados de várias fontes, sendo que muitas vezes os dados não terão o tipo ou classe adequado para que possam ser analisados, assim, o conhecimento dos tipos de dados é fundamental para que você possa alterar o tipo ou classe de suas variáveis para o tipo adequado para a análise que precisa ser realizada, sendo comum a necessidade de alterar o tipo ou classe dos dados durante uma análise.

Imagine seus dados como uma coleção diversificada de objetos. Alguns podem ser números (como idade ou peso), enquanto outros podem ser texto (como nomes ou empresas) e outros podem ser datas. Essas diferentes categorias são chamadas de tipos (ou classe) de dados.

Os cinco tipos vetoriais primitivos (também chamados de tipos ‘atômicos’) mais comuns da linguagem R são:

  • logical
  • integer
  • double
  • complex
  • character (em C também conhecido como ‘string’) e

Outros, menos usuais, são:

  • raw
  • list
  • NULL
  • closure: para funções
  • special
  • builtin: operadores e funções básicas
  • environment
  • S4

Os cinco tipos primitivos mais comuns estão detalhados na Tabela 1.

Tabela 3. Tipos Vetoriais Básicos
typeof descricao
double vetor contendo valores reais
integer vetor contendo valores inteiros
character vetor contendo caracteres/strings
logical vetor contendo valores lógicos
complex vetor contendo valores complexos

A linguagem R possui ainda tipos vetoriais especiais, descritos na Tabela 3.

Tabela 4. Tipos Vetoriais Especiais
typeof descricao
NA Not Available: representa dados faltantes
NaN Not a Number: 0/0, Inf - Inf
Inf + \infty ou - \infty
R não possui um tipo escalar

Números únicos, como 4.2, e strings, como “quatro pontos dois” ainda são vetores, de tamanho 1, ou seja, na linguagem R não existe um tipo escalar. Vetores com tamanho zero são possíveis (e úteis).

8.1 Verificando Tipos de Dados

Agora, vamos nos equipar com as ferramentas para identificar esses tipos de dados em nossos projetos R. Aqui estão duas funções poderosas: typeof() e class().

As funções typeof() e class() da linguagem R são usadas para determinar a natureza de um objeto, mas diferem em aspectos importantes:

  • typeof(): Retorna o tipo de armazenamento interno do objeto, sendo que os tipos mais comuns são: double, integer, logical, character, complex.

  • class(): etorna a classe S3 do objeto, que é uma classificação mais abstrata que define seu comportamento e as funções que podem ser aplicadas a ele. As classes S3 são predefinidas em R e podem ser personalizadas pelo usuário.

Exemplos de classes:

  • numeric: se um objeto é do tipo integer ou double, sua classe é numeric;
  • character;
  • logical;
  • data.frame;
  • matrix;
  • array.

Em resumo:

  • typeof() informa como o objeto é armazenado na memória.

  • class() informa o classe (ou tipo semântico) do objeto e suas propriedades.

8.2 Função str()

Uma outra função muito utilizada para exibir a estrutura interna de um objeto, é a função str() (de structure).

Em geral, utilizamos str() para exibir a estrutura de objetos mais complexos tais como data.frame e list.

No código a seguir, criamos uma data.frame chamada df_str usando a função data.frame. Para criar as 3 variáveis que irão compor a data frame, utilizamos a função c() (de concatenate) que concatena os elementos inseridos em um vetor.

Vejamos alguns exemplos da aplicação da funções typeof() e class()

8.3 Exemplos

Pelos dois exemplos anteriores, você deve ter percebido que um valor que se parece com um número inteiro ainda será armazenado como um número tipo double ou da classe numeric. Isso ocorre, porque, por padrão, R assumirá o tipo mais geral de dados conforme você os atribui a uma variável.

A menos que você diga especificamente ao R o contrário, nesse caso, para que um número tenha o tipo inteiro, é necessário acrescentar um L maiúsculo à sua direita:

Veja alguns exemplos dos tipos especiais:

Em R, a classe Date é utilizada para representar datas. Esta classe é especialmente útil para manipulações e cálculos envolvendo datas, permitindo operações específicas que respeitam a natureza temporal dos dados.

Vamos explorar a classe Date em mais detalhes:

  • Formato Interno:

Internamente, as datas são representadas como o número de dias desde 1970-01-01, conhecido como o “Epoch” (ponto de referência zero para muitos sistemas temporais).

  • Construção de Objetos Date:

Você pode criar um objeto Date utilizando a função as.Date(). Por exemplo:

  • Operações com Datas:

A classe Date permite realizar operações de adição e subtração, facilitando cálculos de diferença entre datas.

  • Manipulação de Formatos:

Funções como format() permitem a exibição de datas em diferentes formatos.

  • Exemplos de Uso:
  1. Criação de Objetos Date:
  1. Operações com Datas:
  1. Manipulação de Formatos:
  • Importância da Classe Date:

A classe Date é muito importante para manipulações de dados de séries temporais, garantindo precisão e consistência em cálculos que envolvem datas.

  1. Análise de Séries Temporais:

Permite a aplicação de métodos para a análises de séries temporais, como visualização e a modelagem de séries temporais,

  1. Comparação de Datas:

Permite comparações lógicas entre datas, úteis em filtros de dados temporais.

  1. Facilita Integração com Pacotes Temporais:

Muitos pacotes em R, como os pacotes lubridate e xts, são desenvolvidos para trabalhar eficientemente com objetos Date, tornando a análise temporal mais eficaz.

Ao utilizar a classe Date, você pode garantir uma manipulação de datas mais precisa e eficiente em suas análises de dados temporais no ambiente R.

Ao entender e verificar efetivamente os tipos de dados, você estará no caminho correto para dominar a manipulação e análise de dados em R. Lembre-se, a prática leva à perfeição, e quanto mais você experimentar, mais confortável você se tornará com os tipos de dados em R. Então, continue explorando, continue programando e continue desmistificando seus dados!

8.4 Verificando o Tipo/Classe de um Objeto

Existem funções da linguagem para verificarmos se um objeto é, ou não, de um determinado tipo ou classe. Algumas das principais funções desta família de funções são:

  • is.numeric()

A função is.numeric() é utilizada para verificar se um objeto é da classe numeric. Retorna TRUE se o objeto for numérico e FALSE caso contrário. Vejamos um exemplo:

  • is.character()

A função is.character() é empregada para verificar se um objeto é do tip/classe character. Retorna TRUE se o objeto for um caracter e FALSE caso contrário.

Exemplo:

  • is.logical()

A função is.logical() verifica se um objeto é do tipo/classe logical, ou seja, se assume os valores TRUE ou FALSE.

Exemplo:

  • is.factor()

A função is.factor() é utilizada para verificar se um objeto é do tipo/classe factor. Fatores são estruturas de dadso usadas para representar variáveis categóricas em R, veremos mais detalhes nas próximas sessões.

Exemplo:

Essas funções são úteis para verificar e validar tipos de dados em R, contribuindo para a consistência e integridade na manipulação de dados.

8.5 Convertendo um Objeto para um Tipo Específico

Às vezes, os dados não são do tipo que você deseja. Então, o que podemos fazer? R possui um grupo de funções que começam com as. que tentam converter (coagir)quaisquer dados de entrada em outro tipo.

As funções importantes são:

  • as.integer()
  • as.numeric()
  • as.character()
  • as.logical()
  • as.Date()
  • as.POSIXct() e as.POSIXlt()

Essas funções tentam converter um dado existente para um tipo específico. Então, se você tiver um número, mas você deseja que R o trate como texto (character), você pode usar as.character():

Você pode forçar isso ao inserir os dados colocando aspas ao redor do número, fazendo com que seja do tipo character:

Mas às vezes você precisa converter um valor já armazenado em uma variável, por exemplo, contida em um arquivo de dados importado. Se você tiver alguns dados numéricos que foram importados como sequências de caracteres, poderá convertê-los novamente em números:

Converter números inteiros para números contínuos (tipo double ou classe numeric) é simples, e recomendamos usar a funçõa as.numeric:

Existem limites para o que R pode converter. E se você fornecer algo que claramente não é um número inteiro? Você pode testar isso com alguns valores e ver se obtém o resultado esperado:

Faz sentido, talvez. Esse é certamente o número inteiro mais próximo (número inteiro) daquele valor. Vamos tentar outro:

Era isso que você esperava? Depende de como você supôs que a função poderia funcionar. as.integer() coage para o número inteiro mais próximo, arredondando em direção a zero.

E quanto aos números negativos?

Novamente o arredondamento ocorre em direção a zero. Portanto, conversões podem, ou não, ser o que você deseja, então certifique-se de que o resultado seja correto esta ao usar as funções de conversão.

R fará o possível para converter de qualquer tipo para qualquer outro tipo que você solicitar, mas apenas algumas combinações são possíveis. De inteiro para numérico é simples. Numérico para inteiro, como você acabou de ver, funciona, desde que você saiba que será arredondado para zero.

8.6 Exercícios

Exercício 1 : Identificando Tipos de Dados

Crie variáveis (objetos) apropriadas para armazenar:

  • Sua idade:
  • Seu nome:
  • Se você considera que possui boa saúde mental:
  • Utilize as funções typeof() e class() para verificar o tipo e a classe de cada variável.

Exercício 2: Testando Tipos de Dados

  • Crie uma variável chamada valor que pode ser numérica ou caractere.
  • Utilize is.numeric() e is.character() para verificar o tipo em diferentes cenários (atribuindo valores numéricos e de caracteres).

Exercício 3: Convertendo Tipos de Dados

  • Crie uma variável chamada numero que receba um valor numérico como string (“123”):
  • Converta a variável para a classe numeric usando as.numeric():
  • Utilize class() para verificar se a conversão foi realizada com sucesso:

Exercício 4: Operações com Tipos de Dados

  • Crie as variáveis num1 e num2 com valores numéricos:
  • Some num1 e num2 e verifique o tipo do resultado.
  • Concatene num1 e num2 como caracteres usando a função paste() e verifique o tipo do resultado.

A função paste() concatena vários objetos em um único. É uma ferramenta versátil para combinar objetos.

A sintáxe da função é:

paste(x, y, ..., sep = "", collapse = "")

sendo: - x, y, …: Objetos a serem concatenados. - sep: Separador entre os objetos (opcional, padrão: espaço em branco). - collapse: Caractere para unir linhas (opcional, padrão: nova linha)

exemplo:

num1 <- 10
num2 <- 20

resultado <- paste(num1, num2)
resultado

Exercício 5: Este exercício ilustra a manipulação de datas na linguagem R, utilizando a classe Date.

Crie duas variáveis do tipo Date:

  • data_nascimento: Sua data de nascimento.
  • data_hoje: A data de hoje (use Sys.Date()).
  • Calcule a diferença entre as duas datas em dias.

Desafio: Identifique situações em que saber o tipo de dados é crucial para a sua análise.

9 Referências

BECKER, R. A.; CHAMBERS, J. M.; WILKS, A. R. The New S Language. New York: Chapman & Hall, 1988.
CHAMBERS, J. M. Programming with Data. New York: Springer, 1998.
CHAMBERS, J. M.; HASTIE, T. J. (EDS.). Statistical Models in S. New York: Chapman & Hall, 1992.
VENABLES, W. N.; SMITH, D. M.; R CORE TEAM, THE. An Introduction to R. Vienna, Austria: R Foundation for Statistical Computing, 2023.