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 DataFrame
s 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çãocategorical
do móduloCategoricalArrays.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