Explorer 欠損値補完
Mix.install([
{:explorer, "~> 0.9"},
{:kino, "~> 0.8"}
])
準備
alias Explorer.DataFrame
alias Explorer.Series
require Explorer.DataFrame
データ作成
df =
%{
x: [nil, 2.0, 3.0, nil, 5.0, 6.0, 7.0],
y: [0.9, 1.8, 3.3, 3.7, nil, nil, nil]
}
|> DataFrame.new()
df
|> Kino.DataTable.new()
x の nil 数
df
|> DataFrame.pull("x")
|> Series.nil_count()
y の nil 数
df
|> DataFrame.pull("y")
|> Series.nil_count()
補完処理
固定値による補完
filled_df =
df
# データの全列に対して補完
|> DataFrame.to_series()
|> Enum.reduce(df, fn {col, _}, df ->
# 対象列について、 nil の場合は 0.0 にする
DataFrame.mutate_with(df, &%{col => Series.fill_missing(&1[col], 0.0)})
end)
filled_df
|> Kino.DataTable.new()
集計値による補完
fill_df = fn target_df, value ->
target_df
|> DataFrame.to_series()
|> Enum.reduce(target_df, fn {col, _}, merged_df ->
DataFrame.mutate_with(merged_df, &%{col => Series.fill_missing(&1[col], value)})
end)
end
一つの前の値(先頭は補完されない)
df
|> fill_df.(:forward)
|> Kino.DataTable.new()
一つ後の値(末尾は補完されない)
df
|> fill_df.(:backward)
|> Kino.DataTable.new()
最大値による補完
df
|> fill_df.(:max)
|> Kino.DataTable.new()
最小値による補完
df
|> fill_df.(:min)
|> Kino.DataTable.new()
平均値による補完
df
|> fill_df.(:mean)
|> Kino.DataTable.new()
型毎に補完処理を変える
df =
%{
float: [0.9, 1.8, 3.3, 3.7, nil, nil, 7.2],
int: [1, 2, 3, nil, 5, 6, 7],
bool: [nil, true, false, nil, true, true, false],
str: ["a", nil, "c", "d", nil, "e", nil],
date: [~D[2022-01-01], ~D[2000-01-03], nil, nil, nil, nil, ~D[2000-02-01]],
datetime: [
nil,
~N[2022-01-01 00:01:00],
~N[2022-01-01 00:02:00],
nil,
nil,
~N[2022-02-01 00:02:00],
nil
]
}
|> DataFrame.new()
df
|> Kino.DataTable.new()
filled_df =
df
|> DataFrame.to_series()
|> Enum.reduce(df, fn {col, series}, df ->
DataFrame.mutate_with(df, fn lazy ->
fill_value =
case Series.dtype(series) do
:float ->
0.0
:integer ->
0
:string ->
""
:date ->
~D[2022-01-01]
:datetime ->
~N[2022-01-01 00:01:00]
:boolean ->
:min
end
%{col => Series.fill_missing(lazy[col], fill_value)}
end)
end)
filled_df
|> Kino.DataTable.new()