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
因为日期列的类型并不正确,所以 sort
并不能正常工作:
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
为了修复此问题,可以使用在 Section 3.5.1 中提到的 Julia 标准库 Date
模块:
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
─────┼───────────────────────────────
1 │ 1 2018-01-28 adolescent
2 │ 2 2019-04-03 adult
3 │ 3 2018-08-01 infant
4 │ 4 2020-11-22 adult
现在,排序的结果与预期相符:
df = fix_date_column(wrong_types())
sort(df, :date)
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
这显然不正确,因为婴儿比成年人和青少年更年轻。 对于此问题和其他分类数据的解决方案是 CategoricalArrays.jl
:
using CategoricalArrays
可以使用 CategoricalArrays.jl
包为分类变量数据添加层级顺序:
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
1 │ 1 28-01-2018 adolescent
2 │ 2 03-04-2019 adult
3 │ 3 01-08-2018 infant
4 │ 4 22-11-2020 adult
df = fix_age_column(wrong_types())
sort(df, :age)
因为已经定义了一组函数,因此可以通过调用函数来定义修正后的数据:
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
数据中的年龄是有序的 (ordered=true
),因此可以正确比较年龄类别:
df = correct_types()
a = df[1, :age]
b = df[2, :age]
a < b
true
如果元素类型为字符串,这将产生错误的比较:
false