Funções na programação R com exemplo

O que é uma função em R?

A função, em um ambiente de programação, é um conjunto de instruções. Um programador constrói uma função para evitar repetindo o mesma tarefa ou reduzir complexidade.

Uma função deve ser

  • escrito para realizar uma tarefa específica
  • pode ou não incluir argumentos
  • contém um corpo
  • pode ou não retornar um ou mais valores.

Uma abordagem geral para uma função é usar a parte do argumento como inputs, alimente o corpo parte e finalmente retornar um saída. A sintaxe de uma função é a seguinte:

function (arglist)  {
  #Function body
}

R funções integradas importantes

Existem muitas funções integradas em R. R combina seus parâmetros de entrada com seus argumentos de função, por valor ou por posição, e então executa o corpo da função. Os argumentos da função podem ter valores padrão: se você não especificar esses argumentos, R assumirá o valor padrão.
Note:
É possível ver o código fonte de uma função executando o nome da própria função no console.

R Funções integradas importantes

Veremos três grupos de funções em ação

  • Função geral
  • Função matemática
  • Função estatística

Funções gerais

Já estamos familiarizados com funções gerais como funções cbind(), rbind(),range(),sort(),order(). Cada uma dessas funções possui uma tarefa específica, recebe argumentos para retornar uma saída. A seguir estão funções importantes que você deve conhecer

função diff()

Se você trabalhar em série temporal, você precisa estacionar a série tomando seus valores de atraso. UMA processo estacionário permite média, variância e autocorrelação constantes ao longo do tempo. Isso melhora principalmente a previsão de uma série temporal. Isso pode ser feito facilmente com a função diff(). Podemos construir uma série temporal aleatória de dados com uma tendência e então usar a função diff() para estacionar a série. A função diff() aceita um argumento, um vetor, e retorna uma diferença defasada e iterada adequada.

Note: Muitas vezes precisamos criar dados aleatórios, mas para aprendizado e comparação queremos que os números sejam idênticos em todas as máquinas. Para garantir que todos geremos os mesmos dados, usamos a função set.seed() com valores arbitrários de 123. A função set.seed() é gerada através do processo de gerador de números pseudoaleatórios que faz com que todos os computadores modernos tenham a mesma sequência de números. Se não usarmos a função set.seed(), todos teremos sequências de números diferentes.

set.seed(123)
## Create the data
x = rnorm(1000)
ts <- cumsum(x)
## Stationary the serie
diff_ts <- diff(ts)
par(mfrow=c(1,2))
## Plot the series
plot(ts, type='l')
plot(diff(ts), type='l')

Função Diferença()

função comprimento()

Em muitos casos, queremos saber comprimento de um vetor para cálculo ou para ser usado em um loop for. A função length() conta o número de linhas no vetor x. Os códigos a seguir importam o conjunto de dados cars e retornam o número de linhas.

Note: length() retorna o número de elementos em um vetor. Se a função for passada para uma matriz ou quadro de dados, o número de colunas será retornado.

dt <- cars
## number columns
length(dt)

Saída:

## [1] 1
## number rows
length(dt[,1])

Saída:

## [1] 50

Funções matemáticas

R tem um array de funções matemáticas.

Operator Descrição
abs (x) Toma o valor absoluto de x
registro(x,base=y) Toma o logaritmo de x com base y; se a base não for especificada, retorna o logaritmo natural
exp (x) Retorna a exponencial de x
sqrt (x) Retorna a raiz quadrada de x
fatorial (x) Retorna o fatorial de x (x!)
# sequence of number from 44 to 55 both including incremented by 1
x_vector <- seq(45,55, by = 1)
#logarithm
log(x_vector)

Saída:

##  [1] 3.806662 3.828641 3.850148 3.871201 3.891820 3.912023 3.931826
##  [8] 3.951244 3.970292 3.988984 4.007333
#exponential
exp(x_vector)
#squared root
sqrt(x_vector)

Saída:

##  [1] 6.708204 6.782330 6.855655 6.928203 7.000000 7.071068 7.141428
##  [8] 7.211103 7.280110 7.348469 7.416198
#factorial
factorial(x_vector)

Saída:

##  [1] 1.196222e+56 5.502622e+57 2.586232e+59 1.241392e+61 6.082819e+62
##  [6] 3.041409e+64 1.551119e+66 8.065818e+67 4.274883e+69 2.308437e+71
## [11] 1.269640e+73

Funções estatísticas

A instalação padrão do R contém uma ampla gama de funções estatísticas. Neste tutorial, veremos brevemente a função mais importante.

Funções estatísticas básicas

