JuliaとJupyter NotebookでScikitLearnがうまく使えない問題

## 経緯
[WEB+DB PRESS vol.111](https://gihyo.jp/magazine/wdpress/archive/2019/vol111)のJulia特集の内容をMac(MacOS Mojava 10.14.5)で試した際に発生したエラーの対応方法になります。

- Julia: 1.1.1

## 実行内容
Jupyter-notebookで以下のJuliaのコマンドを実行

```
]add RDatasets
using RDatasets
iris = dataset("datasets", "iris")
]add ScikitLearn
;pip3 install scikit-learn
using ScikitLearn.CrossValidation: train_test_split
X = Matrix(iris[:, 1:4])
y = string.(iris.Species)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3);
```
- RDatasets の iris データセットを利用
- ScikitLearn の train_test_split を実行してデータセットを分割する

## 発生したエラー

```
This ScikitLearn.jl functionality (sklearn.model_selection) requires installing the Python scikit-learn library. See instructions on https://github.com/cstjean/ScikitLearn.jl

Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] importpy(::String) at /Users/taketoiseki/.julia/packages/ScikitLearn/bo2Pt/src/Skcore.jl:28
 [3] #train_test_split#93(::Base.Iterators.Pairs{Symbol,Float64,Tuple{Symbol},NamedTuple{(:test_size,),Tuple{Float64}}}, ::Function, ::Array{Float64,2}, ::Vararg{Any,N} where N) at /Users/taketoiseki/.julia/packages/ScikitLearn/bo2Pt/src/cross_validation.jl:664
 [4] (::getfield(ScikitLearn.Skcore, Symbol("#kw##train_test_split")))(::NamedTuple{(:test_size,),Tuple{Float64}}, ::typeof(train_test_split), ::Array{Float64,2}, ::Vararg{Any,N} where N) at ./none:0
 [5] top-level scope at In[2]:4
```

- 「Python の scikit-learn をインストールしろ」とのこと
- `;pip3 install scikit-learn`でインストールできてるはずなのに…

## 原因と解決方法
### 原因
- Juliaは`Conda.jl`が内部的にインストールしたPythonを利用する。
- 私の環境では元々インストールしていたPython３がある。
- 結果、`pip3`は元々インストールしていたPython3の方にモジュールをインストールする。

### 解決方法
Julia の REPL にて以下を実行する

```
julia> ENV["PYTHON"]="/usr/local/bin/python3";
(v1.1) pkg> build PyCall
julia> using IJulia
julia > notebook()
```

- 環境変数で Julia で利用する Python のパスを指定する。
- 内部的に呼ばれる`PyCall`をビルドしなおす。
- Jupyter-notebook を再起動する。

## 原因判明までの流れ

### まずはエラー発生箇所のコードを読む
    
https://github.com/cstjean/ScikitLearn.jl/blob/master/src/Skcore.jl

```
function importpy(name::AbstractString)
    try
        return pyimport(name)
    catch e
        if isa(e, PyCall.PyError)
            error("This ScikitLearn.jl functionality ($name) requires installing the Python scikit-learn library. See instructions on https://github.com/cstjean/ScikitLearn.jl")
        else
            rethrow()
        end
    end
end
```

**どうやら`pyimport`した結果、エラーが起きているらしい。**

### REPLからpyimportを読んでみる

```
julia> using PyCall
julia> pyimport("scikit-learn")
```

上記コマンドを実行したところ、以下のエラーが出てきました。

```
ERROR: PyError (PyImport_ImportModule

The Python package scikit-learn could not be found by pyimport. Usually this means
that you did not install scikit-learn in the Python version being used by PyCall.

PyCall is currently configured to use the Julia-specific Python distribution
installed by the Conda.jl package.  To install the scikit-learn module, you can
use `pyimport_conda("scikit-learn", PKG)`, where PKG is the Anaconda
package the contains the module scikit-learn, or alternatively you can use the
Conda package directly (via `using Conda` followed by `Conda.add` etcetera).

Alternatively, if you want to use a different Python distribution on your
system, such as a system-wide Python (as opposed to the Julia-specific Python),
you can re-configure PyCall with that Python.   As explained in the PyCall
documentation, set ENV["PYTHON"] to the path/name of the python executable
you want to use, run Pkg.build("PyCall"), and re-launch Julia.

) <class 'ModuleNotFoundError'>
ModuleNotFoundError("No module named 'scikit-learn'")

Stacktrace:
 [1] pyimport(::String) at /Users/taketoiseki/.julia/packages/PyCall/ttONZ/src/PyCall.jl:544
 [2] top-level scope at none:0

```

すごく親切に原因が書かれてますね。

### Python3のパスを確認

```
% which python3
/usr/local/bin/python3
```

### Python3で scikit-learn がインストール済みであることの確認

```
-> % pip3 show scikit-learn
Name: scikit-learn
Version: 0.21.2
Summary: A set of python modules for machine learning and data mining
Home-page: http://scikit-learn.org
Author: None
Author-email: None
License: new BSD
Location: /usr/local/lib/python3.7/site-packages
Requires: scipy, joblib, numpy
Required-by:
```

### きちんとインストールされてそうなので、環境変数に渡して再度動かしてみる

```
using ScikitLearn.CrossValidation: train_test_split
X = Matrix(iris[:, 1:4])
y = string.(iris.Species)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3);
X_train
```

きちんとX_trainが定義できました。

```
105×4 Array{Float64,2}:
 6.1  2.6  5.6  1.4
 5.6  3.0  4.1  1.3
 6.0  3.0  4.8  1.8
 5.1  3.5  1.4  0.3
 7.7  2.6  6.9  2.3
 6.1  2.8  4.7  1.2
 6.3  2.7  4.9  1.8
 6.2  3.4  5.4  2.3
 4.8  3.4  1.9  0.2
 7.7  2.8  6.7  2.0
 4.8  3.0  1.4  0.3
 5.7  2.9  4.2  1.3
 6.2  2.9  4.3  1.3
 ⋮                 
 6.5  3.2  5.1  2.0
 6.9  3.1  5.4  2.1
 4.4  3.0  1.3  0.2
 4.4  2.9  1.4  0.2
 5.1  3.5  1.4  0.2
 5.7  2.5  5.0  2.0
 6.8  3.0  5.5  2.1
 6.9  3.2  5.7  2.3
 5.3  3.7  1.5  0.2
 6.4  3.2  5.3  2.3
 5.4  3.9  1.3  0.4
 6.1  3.0  4.9  1.8
```

## 感想
Pythonは環境づくりに罠が多いイメージがあるんじゃー