4 Noções básicas de programação em R

Objetivos deste capítulo:

  • Apresentar uma breve introdução aos principais comandos usados em programação

4.1 Sequências de scaping

Há alguns caracteres especiais que não podem ser usados diretamente numa string, pois possuem um significado especial. As aspas são um caso. Assim, por exemplo: variavel <- 'moinho d'agua' retorna erro. Para poder utilizar as aspas, temos de dizer ao programa para “escapar”. Isto é feito de modo geral com o caractere \. Assim, para funcionar, nosso exemplo fica: variavel <- 'moinho d\'agua'. No caso de aspas simples ' ou duplas ", é possível escapar estes caracteres colocando um dentro do outro. Por exemplo: variavel <- "moinho d'agua" ou variavel <- 'O conto "Trio em Lá Menor" de Machado de Assis foi publicado em 1896.'. Outros caracteres que levam escape são:

4.1.1 Comentando o código

Nas linguagens de programação é possível acrescentar comentários para orientar os humanos e que não serão lidos pelo computador. Cada linguagem tem o seu próprio padrão. No R, assim como em muitas linguagens de programação, os comentários no código são feito com a tralha # ou hashtag, jogo da velha, etc. Tudo que vier depois deste símbolo é então ignorado.

print("Olá mundo!")
## [1] "Olá mundo!"
print("Olá mundo R!") # comentário que o computador ignora
## [1] "Olá mundo R!"

Se retirarmos o símbolo # temos então mensagem de erro.

print("Olá mundo! Olá R")  comentários que dará erro
## Error: <text>:1:28: unexpected symbol
## 1: print("Olá mundo! Olá R")  comentários
##                                ^

4.2 Variável e atribuição

Em programação, no processo de automatização de tarefas, o uso de variáveis é essencial. Ele permite que reutilizemos as coisas, através de nomes mais simplificados. Normamente, usa-se o símbolo de igual =para atribuir algo a uma variável, no seguinte modo:

Noma_da_variavel = valores

O R também usa este símbolo, mas também usa outro que lhe é prório, o <- que lembra uma seta.

nome1 = "Fulano"
nome2 <- "Ciclano"
message("Um nome é ", nome1, ", o outro é ", nome2)
## Um nome é Fulano, o outro é Ciclano

Pode-se usar na direção contrária também

"Beltrano" -> nome3
nome3
## [1] "Beltrano"

Há algumas regras para criar variáveis. Não conter espaço no nome é uma delas. Ao invés disso, pode-se usar o underscore (Ex.: bla_ble) ou ponto (bla.ble). Há alguns caracteres especiais que não podem ser usados diretamente numa string, pois possuem um significado especial. As aspas são um caso. Assim, por exemplo: variavel <- 'moinho d'agua' retorna erro. Para poder utilizar as aspas, temos de dizer ao programa para “escapar”. Isto é feito de modo geral com o caractere \. Assim, para funcionar, nosso exemplo fica: variavel <- 'moinho d\'agua'. No caso de aspas simples ' ou duplas ", é possível escapar estes caracteres colocando um dentro do outro. Por exemplo: variavel <- "moinho d'agua" ou variavel <- 'O conto "Trio em Lá Menor" de Machado de Assis'.

4.3 Funções no R

Identificamos as funções no R por elas sempre virem acompanhados dos parênteses, como function(). Criar nossas próprias funções é útil para evitar retrabalho. Possuem a seguinte sintaxe:

# criando uma função no R
nome_da_funcao <- function(argumento_1, argumento_2, ...) {
   fazendo_algo_com(argumento_1)
   fazendo_algo_mais_com(argumento_2)
}

# rodando a função
nome_da_funcao(argumento_1,sargumento_2)

E com um exemplo:

minhaFuncao <- function(entrada){
        entrada + 10
}

minhaFuncao(2)
## [1] 12
minhaFuncao(6)
## [1] 16

minhaFuncao2 <- function(entrada1, entrada2){
        entrada1 + entrada2
}
minhaFuncao2(2,4) 
## [1] 6
minhaFuncao2(1,7) 
## [1] 8

arg_1, arg_2 são os parâmetros de entrada na função, que serão processados. Podemos ver quais argumentos são requeridos por determinada função através do comando args() (que por sua vez, também é uma função).

args(mean)
## function (x, ...) 
## NULL
args(median)
## function (x, na.rm = FALSE, ...) 
## NULL

