JuliaでPythonのコードを使いたい

# はじめに
JuliaでPythonのコードをそのまま使えると聞いて。
もしかして、Pythonの処理を高速で行えたりする！？と思い、とりあえず動かしてみようとしたらエラーが出てしまったので、その解決方法と一緒にまとめる。

# PyCall.jl
JuliaでPythonのコードを使用するにはPyCall.jlというパッケージを用いる。
```julia
usign Pkg ; Pkg.add("PyCall")
```
インポートしたところで早速ドキュメントに書いてあるコードを走らせてみた。

https://www.juliapackages.com/p/pycall

```julia
math = pyimport("math")
math.sin(math.pi / 4)   # 0.70710678...
```
おー、うまくいった。
じゃあ次動かしてみるか。
```julia
plt = pyimport("matplotlib.pyplot")
x = range(0;stop=2*pi,length=1000); y = sin.(3*x + 4*cos.(2*x));
plt.plot(x, y, color="red", linewidth=2.0, linestyle="--")
plt.show()

PyError (PyImport_ImportModule

The Python package matplotlib.pyplot could not be imported by pyimport. Usually this means
that you did not install matplotlib.pyplot 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 matplotlib.pyplot module, you can
use `pyimport_conda("matplotlib.pyplot", PKG)`, where PKG is the Anaconda
package that contains the module matplotlib.pyplot, 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 'matplotlib'")
```
(;'∀')！？！？
エラーがでました。
`pyimport`にそんなパッケージねえよ。と。
`pyimport_conda("matplotlib.pyplot", PKG)`を実行しろ？みたいなこと言われてますが、なんかJuliaが自動でanacondaパッケージの保存場所を作ってくれるみたい？で、そこに追加？する的な？

同僚からの電話を無視しつつ、エラー解消に明け暮れていたところ、`Conda.jl`パッケージにライブラリを追加すればええんか？と考え、実際に以下のコードを実行してみた。
```julia
Pkg.add("Conda")
using Conda
Conda.add("matplotlib")
```
その後、先ほどのコードを実行してみると、

![matplotlib.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/848b23ad-9b81-3722-d137-6bec86b81293.png)

うまくいった！

また、ドキュメントによるとPythonのコードを`py""" """`で挟むことで、そのまま使用することも可能みたい。んで、`py"関数名"(引数)`で呼び出すみたい。
```julia
py"""
import numpy as np

def sinpi(x):
    return np.sin(np.pi * x)
"""
py"sinpi"(1)   # 1.2246467991473532e-16
```
まじでそのまま！感動した。
また、他にもいろいろ調べてみると、`@pyimport`のマクロを使用することでも、コードそのまま使用できるみたいだから、いろいろ試してみた。
```julia
py"""
import pandas as pd 

def readCSV(file_path):
  return pd.read_csv(file_path, encoding='cp932')
"""

file_path = "your_file.csv"
df = py"readCSV"(file_path)
```
これはcsvファイルを読み込んで、`cp932`でエンコーディングして出力してる。
前回の記事でエンコーディングの方法を紹介したが、Pythonでやった方が簡単だね。
ただ、`py""" """`の外にあるコードは少しPythonとは違うような気もしなくない。
ということで`@pyimport`使ってみた。

```julia
@pyimport pandas as pd
df = pd.read_csv("your_file.csv", encoding="cp932")
df.head()
```
**いや、Pythonやんけ。**
頭に`@py`つけただけやん。
俺はJuliaではなくPythonをやっていた...？と錯覚するほどPython
他の複雑なコードも同じように書けるかはまだ試してないが、出来るならすごい。

# PythonCall.jl
この記事を書こうとドキュメント用意してたら、`PythonCall.jl`というパッケージを見つけた。

https://juliapackages.com/p/pythoncall

`PyCall.jl`と何が違うのか。

- PythonCallはJuliaとPython間のより広い範囲の変換をサポートし、変換メカニズムは拡張可能です。
- PythonCallはデフォルトで、変換時にミュータブルオブジェクトをコピーせず、代わりにミュータブルオブジェクトを直接ラップします。これは、変換されたオブジェクトを変更すると元のオブジェクトが変更され、変換が速くなることを意味します。
- PythonCall は通常、結果を自動的に Julia 値に変換せず、 Python オブジェクトとして残します。これにより、これらのオブジェクトでPythonicなこと（例えばメソッドへのアクセス）をするのが簡単になり、型が安定します。
- PythonCallは依存関係をJuliaプロジェクトごとに個別のConda環境にインストールします。これは、各Juliaプロジェクトが独立したPython依存関係を持つことができることを意味します。
- PythonCallはJulia 1.6.1+とPython 3.7+をサポートしており、PyCallはJulia 0.7+とPython 2.7+をサポートしています。
※ Deeple翻訳

なんか`PythonCall.jl`の方がよさそうな…
出力もPythonオブジェクトとして残るから、マジでPython書いてる感覚になりそうか？

Python側でJuliaのコードを呼び出すこともできるみたい。
ほんとすげーなこの言語。
ドキュメントでは`seaborn`でアヤメのデータセットを可視化してるみたい。

# まとめ
今回は、JuliaでPythonのコードを呼び出す方法について紹介した。
もっとこの辺りのパッケージは使いこなせるようにしたいな。
Pythonのコードをすべてそのまま書くことができるなら、すごく助かるし、転職先から「なんの言語使ってんの～？」って聞かれたときに、「Juliaです(｀･ω･´)ｷﾘｯ」ってできるよ。実質書いてるのPythonなのに。
もっと理解深めて、有用な情報や躓いたことは随時まとめていこう。
それでは！！！