Operator Descrição
média(x) Média de x
mediana (x) Mediana de x
var(x) Variância de x
sd(x) Desvio padrão de x
escala (x) Pontuações padrão (pontuações z) de x
quantil (x) Os quartis de x
resumo(x) Resumo de x: média, mínimo, máximo etc.
speed <- dt$speed
speed
# Mean speed of cars dataset
mean(speed)

Saída:

## [1] 15.4
# Median speed of cars dataset
median(speed)

Saída:

## [1] 15
# Variance speed of cars dataset
var(speed)

Saída:

## [1] 27.95918
# Standard deviation speed of cars dataset
sd(speed)

Saída:

## [1] 5.287644
# Standardize vector speed of cars dataset		
head(scale(speed), 5)

Saída:

##           [,1]
## [1,] -2.155969
## [2,] -2.155969
## [3,] -1.588609
## [4,] -1.588609
## [5,] -1.399489
# Quantile speed of cars dataset
quantile(speed)

Saída:

##   0%  25%  50%  75% 100%
##    4   12   15   19   25
# Summary speed of cars dataset
summary(speed)

Saída:

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
##     4.0    12.0    15.0    15.4    19.0    25.0

Até este ponto, aprendemos muitas funções integradas do R.

Note: Tenha cuidado com a classe do argumento, ou seja, numérico, booleano ou string. Por exemplo, se precisarmos passar um valor de string, precisamos colocar a string entre aspas: “ABC” .

Função de gravação em R

Em algumas ocasiões, precisamos escrever nossa própria função porque temos que realizar uma tarefa específica e não existe nenhuma função pronta. Uma função definida pelo usuário envolve um nome, argumentos e de um corpo.

function.name <- function(arguments) 
{
    computations on the arguments	
    some other code
}		

Note: uma boa prática é nomear uma função definida pelo usuário diferente de uma função integrada. Isso evita confusão.

Função de um argumento

No próximo trecho, definimos uma função quadrada simples. A função aceita um valor e retorna o quadrado do valor.

square_function<- function(n) 
{
  # compute the square of integer `n`
  n^2
}  
# calling the function and passing value 4
square_function(4)

Explicação do código

  • A função é denominada função_quadrada; pode ser chamado como quisermos.
  • Recebe um argumento “n”. Nós não especificou o tipo de variável para que o usuário possa passar um inteiro, um vetor ou uma matriz
  • A função pega a entrada “n” e retorna o quadrado da entrada. Quando terminar de usar a função, podemos removê-la com a função rm().

# depois de criar a função

rm(square_function)
square_function

No console, podemos ver uma mensagem de erro: Erro: objeto 'square_function' não encontrado informando que a função não existe.

Escopo do ambiente

Em R, o meio Ambiente é um coleção de objetos como funções, variáveis, quadro de dados, etc.

R abre um ambiente sempre que o Rstudio é solicitado.

O ambiente de nível superior disponível é o ambiente global, chamado R_GlobalEnv. E nós temos o ambiente local.

Podemos listar o conteúdo do ambiente atual.

ls(environment())

saída

## [1] "diff_ts"         "dt"              "speed"           "square_function"
## [5] "ts"              "x"               "x_vector"

Você pode ver todas as variáveis ​​e funções criadas no R_GlobalEnv.

A lista acima irá variar para você com base no código histórico executado no R Studio.

Observe que n, o argumento da função square_function é não neste ambiente global.

A novo ambiente é criado para cada função. No exemplo acima, a função square_function() cria um novo ambiente dentro do ambiente global.

Para esclarecer a diferença entre global e ambiente local, vamos estudar o seguinte exemplo

Essas funções pegam um valor x como argumento e o adicionam a y definido fora e dentro da função

Escopo do ambiente

A função f retorna a saída 15. Isso ocorre porque y é definido no ambiente global. Qualquer variável definida no ambiente global pode ser usada localmente. A variável y tem o valor 10 durante todas as chamadas de função e está acessível a qualquer momento.

Vamos ver o que acontece se a variável y for definida dentro da função.

Precisamos eliminar `y` antes de executar este código usando rm r

Escopo do ambiente

A saída também é 15 quando chamamos f(5), mas retorna um erro quando tentamos imprimir o valor y. A variável y não está no ambiente global.

Finalmente, R usa a definição de variável mais recente para passar dentro do corpo de uma função. Vamos considerar o seguinte exemplo:

Escopo do ambiente

R ignora os valores y definidos fora da função porque criamos explicitamente uma variável y dentro do corpo da função.

Função multiargumentos

Podemos escrever uma função com mais de um argumento. Considere a função chamada “tempos”. É uma função simples que multiplica duas variáveis.

times <- function(x,y) {
  x*y
	}
times(2,4)

Saída:

## [1] 8

Quando devemos escrever a função?

