Criar Funções no R

Inicialmente, tenho uma dúvida sobre como fazer uma função pra diminuir minha repetição de códigos como esse:

dadosLB$data_criacao <- as.Date(as.character(dadosLB$data_criacao),
                                                    format = "%Y-%m-%d")
dadosSP$data_criacao <- as.Date(as.character(dadosSP$data_criacao),
                                                           format = "%Y-%m-%d")
dadosS1M$data_criacao <- as.Date(as.character(dadosS1M$data_criacao),
                                                         format = "%Y-%m-%d")
dadosS3M$data_criacao <- as.Date(as.character(dadosS3M$data_criacao),
                                                         format = "%Y-%m-%d").

Não tenho o costume de utilizar funções e quero MUITO dar esse passo aí no R. Quem puder me dar um help com esse código aí e com materiais legais agradeço.

Olá Fernanda

Eu tentaria colocar todos os dataframes numa lista

lista <- list(dadosLB, dadosS1M, dadosS3M, dadosSP)

for (i in 1:length(lista)) {
  df <- lista[[i]]
  
  df$data_criacao <-
    as.Date(as.character(df$data_criacao),
            format = "%Y-%m-%d")
  
  lista[[i]] <- df
  rm(df)
}

E pra fins de termos esse ciclo em uma função:

nomeDaFuncao <- function(lista) {
  for (i in 1:length(lista)) {
    df <- lista[[i]]

    df$data_criacao <-
      as.Date(as.character(df$data_criacao),
              format = "%Y-%m-%d")

lista[[i]] <- df
rm(df)
 }
}

É o que eu faria, espero que ajude
Humberto

2 curtidas

Fernanda,

Uma função não passa de um trecho de código que recebe uma entrada e retorna um resultado. No seu caso, você quer cortar a repetição do as.Date ..., então vamos pensar nas entradas e nas saídas para que possamos abstraí-las:

  1. Qual é a entrada? O que muda de uma linha para a outra, no geral, é a entrada. Isso faz sentido porque a função sempre aplica o mesmo código e o que varia é o que será passado para ela. Nesse caso, as colunas são as entradas: dadosLB$data_criacao, dadosSP$data_criacao, etc.

  2. Qual é a saída? Analogamente, a saída é o resultado que queremos da função dada aquela entrada específica. Nesse caso, os valores sendo atribuídos (<-) são as saídas.

Note como você mesma já está usando duas funções no seu código: as.character() e as.Date(). A primeira recebe um vetor em qualquer formato e converte ele para string; a segunda recebe um vetor de strings e converte ele para datas (e repare no argumento format! Além do argumento principal, o vetor, a função recebe mais um argumento que muda o seu comportamento… Isso pode ser muito útil quando quisermos fazer funções mais complexas).

Então tá, como fica a nossa função? Criá-la é bastante simples, basta pegar o código que produz a saída e substituir as entradas por um argumento genérico (ou seja, que poderá ser substituído pelas suas colunas).

formatar_data <- function(coluna) {
  as.Date(as.character(coluna), format = "%Y-%m-%d")
}

dadosLB$data_criacao <- formatar_data(dadosLB$data_criacao)
dadosSP$data_criacao <- formatar_data(dadosSP$data_criacao)
dadosS1M$data_criacao <- formatar_data(dadosS1M$data_criacao)
dadosS3M$data_criacao <- formatar_data(dadosS3M$data_criacao)

Para visualizar que essa função de fato faz o que queremos, basta substituir o nome dela pelo seu corpo. Ao fazer essa substituição, também trocamos os argumentos pelos seus valores reais:

# Chamada com a funcao nova
dadosLB$data_criacao <- formatar_data(dadosLB$data_criacao)

# Substituir o nome pelo corpo
dadosLB$data_criacao <- as.Date(as.character(coluna), format = "%Y-%m-%d")

# Substituir o argumento pelo valor passado
dadosLB$data_criacao <- as.Date(as.character(dadosLB$data_criacao), format = "%Y-%m-%d")

E prontinho! Voltamos ao seu código original. Espero que a explicação tenha feito sentido.

2 curtidas

Oi Fe! Vi aqui que duas pessoas já responderam, mas não tinha resposta ainda quando eu abri…

