sort(c(2, 1, 3, 0), decreasing = TRUE)
R> [1] 3 2 1 0
A maior dificuldade que um usuário iniciante possui ao começar a desenvolver rotinas com o R é a forma de trabalho. A nossa interação com computadores foi simplificada ao longo dos anos e atualmente estamos confortáveis com o formato de interação do tipo aponte e clique. Especificamente para o caso de análise de dados, o uso de planilhas eletrônicas do tipo Excel é provavelmente o primeiro contato que temos com algum tipo de plataforma de análise de dados.
O formato aponte e clique, muito utilizado em planilhas, permite que o usuário aponte o mouse para um determinado local da tela, clique em um botão e realize uma determinada operação. Uma série de passos nesse sentido permite a execução de tarefas complexas no computador. Mas não se engane, essa forma de interação no formato aponte e clique é apenas uma camada por cima do que realmente acontece no computador. Por trás de todo clique existe um comando sendo executado, seja na abertura de um arquivo pdf, direcionamento do browser para uma página na internet ou qualquer outra operação cotidiana.
Enquanto esse formato de interação visual e motora tem seus benefícios ao facilitar e popularizar o uso de computadores, é pouco flexível e eficaz quando se trabalha com procedimentos computacionais. Alternativamente, ao conhecer os possíveis comandos disponíveis ao usuário, é possível criar um arquivo contendo instruções em sequência e, futuramente, simplesmente pedir que o computador execute as instruções contidas no arquivo. Uma rotina de computador é nada mais do que um texto que instrui, de forma clara e sequencial, o que o computador deve fazer. Investe-se certo tempo para a criação do programa porém, no futuro, esse irá executar sempre da mesma maneira o procedimento gravado. No médio e longo prazo, existe um ganho significativo de tempo entre o uso de uma rotina do computador e uma interface do tipo aponte e clique.
Além disso, o risco de erro humano na execução do procedimento é quase nulo, pois os comandos e a sua sequência estão registrados no arquivo texto e serão executados sempre da mesma maneira. Indo além, o conjunto de comandos pode ser compartilhado com outras pessoas, as quais podem replicar os resultados em seus computadores. Essa é uma das grandes razões que justificam a popularização de programação na realização de pesquisa em dados. Todos os procedimentos executados, e os resultados, podem ser replicados por outra pessoa através do uso de um script.
O R é uma plataforma de programação e o primeiro choque para um novo usuário é o predomínio no uso de código sobre operações com o mouse. O R e o RStudio possuem algumas funcionalidades através do mouse, porém a sua capacidade é otimizada quando os utilizamos via inserção de comandos específicos. Quando um grupo de comandos é realizado de uma maneira inteligente, temos um script do R que deve preferencialmente produzir algo importante para nós no final de sua execução.
O R também possibilita a exportação de arquivos, tal como figuras a serem inseridas em um relatório técnico ou informações em um arquivo texto. De fato, o próprio relatório técnico pode ser dinamicamente criado dentro do R através da tecnologia RMarkdown e Quarto. Por exemplo, este livro que estás lendo foi escrito utilizando a tecnologia Quarto. O conteúdo do livro é compilado com a execução dos códigos e as suas saídas são registradas em texto. Todas as figuras e os dados do livro podem ser atualizados com a execução de um simples comando.
Ao escrever um código no R, tudo é um objeto, e cada tipo de objeto tem suas propriedades. Por exemplo, o valor da temperatura média em determinado local ao longo do tempo – em vários meses e anos – pode ser representado como um objeto do tipo vetor numérico. As datas em si, no formato YYYY-MM-DD (ano-mês-dia), podem ser representadas como texto (character) ou a própria classe Date
. Por fim, podemos representar conjuntamente os dados de temperatura e as datas armazenando-os em um objeto único do tipo dataframe, o qual nada mais é do que uma tabela com linhas e colunas. Todos esses objetos fazem parte do ecossistema do R e é através da manipulação destes que tiramos o máximo proveito do software.
Os principais tipos de objetos do R são:
Enquanto representamos informações do mundo real com as diferentes classes no R, um tipo especial de objeto é a função, a qual representa um procedimento preestabelecido que está disponível para o usuário. O R possui uma grande quantidade de funções, as quais possibilitam que o usuário realize uma vasta gama de procedimentos. Por exemplo, os comandos básicos do R, não incluindo demais pacotes, somam um total de 1280 funções. Com base neles e outros iremos importar dados, calcular médias, testar hipóteses, limpar dados, e muito mais.
O {base} (R Core Team 2023) é certamente o pacote mais utilizado no R e já vem pré-instalado. O mesmo possui uma quantidade imensa de funções, com os mais diferentes propósitos. Muitos outros pacotes dependem do base para funcionar corretamente, demonstrando assim a sua importância. Saiba que o {base} (R Core Team 2023) é automaticamente carregado na inicialização de sua sessão do R, permitindo acesso direto às suas funções.
Cada função possui um próprio nome. Por exemplo, a função sort() é um procedimento que ordena valores utilizados como input. Caso quiséssemos ordenar os valores no vetor numérico [2, 1, 3, 0], basta inserir no prompt o seguinte comando e apertar enter:
sort(c(2, 1, 3, 0), decreasing = TRUE)
R> [1] 3 2 1 0
O comando c(2, 1, 3, 0)
combina os valores em um vetor (maiores detalhes sobre comando c() serão dados em seção futura). Observe que a função sort() é utilizada com parênteses de início e fim. Esses parênteses servem para destacar as entradas (inputs), isto é, as informações enviadas para a função produzir alguma coisa. Cada entrada (ou opção) da função é separada por uma vírgula, tal como em MinhaFuncao(entrada01, entrada02, entrada03, ...)
. No caso do código anterior, note que usamos a opção decreasing = TRUE
. Essa é uma instrução específica para a função sort() ordenar de forma decrescente os elementos do vetor de entrada. Veja a diferença:
sort(c(2, 1, 3, 0), decreasing = FALSE)
R> [1] 0 1 2 3
O uso de funções está no coração do R e iremos dedicar grande parte do livro a elas. Por enquanto, essa breve introdução já serve o seu propósito. O principal é entender que uma função usa suas entradas para produzir algo de volta. Nos próximos capítulos iremos utilizar funções já existentes para as mais diferentes finalidades: baixar dados da internet, ler arquivos, realizar testes estatísticos e muito mais.
Um dos comandos mais básicos no R é a definição de objetos. Como foi mostrado nas seções anteriores, pode-se definir um objeto com o uso do comando <-
, o qual, para o português, é traduzido para o verbo defina (assign em inglês).
Considere o código a seguir. Para rodar o código no seu computador, escreva (ou copie e cole) o código mostrado em um novo script do RStudio e aperte control + shift + enter. Mais detalhes sobre diferentes maneiras de executar código no RStudio serão dadas em Seção 2.1
# set x
<- 123
my_x
# set x, y and z in one line
<- 1 ; my_y <- 2; my_z <- 3 my_x
Lê-se esse código como x é definido como 123. A direção da seta define onde o valor será armazenado. Por exemplo, utilizar 123 -> my_x
também funcionaria, apesar de ser uma sintaxe pouco utilizada ou recomendada. Note que também é possível escrever diversos comandos na mesma linha com o uso da semi-vírgula (;
).
O uso do símbolo <-
para a definição de objetos é específico do R. Na época da concepção da linguagem S, de onde o R foi baseado, existiam teclados com uma tecla específica que definia diretamente o símbolo de seta. Teclados contemporâneos, porém, não possuem mais esta configuração. Uma alternativa é utilizar o atalho para o símbolo, o qual, no Windows, é definido por alt + -
.
É possível também usar o símbolo =
para definir objetos assim como o <-
. Saliento que esta é prática comum em outras linguagens de programação. Porém, no ecossistema do R, a utilização do =
com esse fim específico não é recomendada. O símbolo de igualdade tem o seu uso especial e resguardado na definição de argumentos de uma função tal como sort(x = 1:10, decreasing = TRUE)
. Como sugestão, dê preferência ao uso do <-
para a criação de novos objetos.
O R executa o código procurando objetos e funções disponíveis no seu ambiente de trabalho (enviromnent). Se tentarmos acessar um objeto que não existe, o R irá retornar uma mensagem de erro:
print(z)
R> Error in print(z): object 'z' not found
Isso ocorre pois o objeto z
não existe na sessão atual do R. Se criarmos uma variável z
como z <- 123
e repetirmos o comando print(z)
, não teremos a mesma mensagem de erro.
Um ponto importante aqui é a definição de objetos de classes diferentes com o uso de símbolos específicos. O uso de aspas duplas (" "
) ou simples (' '
) define objetos da classe texto enquanto números são definidos pelo próprio valor. Conforme será mostrado, cada objeto no R tem uma classe e cada classe tem um comportamento diferente. Portanto, objetos criados com o uso de aspas pertencem à classe character. Podemos confirmar isso via código:
# set vars
<- 1
x <- '1'
y
# display classes
class(x)
R> [1] "numeric"
class(y)
R> [1] "character"
As saídas anteriores mostram que a variável x
é do tipo numérico, enquanto a variável y
é do tipo texto (character). Ambas fazem parte das classes básicas de objetos no R. Por enquanto, este é o mínimo que deves saber para avançar nos próximos capítulos. Iremos estudar este assunto mais profundamente no Capítulo 6.
A nomeação dos objetos criados no R é importante. Tirando alguns casos específicos, o usuário pode nomear os objetos como quiser. Essa liberdade, porém, pode ser um problema. É desejável sempre dar nomes curtos que façam sentido ao conteúdo do objeto e que sejam simples de entender. Isso facilita o entendimento do código por outros usuários e faz parte das normas sugeridas para a estruturação do código do Google.
Anteriormente, criamos objetos simples tal como x <- 1
e x <- 'abc'
. Enquanto isso é suficiente para demonstrar os comandos básicos do R, na prática tais comandos são bastante limitados, uma vez que um problema real de análise de dados certamente irá ter um maior volume de informações do mundo real.
Um dos procedimentos mais utilizados no R é a criação de vetores atômicos. Estes são objetos que guardam uma série de elementos da mesma classe, o que justifica a sua propriedade “atômica”. Um exemplo seria representar no R uma série de preços diários de uma ação negociada em bolsa de valores. Tal série possui vários valores numéricos que formam um vetor da classe numérica.
Vetores atômicos são criados no R através do uso do comando c()** **, o qual é oriundo do verbo em inglês combine. Por exemplo, caso eu quisesse combinar os valores 1, 2 e 3 em um vetor, eu poderia fazê-lo através do seguinte comando:
# set vector
<- c(1, 2, 3)
x
# print it
print(x)
R> [1] 1 2 3
Esse comando funciona da mesma maneira para qualquer número de elementos. Caso necessário, poderíamos criar um vetor com mais elementos simplesmente adicionando valores após o 3
, tal como em x <- c(1, 2, 3, 4, 5)
.
O uso do comando c() não é exclusivo para vetores numéricos. Por exemplo, poderíamos criar um vetor de outra classe de dados, tal como character:
<- c('text 1', 'text 2', 'text 3', 'text 4')
y print(y)
R> [1] "text 1" "text 2" "text 3" "text 4"
A única restrição no uso do comando c() é que todos os itens do vetor tenham a mesma classe. Se inserirmos dados de classes diferentes, o R irá tentar transformar os itens para a mesma classe seguindo uma lógica própria, onde a classe mais complexa sempre tem preferência. Caso ele não consiga transformar todos os elementos para a classe mais complexa, uma mensagem de erro será retornada. Observe, no próximo exemplo, que ao misturarmos text com números, os valores numéricos no primeiro e segundo elemento de x2
são transformados para a classe de caracteres.
# numeric class
<- c(1, 2, 3)
x1 class(x1)
R> [1] "numeric"
# character class
<- c(1, 2, '3')
x2 class(x2)
R> [1] "character"
Outra utilização do comando c() é a combinação de vetores. De fato, isto é exatamente o que fizemos ao executar o código c(1, 2, 3)
. Neste caso, cada vetor possuía um elemento. Podemos realizar o mesmo com vetores maiores. Veja a seguir:
# set x and y
<- c(1, 2, 3)
x <- c(4, 5)
y
# print concatenation between x and y
print(c(x, y))
R> [1] 1 2 3 4 5
Portanto, o comando c() possui duas funções principais: criar e combinar vetores.
Alternativamente, podemos também criar vetores utilizando nomes para os elementos:
# create named vector
<- c("x" = 1, "y" = 2)
named_vec
# print its contents
print(named_vec)
R> x y
R> 1 2
Assim, podemos acessar cada elemento usando o seu nome:
# print only "x" value in named_vec
print(named_vec["x"])
R> x
R> 1
Após a execução de diversos comandos no editor ou prompt, é desejável saber quais são os objetos criados pelo código. É possível descobrir essa informação simplesmente olhando para o lado direito superior do RStudio, na aba da área de trabalho. Porém, existe um comando que sinaliza a mesma informação no prompt. Com o fim de saber quais são as variáveis atualmente disponíveis na memória do R, pode-se utilizar o comando ls() . Observe o exemplo a seguir:
# set vars
<- 1
x <- 2
y <- 3
z
# show current objects
ls()
R> [1] "x" "y" "z"
Os objetos x
, y
e z
foram criados e estavam disponíveis no ambiente de trabalho atual, juntamente com outros objetos. Para descobrir os valores dos mesmos, basta digitar os nomes dos objetos e apertar enter
no prompt:
x
R> [1] 1
y
R> [1] 2
z
R> [1] 3
Digitar o nome do objeto na tela tem o mesmo resultado que utilizar a função print() . De fato, ao executar o nome de uma variável, internamente o R passa esse objeto para a função print() .
No R, conforme já mostrado, todos os objetos pertencem a alguma classe. Para descobrir a classe de um objeto, basta utilizar a função class() . Observe no exemplo a seguir que x
é um objeto da classe numérica e y
é um objeto da classe de texto (character).
# set vars
<- 1
x <- 'a'
y
# check classes
class(x)
R> [1] "numeric"
class(y)
R> [1] "character"
Outra maneira de conhecer melhor um objeto é verificar a sua representação em texto. Todo objeto no R possui uma representação textual e a verificação desta é realizada através da função str() :
# print textual representation of a vector
<- 1:10
x print(str(x))
R> int [1:10] 1 2 3 4 5 6 7 8 9 10
R> NULL
Essa função é particularmente útil quando se está tentando entender os detalhes de um objeto mais complexo, tal como uma tabela. A utilidade da representação textual é que nela aparece o tamanho do objeto e suas classes internas. Nesse caso, o objeto x
é da classe integer e possui dez elementos. Como exemplo para um objeto mais complexo, as seguir apresentamos a representação textual de um objeto do tipo dataframe
:
# print textual representation of a dataframe
<- data.frame(x = 1:10, y = "ABC")
df print(str(df))
R> 'data.frame': 10 obs. of 2 variables:
R> $ x: int 1 2 3 4 5 6 7 8 9 10
R> $ y: chr "ABC" "ABC" "ABC" "ABC" ...
R> NULL
Na prática de programação com o R, é muito importante saber o tamanho das variáveis que estão sendo utilizadas. Isso serve não somente para auxiliar o usuário na verificação de possíveis erros do código, mas também para saber o tamanho necessário em certos procedimentos de iteração tal como loops, os quais serão tratados em capítulo futuro.
No R, o tamanho do objeto pode ser verificado com o uso de quatro principais funções: length() , nrow() , ncol() e dim() .
A função length() é destinada a objetos com uma única dimensão, tal como vetores atômicos:
# set x
<- c(2, 3, 3, 4, 2, 1)
x
# get length x
<- length(x)
n
# display message
message(paste('The length of x is', n))
R> The length of x is 6
Para objetos com mais de uma dimensão, por exemplo matrizes e dataframes, utilizam-se as funções nrow() , ncol() e dim() para descobrir o número de linhas (primeira dimensão) e o número de colunas (segunda dimensão). Veja a diferença a seguir.
# set matrix and print it
<- matrix(1:20, nrow = 4, ncol = 5)
x print(x)
R> [,1] [,2] [,3] [,4] [,5]
R> [1,] 1 5 9 13 17
R> [2,] 2 6 10 14 18
R> [3,] 3 7 11 15 19
R> [4,] 4 8 12 16 20
# find number of rows, columns and elements
<- nrow(x)
my_nrow <- ncol(x)
my_ncol <- length(x)
my_length
# print message
message(paste('\nThe number of lines in x is ', my_nrow))
R>
R> The number of lines in x is 4
message(paste('\nThe number of columns in x is ', my_ncol))
R>
R> The number of columns in x is 5
message(paste('\nThe number of elements in x is ', my_length))
R>
R> The number of elements in x is 20
Já a função dim() mostra a dimensão do objeto, resultando em um vetor numérico como saída. Essa deve ser utilizada quando o objeto tiver mais de duas dimensões. Na prática, esses casos são raros. Um exemplo para a variável x
é dado a seguir:
print(dim(x))
R> [1] 4 5
Para o caso de objetos com mais de duas dimensões, podemos utilizar a função array() para criá-los e dim() para descobrir o seu tamanho:
# set array with dimension
<- array(1:9, dim = c(3,3,3))
my_array
# print it
print(my_array)
R> , , 1
R>
R> [,1] [,2] [,3]
R> [1,] 1 4 7
R> [2,] 2 5 8
R> [3,] 3 6 9
R>
R> , , 2
R>
R> [,1] [,2] [,3]
R> [1,] 1 4 7
R> [2,] 2 5 8
R> [3,] 3 6 9
R>
R> , , 3
R>
R> [,1] [,2] [,3]
R> [1,] 1 4 7
R> [2,] 2 5 8
R> [3,] 3 6 9
# print its dimension
print(dim(my_array))
R> [1] 3 3 3
Reforçando, cada objeto no R tem suas propriedades e funções específicas para manipulação.
Uma observação importante aqui é que as funções anteriores não servem para descobrir o número de letras em um texto. Esse é um erro bastante comum. Por exemplo, caso tivéssemos um objeto do tipo texto e usássemos a função length() , o resultado seria o seguinte:
# set char object
<- 'abcde'
my_char
# find its length (and NOT number of characters)
print(length(my_char))
R> [1] 1
Isso ocorre pois a função length() retorna o número de elementos. Nesse caso, my_char
possui apenas um elemento. Para descobrir o número de caracteres no objeto, utilizamos a função nchar() , conforme a seguir:
# using nchar for number of characters
print(nchar(my_char))
R> [1] 5
Q.1 - Crie um novo script, salve o mesmo em uma pasta pessoal. Agora, escreva os comandos no script que definam dois objetos: um contendo uma sequência entre 1 e 100 e outro com o texto do seu nome (ex. 'Ricardo'
). Execute o código com os atalhos no teclado.
Q.2 - No script criado anteriormente, use função message() para mostrar a seguinte frase no prompt do R: "My name is ...."
.
Q.3 - Você e três amigos foram comer um delicioso X em Porto Alegre RS. A conta final ficou como a seguir:
Nome | Pedido | Valor |
---|---|---|
Você | X salada | 20 |
Marcelo | X bacon | 25 |
Ricardo | X salada | 20 |
Amadeus | X Galinha | 22 |
No final da janta decidiram que iriam dividir a conta igualmente, isto é, basta somar os gastos individuais, e dividir pelo número de participantes.
Usando o R, crie um código que resulte no valor a ser pago por cada participante do jantar.
Q.4 - Qual o comando do R que mostra todos objetos disponíveis na sua sessão do R?
Q.5 - Qual das seguintes funções não mostra um texto na tela?
Q.6 - Qual das funções abaixo possui o mesmo resultado do comando paste0(c("a", "b", "c"))
?
Q.7 - Considere o objeto criado com o código a seguir:
M <- matrix(1:12, nrow = 3)
Qual o número de colunas no objeto resultante?