Skip to content

Commit cfec963

Browse files
committed
refactor autots
1 parent 45c40d4 commit cfec963

File tree

8 files changed

+520
-0
lines changed

8 files changed

+520
-0
lines changed

AutoTS/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name = "AutoTS"
2+
uuid = "9f9003ca-5fd1-4e14-9a26-1226c8bf687b"
3+
version = "0.1.0"
4+
authors = ["Paulito Palmes, PhD <[email protected]>"]

AutoTS/src/AutoTS.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module AutoTS
2+
3+
greet() = print("Hello World!")
4+
5+
include("carettspredictor.jl")
6+
using .CaretTSPredictors
7+
export CaretTSPredictor, carettsdriver
8+
9+
include("automlflowtsprediction.jl")
10+
using .AutoMLFlowTSPredictions
11+
export AutoMLFlowTSPrediction
12+
export mlftsdriver
13+
14+
end # module AutoTS
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
module AutoMLFlowTSPredictions
2+
3+
using PDFmerger: append_pdf!
4+
using Plots
5+
using Statistics
6+
using Serialization
7+
import PythonCall
8+
const PYC = PythonCall
9+
using CSV
10+
11+
using DataFrames: DataFrame
12+
using Random
13+
using ..AbsTypes
14+
using ..Utils
15+
using ..CaretTSPredictors
16+
17+
import ..AbsTypes: fit, fit!, transform, transform!
18+
export fit, fit!, transform, transform!
19+
export mlftsdriver, AutoMLFlowTSPrediction
20+
21+
const MLF = PYC.pynew()
22+
const REQ = PYC.pynew()
23+
24+
function __init__()
25+
PYC.pycopy!(MLF, PYC.pyimport("mlflow"))
26+
PYC.pycopy!(REQ, PYC.pyimport("requests"))
27+
end
28+
29+
include("./mlflowutils.jl")
30+
31+
mutable struct AutoMLFlowTSPrediction <: Workflow
32+
name::String
33+
model::Dict{Symbol,Any}
34+
35+
function AutoMLFlowTSPrediction(args=Dict())
36+
default_args = Dict(
37+
:name => "AutoTSPredictions",
38+
:projectname => "AutoTSPredictions",
39+
:url => "http://localhost:8080",
40+
:description => "Automated Timeseries Prediction",
41+
:projecttype => "tsprediction",
42+
:artifact_name => "AutoTSPredictionModel.bin",
43+
:impl_args => Dict(
44+
:name => "autots",
45+
:learner=>"auto",
46+
:forecast_horizon=>10
47+
)
48+
)
49+
cargs = nested_dict_merge(default_args, args)
50+
initmlflowcargs!(cargs)
51+
cargs[:automodel] = CaretTSPredictor(cargs[:impl_args])
52+
new(cargs[:name], cargs)
53+
end
54+
end
55+
56+
function AutoMLFlowTSPrediction(name::String, args::Dict)
57+
AutoMLFlowTSPrediction(Dict(:name => name, args...))
58+
end
59+
60+
function AutoMLFlowTSPrediction(name::String; args...)
61+
AutoMLFlowTSPrediction(Dict(Dict(pairs(args))...))
62+
end
63+
64+
function (obj::AutoMLFlowTSPrediction)(; args...)
65+
model = obj.model
66+
cargs = nested_dict_merge(model, Dict(pairs(args)))
67+
obj.model = cargs
68+
return obj
69+
end
70+
71+
function fit!(mlfas::AutoMLFlowTSPrediction, X::DataFrame, Y::Vector=[])::Nothing
72+
# start experiment run
73+
setupautofit!(mlfas)
74+
# automate prediction
75+
autots = mlfas.model[:automodel]
76+
tsoutput = fit_transform!(autots, X, Y)
77+
# save model in memory
78+
mlfas.model[:automodel] = autots
79+
# log info to mlflow
80+
MLF.log_param("TSOutput", tsoutput)
81+
MLF.log_metric("ForecastHorizon", autots.model[:forecast_horizon])
82+
# log artifacts and end experiment run
83+
logmlartifact(mlfas)
84+
return nothing
85+
end
86+
87+
function fit(mlfas::AutoMLFlowTSPrediction, X::DataFrame, Y::Vector=[])::Nothing
88+
mlfcopy = deepcopy(mlfas)
89+
fit!(mlfcopy, X, Y)
90+
return mlfcopy
91+
end
92+
93+
function plottroutput(mlfas::AutoMLFlowTSPrediction, Y::Union{Vector,DataFrame})
94+
data = Y
95+
votepercent = mlfas.model[:automodel].model[:votepercent]
96+
tmpdir = tempdir()
97+
println(tmpdir)
98+
artifact_plot = joinpath(tmpdir, "plots.pdf")
99+
artifact_allplots = joinpath(tmpdir, "allplots.pdf")
100+
rm(artifact_allplots, force=true)
101+
if votepercent == 0.0
102+
for ndx in 0.1:0.1:1.0
103+
strndx = string(ndx)
104+
coldata = data[:, strndx]
105+
ndx = findall(x -> x == true, coldata)
106+
Plots.plot(data[:,1], label="tsdata", title="TS Prediction")
107+
xlabel!("X")
108+
ylabel!("Y")
109+
plp = scatter!(ndx, data[:,1][ndx], label="prediction")
110+
savefig(plp, artifact_plot)
111+
append_pdf!(artifact_allplots, artifact_plot, cleanup=true)
112+
end
113+
else
114+
strndx = string(votepercent)
115+
coldata = data[:, strndx]
116+
ndx = findall(x -> x == true, coldata)
117+
Plots.plot(data[:,1], label="tsdata", title="TS Prediction")
118+
xlabel!("X")
119+
ylabel!("Y")
120+
scatter!(ndx, data[:,1][ndx], label="prediction")
121+
savefig(artifact_allplots)
122+
end
123+
MLF.log_artifact(artifact_allplots)
124+
end
125+
126+
function transform!(mlfas::AutoMLFlowTSPrediction, X::DataFrame)
127+
# start experiment run
128+
Y = autotransform!(mlfas, X)
129+
# create plots and save them as mlfow artifacts
130+
# plottroutput(mlfas, Y)
131+
# end run
132+
MLF.end_run()
133+
return Y
134+
end
135+
136+
function transform(mlfas::AutoMLFlowTSPrediction, X::DataFrame)
137+
mlfasc = deepcopy(mlfas)
138+
return transform!(mlfasc, X)
139+
end
140+
141+
function mlftsdriver()
142+
url = "http://mlflow.home"
143+
url = "http://mlflow.isiath.duckdns.org:8082"
144+
url = "http://localhost:8081"
145+
146+
X = CSV.read("./data/node_cpu_ratio_rate_5m_1d_1m.csv",DataFrame;header=false)
147+
148+
#X = vcat(5 * cos.(-10:10), sin.(-30:30), 3 * cos.(-10:10), 2 * tan.(-10:10), sin.(-30:30)) |> x -> DataFrame([x], :auto)
149+
150+
mlfas = AutoMLFlowTSPrediction(Dict(:url => url))
151+
pred=fit_transform!(mlfas, X)
152+
return pred
153+
end
154+
155+
end