Ao chamar uma função, passa-se argumentos para esta processar e nos retornar um determinado resultado. No R, repassamos argumentos 1) pela ordem apresentado em args(), ou 2) indicando qual valor para qual argumento. Nesta segunda opção, podemos enviar argumentos fora de ordem.

Ao criar nossas próprias funções, os argumentos usados na entrada também podem conter valores padrão, caso a informação não lhe seja repassada à função.

Em um exemplo simples de função:

x <- function(){
  print('Olá Mundo')
}
x()
## [1] "Olá Mundo"

Ou um outro exemplo, com a função tendo argumentos de entrada:

# Criando função com valores padrão:
minhafuncao <- function(a = 2, b = 3) {
   resultado <- a + b
   print(resultado)
}

# chamando a função sem nenhum argumento.
minhafuncao()
## [1] 5

# chamando a função repassando argumentos.
minhafuncao(10,4)
## [1] 14

# chamando a função repassando parte dos argumentos.
minhafuncao(,4)
## [1] 6

Geralmente, mas não sempre, como fazem transformações, funções são nomeadas com verbos, como “filtrar”, “mutar”, “cortar”, , etc. Isso nos ajuda a compreender mais intuitivamente do que se trata a função. Quanto aos tipos de argumentos, esses podem ser 1) os dados a serem computados, ou 2) detalhes dos argumentos, especificando melhor um modo específico/diferente do padrão para computar estes dados. Por exemplo, ao observarmos os argumentos da função cor(), de correlation/correlação:

args(cor)
## function (x, y = NULL, use = "everything", method = c("pearson", 
##     "kendall", "spearman")) 
## NULL
  • x e y: indicam os dados que entrarão na função. De modo geral - mas nem sempre! - os dados aparecem como primeiro argumento das funções. Este é o padrão sobretudo nas funções mais recentes do R, mas vamos encontrar algumas funções onde isso não é verdade, como na função grep.
  • method = c("pearson", "kendall", "spearman") mostram os argumentos possíveis em “method”, no caso desta função, especificando o tipo de correlação que queremos. Para especificarmos então qual destas usar, digamos “spearman”, o argumento ficaria method = "spearman".

4.4 Condicionais: se/então, If/else

  • Se uma condição, então faça algo.
  • Se outra condição, então faça outra coisa.
  • else: Se nenhuma das condições anteriores for satisfeita, então faça o seguinte.

Em sua versão mais simples

if (condição) { 
  fazer_algo()
}

Se certa condição for satisfeita, for verdadeira, então algo especificado será feito. Se certa condição não for satisfeita, for falsa, então nada será feito.

Perceba que nossa função apenas retorna algo se o argumento de entrada for maior que 5. Caso contrário - como foi com o valor 3 - ela nada faz.

if(3 > 5){
  print("X é maior que 5")
}

if(14 > 5){
  print("X é maior que 5")
}
## [1] "X é maior que 5"

4.4.1 Else

Uma versão mais elaborada da condicional envolve a condição else

if (condição) { 
  fazer_algo()
} else {
  fazer_outra_coisa()
}

Se certa condição for satisfeita, for verdadeira, então algo especificado - a função fazer_algo() - será realizada. Se certa condição não for satisfeita, for falsa, então outra coisa será feita. Ex.:

minhafuncao <- function(arg1){
  if(arg1 > 5){
    message(arg1, " é maior que 5")
  } else { 
     message(arg1, ' não é maior que 5')
  }
}
minhafuncao(3)
## 3 não é maior que 5
minhafuncao(13)
## 13 é maior que 5

4.4.2 else if

Podemos colocar mais condições intermediárias, quantas quisermos, com else if

comes <- function(arg1){
  if (arg1 == "laranja"){
    print("Prefiro tamarindo")
  }   else if (arg1 == "rucula"){
    print("bleaaaargh")
  }   else if (arg1 == "sanduiche"){
    print("Com suco de tamarindo!")
  }  else {
    print("Só sei com laranjas")
  }
}

# chamando a função acima
comes("laranja")
## [1] "Prefiro tamarindo"
comes("rucula")
## [1] "bleaaaargh"
comes("sanduiche")
## [1] "Com suco de tamarindo!"
comes("abacaxi")
## [1] "Só sei com laranjas"
comes("morango")
## [1] "Só sei com laranjas"

Combinando função e If/Else

