4.5 Tipos de Dados e Dados Faltantes

Como discutido em Section 4.1, CSV.jl fará o seu melhor para adivinhar os tipo de dados das colunas de sua tabela. No entanto, isso nem sempre funcionará perfeitamente. Nesta seção, mostramos porque os tipos adequados são importantes e corrigimos os tipos de dados incorretos. Para ser mais claro sobre os tipos, mostramos a saída de texto para DataFrames ao invés de uma tabela bem formatada. Nesta seção, trabalharemos com o seguinte dataset:

function wrong_types()
    id = 1:4
    date = ["28-01-2018", "03-04-2019", "01-08-2018", "22-11-2020"]
    age = ["adolescent", "adult", "infant", "adult"]
    DataFrame(; id, date, age)
end
wrong_types()
4×3 DataFrame
 Row │ id     date        age
     │ Int64  String      String
─────┼───────────────────────────────
   1 │     1  28-01-2018  adolescent
   2 │     2  03-04-2019  adult
   3 │     3  01-08-2018  infant
   4 │     4  22-11-2020  adult

Como a coluna de data tem o tipo incorreto, a ordenação dessa coluna não funcionará corretamente:

sort(wrong_types(), :date)
4×3 DataFrame
 Row │ id     date        age
     │ Int64  String      String
─────┼───────────────────────────────
   1 │     3  01-08-2018  infant
   2 │     2  03-04-2019  adult
   3 │     4  22-11-2020  adult
   4 │     1  28-01-2018  adolescent

Para corrigir a ordenação, podemos usar o módulo Date da biblioteca padrão de Julia, conforme descrito em Section 3.4.1:

function fix_date_column(df::DataFrame)
    strings2dates(dates::Vector) = Date.(dates, dateformat"dd-mm-yyyy")
    dates = strings2dates(df[!, :date])
    df[!, :date] = dates
    df
end
fix_date_column(wrong_types())
4×3 DataFrame
 Row │ id     date        age
     │ Int64  Date        String
─────┼───────────────────────────────
   1 │     1  2018-01-28  adolescent
   2 │     2  2019-04-03  adult
   3 │     3  2018-08-01  infant
   4 │     4  2020-11-22  adult

Agora, a ordenação funcionará conforme o planejado:

df = fix_date_column(wrong_types())
sort(df, :date)
4×3 DataFrame
 Row │ id     date        age
     │ Int64  Date        String
─────┼───────────────────────────────
   1 │     1  2018-01-28  adolescent
   2 │     3  2018-08-01  infant
   3 │     2  2019-04-03  adult
   4 │     4  2020-11-22  adult

Para a coluna age (idade), temos um problema semelhante:

sort(wrong_types(), :age)
4×3 DataFrame
 Row │ id     date        age
     │ Int64  String      String
─────┼───────────────────────────────
   1 │     1  28-01-2018  adolescent
   2 │     2  03-04-2019  adult
   3 │     4  22-11-2020  adult
   4 │     3  01-08-2018  infant

Isso não está certo, porque uma criança é mais jovem do que adultos e adolescentes. A solução para este problema e para qualquer tipo de dado categórico é usar CategoricalArrays.jl:

using CategoricalArrays

Com o pacote CategoricalArrays.jl, podemos adicionar níveis que representam a ordem da variável categórica em questão para nossos dados:

function fix_age_column(df)
    levels = ["infant", "adolescent", "adult"]
    ages = categorical(df[!, :age]; levels, ordered=true)
    df[!, :age] = ages
    df
end
fix_age_column(wrong_types())
4×3 DataFrame
 Row │ id     date        age
     │ Int64  String      Cat…
─────┼───────────────────────────────
   1 │     1  28-01-2018  adolescent
   2 │     2  03-04-2019  adult
   3 │     3  01-08-2018  infant
   4 │     4  22-11-2020  adult

OBESERVAÇÃO: Observe também que estamos passando o argumento ordered=true que diz para a função categorical do módulo CategoricalArrays.jl que nossos dados categóricos são “ordenados.” Sem isso, qualquer tipo de ordenação ou de comparações do tipo maior/menor não seria possível.

Agora, podemos classificar os dados corretamente na coluna age (idade):

df = fix_age_column(wrong_types())
sort(df, :age)
4×3 DataFrame
 Row │ id     date        age
     │ Int64  String      Cat…
─────┼───────────────────────────────
   1 │     3  01-08-2018  infant
   2 │     1  28-01-2018  adolescent
   3 │     2  03-04-2019  adult
   4 │     4  22-11-2020  adult

Como definimos funções convenientes, agora podemos definir nossos dados fixos apenas executando as chamadas de função:

function correct_types()
    df = wrong_types()
    df = fix_date_column(df)
    df = fix_age_column(df)
end
correct_types()
4×3 DataFrame
 Row │ id     date        age
     │ Int64  Date        Cat…
─────┼───────────────────────────────
   1 │     1  2018-01-28  adolescent
   2 │     2  2019-04-03  adult
   3 │     3  2018-08-01  infant
   4 │     4  2020-11-22  adult

Já que a variável age (idade) em nossos dados é ordinal (ordered=true), podemos comparar adequadamente as categorias de idade:

df = correct_types()
a = df[1, :age]
b = df[2, :age]
a < b
true

o que daria comparações erradas se o tipo de elemento fosse strings:

"infant" < "adult"
false


CC BY-NC-SA 4.0 Jose Storopoli, Rik Huijzer, Lazaro Alonso