AutoTS/src/carettspredictor.jl

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
module CaretTSPredictors
2+
3+
using Distributed
4+
import PythonCall
5+
const PYC = PythonCall
6+
7+
# standard included modules
8+
using DataFrames: DataFrame
9+
using Random
10+
using ..AbsTypes
11+
using ..Utils
12+
13+
import ..AbsTypes: fit, fit!, transform, transform!
14+
export fit, fit!, transform, transform!
15+
export CaretTSPredictor, carettspredictors
16+
export carettsdriver
17+
18+
function carettspredictors()
19+
println("Use available learners:")
20+
[print(learner, " ") for learner in keys(carettspredictor_dict)]
21+
println()
22+
end
23+
24+
const CTS = PYC.pynew()
25+
const PD = PYC.pynew()
26+
27+
function __init__()
28+
PYC.pycopy!(CTS, PYC.pyimport("pycaret.time_series"))
29+
PYC.pycopy!(PD, PYC.pyimport("pandas"))
30+
end
31+
32+
const carettspredictor_dict = Dict{String,PYC.Py}(
33+
"exp_smooth" => CTS, "ets" => CTS, "arima" => CTS,
34+
"auto_arima" => CTS, "theta" => CTS,
35+
"huber_cds_dt" => CTS, "knn_cds_dt" => CTS,
36+
"lr_cds_dt" => CTS, "ridge_cds_dt" => CTS, "br_cds_dt" => CTS,
37+
"en_cds_dt" => CTS, "lasso_cds_dt" => CTS, "et_cds_dt" => CTS,
38+
"rf_cds_dt" => CTS, "dt_cds_dt" => CTS, "lightgbm_cds_dt" => CTS,
39+
"ada_cds_dt" => CTS, "omp_cds_dt" => CTS, "gbr_cds_dt" => CTS,
40+
"llar_cds_dt" => CTS, "naive" => CTS,
41+
"polytrend" => CTS, "croston" => CTS, "grand_means" => CTS,
42+
"bats" => CTS, "tbats" => CTS
43+
#"snaive","stlf","prophet","catboost_cds_dt"
44+
45+
)
46+
47+
const carettsexp_dict = Dict{String,PYC.Py}()
48+
carettsexp_dict["TSForecastingExperiment"] = CTS
49+
50+
51+
mutable struct CaretTSPredictor <: Learner
52+
name::String
53+
model::Dict{Symbol,Any}
54+
function CaretTSPredictor(args=Dict())
55+
default_args = Dict(
56+
:name => "caretts",
57+
:verbose => false,
58+
:learner => "auto",
59+
:experiment => "TSForecastingExperiment",
60+
:output => "forecast",
61+
:forecast_horizon => 10,
62+
:impl_args => Dict{Symbol,Any}()
63+
)
64+
cargs = nested_dict_merge(default_args, args)
65+
cargs[:name] = cargs[:name] * "_" * randstring(3)
66+
skl = cargs[:learner]
67+
if skl != "auto" && !(skl in keys(carettspredictor_dict))
68+
println("$skl is not supported.")
69+
println()
70+
carettspredictors()
71+
error("Argument keyword error")
72+
end
73+
new(cargs[:name], cargs)
74+
end
75+
end
76+
77+
function CaretTSPredictor(learner::String, args::Dict)
78+
CaretTSPredictor(Dict(:learner => learner, :name => learner, args...))
79+
end
80+
81+
function CaretTSPredictor(learner::String; args...)
82+
CaretTSPredictor(Dict(:learner => learner, :name => learner, :impl_args => Dict(pairs(args))))
83+
end
84+
85+
function fit!(adl::CaretTSPredictor, xx::DataFrame, ::Vector=[])::Nothing
86+
xh = xx |> Array
87+
py_dataframe = getproperty(PD, "DataFrame")
88+
x = py_dataframe(xh)
89+
impl_args = copy(adl.model[:impl_args])
90+
expt = adl.model[:experiment]
91+
learner = adl.model[:learner]
92+
py_experiment = getproperty(carettsexp_dict[expt], expt)()
93+
_verbose = adl.model[:verbose]
94+
py_experiment.setup(x, session_id=123, verbose=_verbose)
95+
if learner != "auto"
96+
clearner = py_experiment.create_model(learner, verbose=_verbose)
97+
@info "evaluating the model: $clearner"
98+
finalmodel = py_experiment.finalize_model(clearner)
99+
adl.model[:finalmodel] = finalmodel
100+
else
101+
best = py_experiment.compare_models(verbose=_verbose)
102+
@info "evaluating the best model: $best"
103+
finalmodel = py_experiment.finalize_model(best)
104+
adl.model[:finalmodel] = finalmodel
105+
end
106+
107+
# save experiment
108+
#adl.model[:py_experiment] = py_experiment
109+
return nothing
110+
end
111+
112+
function transform!(adl::CaretTSPredictor, xx::DataFrame)
113+
xh = deepcopy(xx) |> Array
114+
py_dataframe = getproperty(PD, "DataFrame")
115+
x = py_dataframe(xh)
116+
learner = adl.model[:learner]
117+
expt = adl.model[:experiment]
118+
py_experiment = getproperty(carettsexp_dict[expt], expt)()
119+
_verbose = adl.model[:verbose]
120+
py_experiment.setup(x, session_id=123, verbose=_verbose)
121+
forecast_horizon = adl.model[:forecast_horizon]
122+
finalmodel = adl.model[:finalmodel]
123+
res = py_experiment.predict_model(finalmodel, fh=forecast_horizon, verbose=_verbose)
124+
finalres = res.y_pred |> PYC.PyArray |> Vector
125+
return finalres
126+
end
127+
128+
function carettsdriver()
129+
DT = PYC.pyimport("pycaret.datasets")
130+
PD = PYC.pyimport("pandas")
131+
get_data = getproperty(DT, "get_data")
132+
dftmp = get_data("airline") |> collect
133+
dt=PYC.pyconvert.(Float64,dftmp)
134+
df = DataFrame(x1=dt)
135+
#df = rand(100, 1) |> x -> DataFrame(x, :auto)
136+
#bmodel = CaretTSPredictor("auto_arima", Dict(:verbose => true,:forecast_horizon=>30))
137+
bmodel = CaretTSPredictor("auto", Dict(:verbose => true,:forecast_horizon=>30))
138+
bestres = fit_transform!(bmodel, df)
139+
#tabres = @sync @distributed (hcat) for learner in ["ridge_cds_dt", "auto_arima", "ets", "rf_cds_dt"]
140+
# model = CaretTSPredictor(learner, Dict(:verbose => false))
141+
# res = fit_transform!(model, df)
142+
# DataFrame(learner => res)
143+
#end
144+
#@show hcat(tabres, DataFrame(:best => bestres))
145+
#print(bmodel.model[:finalmodel])
146+
#return nothing
147+
#hcat(tabres, DataFrame(:best => bestres))
148+
ndx1=1:length(df.x1)
149+
ndx2=(length(ndx1)+1):length(ndx1)+length(bestres)
150+
(ndx1,df.x1,ndx2,bestres)
151+
end
152+
153+
end
154+

0 commit comments

Comments
 (0)