Skip to content

Commit 20d00bd

Browse files
authored
Merge pull request #108 from IBM/pythoncall_transition
Pythoncall transition
2 parents 9ff9510 + 297f19c commit 20d00bd

File tree

11 files changed

+133
-150
lines changed

11 files changed

+133
-150
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
*.swp
2+
.CondaPkg
23
.DS_Store
34
.ipynb_checkpoints
45
*.serialized

CondaPkg.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
channels = ["mkl", "scikit-learn"]
2+
3+
[deps]
4+
scikit-learn = ""
5+
python = ""

Project.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
name = "AutoMLPipeline"
22
uuid = "08437348-eef5-4817-bc1b-d4e9459680d6"
33
authors = ["Paulito Palmes <[email protected]>"]
4-
version = "0.3.6"
4+
version = "0.4.0"
55

66
[deps]
77
AMLPipelineBase = "e3c3008a-8869-4d53-9f34-c96f99c8a2b6"
8-
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
8+
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
99
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
10-
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
10+
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
1111
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1212
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1313

1414
[compat]
1515
AMLPipelineBase = "0.1"
16-
Conda = "1.0, 1.1, 1.2, 1.3, 1.4, 1.5"
16+
CondaPkg = "0.2"
1717
DataFrames = "0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 1.0, 1.1"
18-
PyCall = "1.90, 1.91, 1.92"
18+
PythonCall = "0.9"
1919
julia = "1"
2020

2121
[extras]
2222
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
23-
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
23+
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
2424
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2525
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
2626
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2727

2828
[targets]
29-
test = ["Dates", "Test", "Random", "PyCall", "Statistics"]
29+
test = ["Dates", "Test", "Random", "PythonCall", "Statistics"]

deps/build.jl

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/skcrossvalidator.jl

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SKCrossValidators
22

3-
using PyCall
3+
import PythonCall
4+
const PYC=PythonCall
45

56
# standard included modules
67
using DataFrames
@@ -11,11 +12,11 @@ using ..Utils
1112
import ..CrossValidators: crossvalidate
1213
export crossvalidate
1314

14-
const metric_dict = Dict{String,PyObject}()
15-
const SKM = PyNULL()
15+
const metric_dict = Dict{String,PYC.Py}()
16+
const SKM = PYC.pynew()
1617

1718
function __init__()
18-
copy!(SKM, pyimport_conda("sklearn.metrics","scikit-learn"))
19+
PYC.pycopy!(SKM, PYC.pyimport("sklearn.metrics"))
1920