como eu fiz uma resposta um pouco diferente das outras, vou colar a forma que eu pensei também!

# criando umas bases de exemplo,
# as bases tem nome de coluna diferente
ex_1 <- tibble::tibble(data_criacao = c("2022-02-28", "2022-01-29", "2022-02-15"))
ex_2 <- tibble::tibble(data = c("2022-02-28", "2022-01-29", "2022-02-15"))



# a funcao transformar data usa seu codigo, e recebendo uma base de dados e o nome da coluna, transforma a coluna
transformar_data <- function(data, col){
    dplyr::mutate(data, {{col}} :=  as.Date(as.character(.data[[col]]),
                          format = "%Y-%m-%d"))
}

# exemplos de uso
ex_12 <- transformar_data(ex_1, "data_criacao")
ex_12
#> # A tibble: 3 × 1
#>   data_criacao
#>   <date>      
#> 1 2022-02-28  
#> 2 2022-01-29  
#> 3 2022-02-15

ex_22 <- transformar_data(ex_2, "data")
ex_22
#> # A tibble: 3 × 1
#>   data      
#>   <date>    
#> 1 2022-02-28
#> 2 2022-01-29
#> 3 2022-02-15


# dentro da função também daria pra usar o parse_date:
transformar_data_parse <- function(data, col){
  dplyr::mutate(data, {{col}} :=  readr::parse_date(.data[[col]],
                                          format = "%Y-%m-%d"))
}

ex_13 <- transformar_data_parse(ex_1, "data_criacao")
ex_13
#> # A tibble: 3 × 1
#>   data_criacao
#>   <date>      
#> 1 2022-02-28  
#> 2 2022-01-29  
#> 3 2022-02-15

ex_23 <- transformar_data_parse(ex_2, "data")
ex_23
#> # A tibble: 3 × 1
#>   data      
#>   <date>    
#> 1 2022-02-28
#> 2 2022-01-29
#> 3 2022-02-15

Created on 2022-03-11 by the reprex package (v2.0.0.9000)

Bom, acho que a solução que o Caio deu ficou mais fácil aiuhauhauia mas é legal ver formas diferentes de fazer a mesma coisa :slight_smile:

Edit!

Eu acho que algo que é bom citar é que a solução que eu fiz fica pipeável, por exemplo:

transformar_data <- function(data, col){
  dplyr::mutate(data, {{col}} :=  as.Date(as.character(.data[[col]]),
                                          format = "%Y-%m-%d"))
}

base_com_varias_colunas_pra_tratar <- tibble::tibble(
  data_criacao = c("2022-02-28", "2022-01-29", "2022-02-15"),
  data = c("2022-02-28", "2022-01-29", "2022-02-15"),
  data_final = c("2022-02-28", "2022-01-29", "2022-02-15")
)

base_com_varias_colunas_pra_tratar
#> # A tibble: 3 × 3
#>   data_criacao data       data_final
#>   <chr>        <chr>      <chr>     
#> 1 2022-02-28   2022-02-28 2022-02-28
#> 2 2022-01-29   2022-01-29 2022-01-29
#> 3 2022-02-15   2022-02-15 2022-02-15


base_com_varias_colunas_pra_tratar |> 
  transformar_data("data_criacao") |> 
  transformar_data("data") |> 
  transformar_data("data_final")
#> # A tibble: 3 × 3
#>   data_criacao data       data_final
#>   <date>       <date>     <date>    
#> 1 2022-02-28   2022-02-28 2022-02-28
#> 2 2022-01-29   2022-01-29 2022-01-29
#> 3 2022-02-15   2022-02-15 2022-02-15

Created on 2022-03-11 by the reprex package (v2.0.0.9000)

2 curtidas

Só um pequeno adendo por completude. Se a Fernanda tiver várias bases diferentes e não uma base só com várias colunas, a solução da @beatrizmilz ficaria assim:

formatar_data <- function(coluna) {
  as.Date(as.character(coluna), format = "%Y-%m-%d")
}

dados <- list(
  dadosLB,
  dadosSP,
  dadosS1M,
  dadosS3M
)

dados %>%
  purrr::map(dplyr::mutate, data_criacao = formatar_data(data_criacao))
4 curtidas