verifica <- function(arg_entrada1, arg_entrada2){
  if (arg_entrada1 > arg_entrada2) {
    message(arg_entrada1, ' é maior que ', arg_entrada2)
  } else { 
    message(arg_entrada1, ' não é maior que ', arg_entrada2)
  }
}

Chamando a função

verifica(1,5)
## 1 não é maior que 5
verifica(7,2)
## 7 é maior que 2

Há ainda uma versão compacta de condicionais com a função ifelse(), e que segue a mesma lógica: ifelse(condição, se TRUE faça X, Se FALSE faça Y)

a  <- c(5, 6, 3, 9, 7)
ifelse(a > 5 ,"maior","menor")
## [1] "menor" "maior" "menor" "maior" "maior"

4.5 Operadores

Usamos operadores para realizar transformações ou comparações entre valores ou variáveis (que por sua vez, contém valores).

4.5.1 Operadores de atribuição (assignment)

Os operadores de atribuição são aqueles que vimos na sessão “variável”, que são =, <-, <<-, -> e ->>.

4.5.2 Operadores Aritiméticos

Operador Descrição
+ adição
- subtração
* multiplicação
/ divisão
^ ou ** exponencial
x %% y modulus: ao dividir x por y, %% retorna o resto
5+7
## [1] 12
2-1
## [1] 1
4*2 # 4 vezes 2
## [1] 8
15/3 # 15 dividido por 3
## [1] 5
2^3 # dois elevado a 3
## [1] 8
3**2 # 3 elevado a 2
## [1] 9

Como no operador %% nos dá a sobra da divisão (relembrando, os outros elementos da divisão são dividendo, divisor, quociente ou produto), a operação x %% y == 0 nos diz se há ou não resto, e portando, diz se x é divisível por y.

10 %% 3
## [1] 1
10 %% 5
## [1] 0
# De 1 a 10, quais são múltiplos de 2? (retorna lógicos)
1:10 %% 2 == 0
##  [1] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
# múltiplos de 2 até 10
(1:10)[1:10 %% 2 == 0]
## [1]  2  4  6  8 10
# múltiplos de 3 até 15
(1:15)[1:15 %% 3 == 0]
## [1]  3  6  9 12 15

Há ainda o operador %/%, utilizado em divisão integral.

4.5.3 Operadores relacionais

Operador Descrição
< menor que
<= menor ou igual a
> maior que
>= maior ou igual que
== exatamente igual a
!= diferente de
5>6
## [1] FALSE
7<=6
## [1] FALSE
variavel <- "teste"
variavel == "abacate"
## [1] FALSE
variavel != "TESTE"
## [1] TRUE

4.5.4 Operadores booleanos

E OU NÃO
AND OR NOT
Símbolos & | !
No R também temos && || !
Operador Descrição
!= não igual a
!x não x
x | y x ou y
x & y x E y
isTRUE(x) teste se X é TRUE

https://stat.ethz.ch/R-manual/R-devel/library/base/html/Logic.html

txt <- c("bla bla", "bla ble", "bla bli", "bla non")
grep('bla (bla|ble)', txt, value =T)
## [1] "bla bla" "bla ble"
y <- c("bla", "ble", "bli")
y=="bla"
## [1]  TRUE FALSE FALSE
y!="bla"
## [1] FALSE  TRUE  TRUE

Algumas buscas na internet disponibilizam alguns operadores. No portal da Cãmara dos deputados, pode-se buscar discursos dos parlamentares no banco de discursos utilizando “and” e “or” (link aqui). Na busca do Google, é possível excluir termos da busca (no caso, o operador “NOT”), utilizando o sinal de menos antes do termo.

4.5.5 Outros operadores

Operador Descrição
: Cria uma sequência de números em uma sequência
%in% Se um elemento pertence/está contido em um vetor de elementos
%*% Multiplicação de matrizes
# geranto automaticamente uma sequencia de 5 a 10
x <- 5:10
x
## [1]  5  6  7  8  9 10
# gerando uma sequencia de letras minúsculas
letters[1:5]
## [1] "a" "b" "c" "d" "e"
# gerando uma sequencia de letras miúsculas
LETTERS[5:10]
## [1] "E" "F" "G" "H" "I" "J"

# checando se os numeros estão contidos no vetor x
2 %in% x
## [1] FALSE
7 %in% x
## [1] TRUE