2021
metric_dict["roc_auc_score"] = SKM.roc_auc_score
2122
metric_dict["accuracy_score"] = SKM.accuracy_score
@@ -67,53 +68,57 @@ end
6768
6869
Runs K-fold cross-validation using balanced accuracy as the default. It support the
6970
following metrics for classification:
70-
- accuracy_score
71-
- balanced_accuracy_score
72-
- cohen_kappa_score
73-
- jaccard_score
74-
- matthews_corrcoef
75-
- hamming_loss
76-
- zero_one_loss
77-
- f1_score
78-
- precision_score
79-
- recall_score
71+
- "accuracy_score"
72+
- "balanced_accuracy_score"
73+
- "cohen_kappa_score"
74+
- "jaccard_score"
75+
- "matthews_corrcoef"
76+
- "hamming_loss"
77+
- "zero_one_loss"
78+
- "f1_score"
79+
- "precision_score"
80+
- "recall_score"
8081
8182
and the following metrics for regression:
82-
- mean_squared_error
83-
- mean_squared_log_error
84-
- median_absolute_error
85-
- r2_score
86-
- max_error
87-
- explained_variance_score
83+
- "mean_squared_error"
84+
- "mean_squared_log_error"
85+
- "median_absolute_error"
86+
- "r2_score"
87+
- "max_error"
88+
- "explained_variance_score"
8889
"""
8990
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,
9091
sfunc::String; nfolds=10,verbose::Bool=true)
92+
93+
YC=Y
94+
if !(eltype(YC) <: Real)
95+
YC = Y |> Vector{String}
96+
end
97+
9198
checkfun(sfunc)
9299
pfunc = metric_dict[sfunc]
93-
metric(a,b) = pfunc(a,b)
94-
crossvalidate(pl,X,Y,metric,nfolds,verbose)
100+
metric(a,b) = pfunc(a,b) |> (x -> PYC.pyconvert(Float64,x))
101+
crossvalidate(pl,X,YC,metric,nfolds,verbose)
95102
end
96103

97-
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,sfunc::String,folds::Int)
98-
crossvalidate(pl,X,Y,sfunc,nfolds=folds)
104+
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,sfunc::String,nfolds::Int)
105+
crossvalidate(pl,X,Y,sfunc; nfolds)
99106
end
100107

101-
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,sfunc::String,verby::Bool)
102-
crossvalidate(pl,X,Y,sfunc,verbose=verby)
108+
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,sfunc::String,verbose::Bool)
109+
crossvalidate(pl,X,Y,sfunc; verbose)
103110
end
104111

105112
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,
106-
sfunc::String, folds::Int,verby::Bool)
107-
crossvalidate(pl,X,Y,sfunc,nfolds=folds,verbose=verby)
113+
sfunc::String, nfolds::Int,verbose::Bool)
114+
crossvalidate(pl,X,Y,sfunc; nfolds,verbose)
108115
end
109116

110-
111-
112117
function crossvalidate(pl::Machine,X::DataFrame,Y::Vector,
113-
sfunc::String,averagetype::String,nfolds=10,verbose::Bool=true)
118+
sfunc::String,averagetype::String;nfolds=10,verbose::Bool=true)
114119
checkfun(sfunc)
115120
pfunc = metric_dict[sfunc]
116-
metric(a,b) = pfunc(a,b,average=averagetype)
121+
metric(a,b) = pfunc(a,b,average=averagetype) |> (x -> PYC.pyconvert(Float64,x))
117122
crossvalidate(pl,X,Y,metric,nfolds,verbose)
118123
end
119124

src/sklearners.jl

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SKLearners
22

3-
using PyCall
3+
import PythonCall
4+
const PYC=PythonCall
45

56
# standard included modules
67
using DataFrames
@@ -12,31 +13,31 @@ import ..AbsTypes: fit, fit!, transform, transform!
1213
export fit, fit!, transform, transform!
1314
export SKLearner, sklearners
1415

15-
const learner_dict = Dict{String,PyObject}()
16-
const ENS = PyNULL()
17-
const LM = PyNULL()
18-
const DA = PyNULL()
19-
const NN = PyNULL()
20-
const SVM = PyNULL()
21-
const TREE = PyNULL()
22-
const ANN = PyNULL()
23-
const GP = PyNULL()
24-
const KR = PyNULL()
25-
const NB = PyNULL()
26-
const ISO = PyNULL()
16+
const learner_dict = Dict{String,PYC.Py}()
17+
const ENS = PYC.pynew()
18+
const LM = PYC.pynew()
19+
const DA = PYC.pynew()
20+
const NN = PYC.pynew()
21+
const SVM = PYC.pynew()
22+
const TREE = PYC.pynew()
23+
const ANN = PYC.pynew()
24+
const GP = PYC.pynew()
25+
const KR = PYC.pynew()
26+
const NB = PYC.pynew()
27+
const ISO = PYC.pynew()
2728

2829
function __init__()
29-
copy!(ENS , pyimport_conda("sklearn.ensemble","scikit-learn"))
30-
copy!(LM , pyimport_conda("sklearn.linear_model","scikit-learn"))
31-
copy!(DA , pyimport_conda("sklearn.discriminant_analysis","scikit-learn"))
32-
copy!(NN , pyimport_conda("sklearn.neighbors","scikit-learn"))
33-
copy!(SVM , pyimport_conda("sklearn.svm","scikit-learn"))
34-
copy!(TREE, pyimport_conda("sklearn.tree","scikit-learn"))
35-
copy!(ANN , pyimport_conda("sklearn.neural_network","scikit-learn"))
36-
copy!(GP , pyimport_conda("sklearn.gaussian_process","scikit-learn"))
37-
copy!(KR , pyimport_conda("sklearn.kernel_ridge","scikit-learn"))
38-
copy!(NB , pyimport_conda("sklearn.naive_bayes","scikit-learn"))
39-
copy!(ISO , pyimport_conda("sklearn.isotonic","scikit-learn"))
30+
PYC.pycopy!(ENS , PYC.pyimport("sklearn.ensemble"))
31+
PYC.pycopy!(LM , PYC.pyimport("sklearn.linear_model"))
32+
PYC.pycopy!(DA , PYC.pyimport("sklearn.discriminant_analysis"))
33+
PYC.pycopy!(NN , PYC.pyimport("sklearn.neighbors"))
34+
PYC.pycopy!(SVM , PYC.pyimport("sklearn.svm"))
35+
PYC.pycopy!(TREE, PYC.pyimport("sklearn.tree"))
36+
PYC.pycopy!(ANN , PYC.pyimport("sklearn.neural_network"))
37+
PYC.pycopy!(GP , PYC.pyimport("sklearn.gaussian_process"))
38+
PYC.pycopy!(KR , PYC.pyimport("sklearn.kernel_ridge"))
39+
PYC.pycopy!(NB , PYC.pyimport("sklearn.naive_bayes"))
40+
PYC.pycopy!(ISO , PYC.pyimport("sklearn.isotonic"))
4041

4142
# Available scikit-learn learners.
4243
learner_dict["AdaBoostClassifier"] = ENS
@@ -157,8 +158,16 @@ function sklearners()
157158
println("Note: Consult Scikitlearn's online help for more details about the learner's arguments.")
158159
end
159160

160-
function fit!(skl::SKLearner, xx::DataFrame, y::Vector)::Nothing
161+
function fit!(skl::SKLearner, xx::DataFrame, yy::Vector)::Nothing
162+
# normalize inputs
161163
x = xx |> Array
164+
y = yy
165+
skl.model[:predtype] = :numeric
166+
if !(eltype(yy) <: Real)
167+
y = yy |> Vector{String}
168+
skl.model[:predtype] = :alpha
169+
end
170+
162171
impl_args = copy(skl.model[:impl_args])
163172
learner = skl.model[:learner]
164173
py_learner = getproperty(learner_dict[learner],learner)
@@ -185,9 +194,15 @@ end
185194

186195
function transform!(skl::SKLearner, xx::DataFrame)::Vector
187196
x = deepcopy(xx) |> Array
188-
#return collect(skl.model[:predict](x))
189197
sklearner = skl.model[:sklearner]
190-
return collect(sklearner.predict(x))
198+
res = sklearner.predict(x)
199+
if skl.model[:predtype] == :numeric
200+
predn = PYC.pyconvert(Vector{Float64},res)
201+
return predn
202+
else
203+
predc = PYC.pyconvert(Vector{String},res)
204+
return predc
205+
end
191206
end
192207

193208
transform(skl::SKLearner, xx::DataFrame)::Vector = transform!(skl,xx)

src/skpreprocessor.jl

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SKPreprocessors
22

3-
using PyCall
3+
import PythonCall
4+
const PYC=PythonCall
45

56
# standard included modules
67
using DataFrames
@@ -12,18 +13,18 @@ import ..AbsTypes: fit, fit!, transform, transform!
1213
export fit, fit!, transform, transform!
1314
export SKPreprocessor, skpreprocessors
1415

15-
const preprocessor_dict = Dict{String,PyObject}()
16-
const DEC = PyNULL()
17-
const FS = PyNULL()
18-
const IMP = PyNULL()
19-
const PREP = PyNULL()
16+
const preprocessor_dict = Dict{String,PYC.Py}()
17+
const DEC = PYC.pynew()
18+
const FS = PYC.pynew()
19+
const IMP = PYC.pynew()
20+
const PREP = PYC.pynew()
2021

2122

2223
function __init__()
23-
copy!(DEC , pyimport_conda("sklearn.decomposition","scikit-learn"))
24-
copy!(FS , pyimport_conda("sklearn.feature_selection","scikit-learn"))
25-
copy!(IMP , pyimport_conda("sklearn.impute","scikit-learn"))
26-
copy!(PREP, pyimport_conda("sklearn.preprocessing","scikit-learn"))
24+
PYC.pycopy!(DEC , PYC.pyimport("sklearn.decomposition"))
25+
PYC.pycopy!(FS , PYC.pyimport("sklearn.feature_selection",))
26+
PYC.pycopy!(IMP , PYC.pyimport("sklearn.impute"))
27+
PYC.pycopy!(PREP, PYC.pyimport("sklearn.preprocessing"))
2728

2829
# Available scikit-learn learners.
2930
preprocessor_dict["DictionaryLearning"] = DEC
@@ -155,8 +156,13 @@ function skpreprocessors()
155156
println("Note: Please consult Scikitlearn's online help for more details about the preprocessor's arguments.")
156157
end
157158

158-
function fit!(skp::SKPreprocessor, x::DataFrame, y::Vector=[])::Nothing
159+
function fit!(skp::SKPreprocessor, x::DataFrame, yc::Vector=[])::Nothing
159160
features = x |> Array
161+
y = yc
162+
if !(eltype(yc) <: Real)
163+
y = yc |> Vector{String}
164+
end
165+
160166
impl_args = copy(skp.model[:impl_args])
161167
autocomp = skp.model[:autocomponent]
162168
if autocomp == true
@@ -186,7 +192,8 @@ end
186192
function transform!(skp::SKPreprocessor, x::DataFrame)::DataFrame
187193
features = deepcopy(x) |> Array
188194
model=skp.model[:skpreprocessor]
189-
return collect(model.transform(features)) |> x->DataFrame(x,:auto)
195+
res = (model.transform(features))
196+
PYC.pyconvert(Matrix,res) |> x->DataFrame(x,:auto)
190197
end
191198

192199
transform(skp::SKPreprocessor, x::DataFrame)::DataFrame = transform!(skp,x)

test/runtests.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
module TestAutoMLPipeline
22
using Test
33

4-
# suppress warnings
5-
@info "suppressing PyCall warnings"
6-
using PyCall
7-
warnings = pyimport("warnings")
4+
# @info "suppressing Python warnings"
5+
import PythonCall
6+
const PYC=PythonCall
7+
warnings = PYC.pyimport("warnings")
88
warnings.filterwarnings("ignore")
99

1010
include("test_skpreprocessing.jl")

0 commit comments

Comments
 (0)