O cientista de dados precisa realizar muitas tarefas repetitivas. Na maioria das vezes, copiamos e colamos trechos de código repetidamente. Por exemplo, a normalização de uma variável é altamente recomendada antes de executarmos um aprendizado de máquina algoritmo. A fórmula para normalizar uma variável é:

Fórmula para normalizar uma variável

Já sabemos como usar as funções min() e max() em R. Usamos a biblioteca tibble para criar o quadro de dados. Até agora, Tibble é a função mais conveniente para criar um conjunto de dados do zero.

library(tibble)
# Create a data frame
data_frame <- tibble(  
  c1 = rnorm(50, 5, 1.5), 
  c2 = rnorm(50, 5, 1.5),    
  c3 = rnorm(50, 5, 1.5),    
)

Procederemos em duas etapas para calcular a função descrita acima. Na primeira etapa, criaremos uma variável chamada c1_norm que é o reescalonamento de c1. Na segunda etapa, apenas copiamos e colamos o código c1_norm e alteramos com c2 e c3.

Detalhe da função com a coluna c1:

Nominador:: data_frame$c1 -min(data_frame$c1))

Denominador: max(data_frame$c1)-min(data_frame$c1))

Portanto, podemos dividi-los para obter o valor normalizado da coluna c1:

(data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))

Podemos criar c1_norm, c2_norm e c3_norm:

Create c1_norm: rescaling of c1		
data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))
# show the first five values
head(data_frame$c1_norm, 5)

Saída:

## [1] 0.3400113 0.4198788 0.8524394 0.4925860 0.5067991

Funciona. Podemos copiar e colar

data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))

em seguida, altere c1_norm para c2_norm e c1 para c2. Fazemos o mesmo para criar c3_norm

data_frame$c2_norm <- (data_frame$c2 - min(data_frame$c2))/(max(data_frame$c2)-min(data_frame$c2))
data_frame$c3_norm <- (data_frame$c3 - min(data_frame$c3))/(max(data_frame$c3)-min(data_frame$c3))

Redimensionamos perfeitamente as variáveis ​​c1, c2 e c3.

No entanto, este método está sujeito a erros. Poderíamos copiar e esquecer de alterar o nome da coluna após colar. Portanto, uma boa prática é escrever uma função cada vez que precisar colar o mesmo código mais de duas vezes. Podemos reorganizar o código em uma fórmula e chamá-lo sempre que necessário. Para escrever nossa própria função, precisamos fornecer:

  • Nome: normalizar.
  • o número de argumentos: precisamos apenas de um argumento, que é a coluna que usamos em nosso cálculo.
  • O corpo: esta é simplesmente a fórmula que queremos retornar.

Procederemos passo a passo para criar a função normalizar.

Passo 1) Nós criamos o nominador, qual é . Em R, podemos armazenar o nomeador em uma variável como esta:

nominator <- x-min(x)

Passo 2) nós calculamos o denominador: . Podemos replicar a ideia do passo 1 e armazenar o cálculo em uma variável:

denominator <- max(x)-min(x)

Passo 3) Realizamos a divisão entre o denominador e o denominador.

normalize <- nominator/denominator

Passo 4) Para retornar valor para a função de chamada, precisamos passar normalize dentro de return() para obter a saída da função.

return(normalize)

Passo 5) Estamos prontos para usar a função envolvendo tudo dentro do colchete.

normalize <- function(x){
  # step 1: create the nominator
  nominator <- x-min(x)
  # step 2: create the denominator
  denominator <- max(x)-min(x)
  # step 3: divide nominator by denominator
  normalize <- nominator/denominator
  # return the value
  return(normalize)
}

Vamos testar nossa função com a variável c1:

normalize(data_frame$c1)

Funciona perfeitamente. Criamos nossa primeira função.

As funções são uma forma mais abrangente de realizar uma tarefa repetitiva. Podemos usar a fórmula de normalização em diferentes colunas, como abaixo:

data_frame$c1_norm_function <- normalize (data_frame$c1)
data_frame$c2_norm_function <- normalize	(data_frame$c2)
data_frame$c3_norm_function <- normalize	(data_frame$c3)

Embora o exemplo seja simples, podemos inferir o poder de uma fórmula. O código acima é mais fácil de ler e principalmente evita erros ao colar códigos.

Funções com condição

Às vezes, precisamos incluir condições em uma função para permitir que o código retorne resultados diferentes.