# Num outro exemplo, vamos usar o operador para checar intesecção entre dois vetores
v1 <- c("a", "b", "c", 1, 2, 67, 53, 73)
v2 <- c("x", "y", "z", "2", "h", "j", "c")
# obtendo um vetor com booleanos (TRUE e FALSE) de todos os elementos
v1 %in% v2
## [1] FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE
# observando apenas os elementos que tem intersecção entre os vetores
v1[v1 %in% v2]
## [1] "c" "2"

Num exemplo prático do operador %in%, o comando colors() lista as cores que possuem nome no R. Com o operador %in%, podemos checar se um nome de cor específico ou um vetor de nomes está presente no vetor de cores que o comando colors() retorna.

"darkred" %in% colors() 
## [1] TRUE
# Um vetor
c("darkred", "lightred") %in% colors()
## [1]  TRUE FALSE

4.6 Loops, repetições

4.6.1 For Loops

Quando necessita de fazer uma mesma operação, repetida, em vários itens de uma lista, usamos os loops. Com loops iteramos, aplicamos uma operação a cada item de uma série de itens.

for (item in variavel_com_varios_itens){
         faça algo com cada item n da variável
}

Por exemplo:

x <- c(1, 3, 5)

# o loop abaixo pegará os elementos 1,3 e 5
# e adicionará 1 a cada um deles.
for (i in x){
  print(i+1)
}
## [1] 2
## [1] 4
## [1] 6

Também podemos aplicar loops a strings:

x <- c('bla', 'ble')

for (i in x){
  print(paste('Alguém disse: ', i))
}
## [1] "Alguém disse:  bla"
## [1] "Alguém disse:  ble"
nomes <- c("Fulano", "Beltrano", "Maria", "Karen") 
for(i in nomes) {
  # o comando nchar() conta quantos caracteres há no item
  print(paste("O nome", i, "contém", nchar(i), "caracteres."))
}
## [1] "O nome Fulano contém 6 caracteres."
## [1] "O nome Beltrano contém 8 caracteres."
## [1] "O nome Maria contém 5 caracteres."
## [1] "O nome Karen contém 5 caracteres."

4.6.2 While loop

O for loops é usado quando temos uma lista que sabemos quantos elementos temos. Para o caso de não sabermos ao certo quantos e quais elementos temos, há ainda um outro tipo de loop em programação, o while loop, que diz enquanto uma condição for verdadeira, ela continuará rodando, e irá parar assim que for falsa.

# criando a variável "i" de valor 1
i <- 1
# Enquanto a condição i for menor que 7, continue
while (i < 7) {
  # imprime a mensagem 
  message(i, " é menor que 7")
  # adiciona 1 ao valor de i
  i <- i + 1
  # volta ao início
}
## 1 é menor que 7
## 2 é menor que 7
## 3 é menor que 7
## 4 é menor que 7
## 5 é menor que 7
## 6 é menor que 7

No exemplo acima, criamos a variável “i” que tem valor 1, e dentro do loop há a operação de acrescentar +1 a cada “rodada” do loop, que começa com o valor “1”. A cada rodada, o loop avalia se a condição i < 7 é verdadeira. Se sim, imprime o valor atual da variável i e adiciona +1 ao valor de i. O loop continua rodando para o próximo item. Assim que chega em 7, o loop pára, já que “7 < 7” é falso.

4.6.3 apply (lapply, sapply, tapply e mapply)

Além de for loop e while loop, no R temos a família apply (lapply, sapply, tapply e mapply), que funciona como um for loop normal, mas que pode simplificar um pouco a repetição, além de ser mais rápido que o for loop. Entretanto, o apply funciona aplicando uma função já pré definida anteriormente.

Assim, no nosso exemplo com o vetor

nomes <- c("Fulano", "Beltrano", "Maria", "Karen")

Em que aplicamos o for loop

for(i in nomes) {
  # o comando nchar() conta quantos caracteres há no item
  print(nchar(i))
}
## [1] 6
## [1] 8
## [1] 5
## [1] 5

Podemos fazer algo parecido com o apply

sapply(nomes, nchar)
##   Fulano Beltrano    Maria    Karen 
##        6        8        5        5

Além de forloops e da família apply, o R conta também com:

  • família de funções map_ do pacote purrr do tidyverse
  • pacote foreach, que possibilita forloops com processamento paralelo, isto é, mais rápido.
  • As funções do purrr também podem ser paralelizadas para ficarem mais rápidas através do pacote furrr.