Nas tarefas de aprendizado de máquina, precisamos dividir o conjunto de dados entre um conjunto de treinamento e um conjunto de teste. O conjunto de trens permite que o algoritmo aprenda com os dados. Para testar o desempenho do nosso modelo, podemos usar o conjunto de testes para retornar a medida de desempenho. R não possui uma função para criar dois conjuntos de dados. Podemos escrever nossa própria função para fazer isso. Nossa função recebe dois argumentos e é chamada split_data(). A ideia por trás é simples: multiplicamos o comprimento do conjunto de dados (ou seja, número de observações) por 0.8. Por exemplo, se quisermos dividir o conjunto de dados 80/20, e nosso conjunto de dados contiver 100 linhas, então nossa função irá multiplicar 0.8*100 = 80. 80 linhas serão selecionadas para se tornarem nossos dados de treinamento.

Usaremos o conjunto de dados de qualidade do ar para testar nossa função definida pelo usuário. O conjunto de dados de qualidade do ar possui 153 linhas. Podemos ver isso com o código abaixo:

nrow(airquality)

Saída:

## [1] 153

Procederemos da seguinte forma:

split_data <- function(df, train = TRUE)
Arguments:
-df: Define the dataset
-train: Specify if the function returns the train set or test set. By default, set to TRUE

Nossa função tem dois argumentos. O trem de argumentos é um parâmetro booleano. Se estiver definido como TRUE, nossa função cria o conjunto de dados de trem, caso contrário, cria o conjunto de dados de teste.

Podemos proceder como fizemos com a função normalise(). Escrevemos o código como se fosse apenas um código único e, em seguida, agrupamos tudo com a condição no corpo para criar a função.

-

Precisamos calcular o comprimento do conjunto de dados. Isso é feito com a função nrow(). Nrow retorna o número total de linhas no conjunto de dados. Chamamos o comprimento variável.

length<- nrow(airquality)
length

Saída:

## [1] 153

-

Multiplicamos o comprimento por 0.8. Ele retornará o número de linhas a serem selecionadas. Deve ser 153 * 0.8 = 122.4

total_row <- length*0.8
total_row

Saída:

## [1] 122.4

Queremos selecionar 122 linhas entre as 153 linhas do conjunto de dados de qualidade do ar. Criamos uma lista contendo valores de 1 a total_row. Armazenamos o resultado na variável chamada split

split <- 1:total_row
split[1:5]

Saída:

## [1] 1 2 3 4 5

split escolhe as primeiras 122 linhas do conjunto de dados. Por exemplo, podemos ver que nossa variável split reúne os valores 1, 2, 3, 4, 5 e assim por diante. Esses valores serão o índice quando selecionarmos as linhas a serem retornadas.

-

Precisamos selecionar as linhas no conjunto de dados de qualidade do ar com base nos valores armazenados na variável de divisão. Isso é feito assim:

train_df <- airquality[split, ] 
head(train_df)

Saída:

##[1]    Ozone Solar.R Wind Temp Month Day
##[2]  51    13     137 10.3   76     6  20
##[3]  15    18      65 13.2   58     5  15
##[4]  64    32     236  9.2   81     7   3
##[5]  27    NA      NA  8.0   57     5  27
##[6]  58    NA      47 10.3   73     6  27
##[7]  44    23     148  8.0   82     6  13

-

Podemos criar o conjunto de dados de teste usando as linhas restantes, 123:153. Isso é feito usando – na frente de split.

test_df <- airquality[-split, ] 
head(test_df)

Saída:

##[1] Ozone Solar.R Wind Temp Month Day
##[2]  123    85     188  6.3   94     8  31
##[3]  124    96     167  6.9   91     9   1
##[4]  125    78     197  5.1   92     9   2
##[5]  126    73     183  2.8   93     9   3
##[6]  127    91     189  4.6   93     9   4
##[7]  128    47      95  7.4   87     9   5

-

Podemos criar a condição dentro do corpo da função. Lembre-se, temos um trem de argumentos que é um booleano definido como TRUE por padrão para retornar o conjunto de trens. Para criar a condição, usamos a sintaxe if:

  if (train ==TRUE){ 
    train_df <- airquality[split, ] 
      return(train)		
  } else {
    test_df <- airquality[-split, ] 
      return(test)		
  }

É isso, podemos escrever a função. Precisamos apenas alterar a qualidade do ar para df porque queremos testar nossa função para qualquer quadro de dados, não apenas qualidade do ar:

split_data <- function(df, train = TRUE){
  length<- nrow(df)
  total_row <- length *0.8
  split <- 1:total_row
  if (train ==TRUE){ 
    train_df <- df[split, ] 
      return(train_df)		
  } else {
    test_df <- df[-split, ] 
      return(test_df)		
  }
}

Vamos tentar nossa função no conjunto de dados de qualidade do ar. deveríamos ter um conjunto de trem com 122 linhas e um conjunto de teste com 31 linhas.

train <- split_data(airquality, train = TRUE)
dim(train)

Saída:

## [1] 122   6
test <- split_data(airquality, train = FALSE)
dim(test)

Saída:

## [1] 31  6