Pandas（Python）と DataFrames（Julia）を Featherフォーマット で連係してみた【 Python目線 】

# ■ 概　要
 - こちらの続編になります。

https://qiita.com/malo21st/items/3b0f96713cb433202725

 - 前編では、Pandas の DataFrame を引数渡しで処理する方法を説明しましたが、Julia側では辞書で処理していました。
 - Julia には **PythonのPandas にあたる DataFrames.jl** があり、どうせやるなら、**Pandas（Python）と DataFrames（Julia）の間で DataFrame連係** させてみようと思い、今回やってみました。
 - DataFrame連係には、Featherというデータフォーマットを使用しました。Featherは、DataFrameを忠実に シリアライズ および デシリアライズ するように設計され、ディスクへの読み書きも効率化されており、データ分析言語間でのデータ共有に向いたデータフォーマットです。
 
# ■ ライブラリのインストール
 ◇ Python側：[**PyJulia**](https://pypi.org/project/julia/) のインストール

```
pip install julia # Juliaとの連携
```

 ◇ Julia側：[**PyCall**](https://github.com/JuliaPy/PyCall.jl) と [**DataFrames.jl**](https://github.com/JuliaData/DataFrames.jl)，[**Feather**](https://github.com/wesm/feather) のインストール

```
using Pkg; Pkg.add("PyCall") # Pythonとの連携
using Pkg; Pkg.add("DataFrames") # Julia版のPandas
using Pkg; Pkg.add("Feather") # Feather・DataFrame間の変換
```

# ■ コード
## ◇ **call_julia.py** 【Python】

```python:call_julia.py
from julia import Julia # !pip install julia
Julia(compiled_modules = False) # PyJuliaの設定変更
from julia import Main as call_julia
import pandas as pd

# Juliaプログラムからインスタンス生成
call_julia.include("call_julia.jl")

# データ型変換用のデコレータ　DataFrame(pandas) <-> feather
def df2feather(func):
    def wrapper(in_df):
        in_df.to_feather("in.feather", version=1) # dataframe -> feather
        func("in.feather")                        # feather -> func
        out_df = pd.read_feather("out.feather")   # feather -> dataframe 
        return out_df
    return wrapper

# 引数がデータフレーム(featherファィル経由)
@df2feather
def calc_bmi(in_feather_file: str):
    return call_julia.calc_bmi(in_feather_file)
```

## ◇ **call_julia.jl** 【Julia】

```julia:call_julia.jl
using DataFrames # using Pkg; Pkg.add("DataFrames")
using Feather    # using Pkg; Pkg.add("Feather")

# 引数がデータフレーム(featherファィル経由)
function calc_bmi(in_feather_file::String)
    dfs = Feather.read(in_feather_file) # feather -> dataframe

    dfs.bmi = dfs.weight ./ dfs.height .^ 2
    
    dfs.msg = ["普通" for r in 1:size(dfs, 1)]
    for row in eachrow(dfs)
        if row.bmi >= 25
            row.msg = "肥満"
        elseif row.bmi < 18.5
            row.msg = "低体重"
        end
    end
    
    Feather.write("out.feather", dfs) # dataframe -> feather
end
```

# ■ 使い方（実行画面）
 - **実行ファイル（.ipynb, .py）**は、**call_julia.py**，**call_julia.jl** と**同じフォルダ**に置いて下さい。
 - **データ連携用のFeatherファイル（in.feather，out.feather）も同じフォルダ**に出力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234391/5b1b2508-b526-b787-d948-b48141e2aa39.png)

# ■ 注意点
 - **Featherフォーマットで保存するときは、DataFrame の Index が デフォルト（0, 1,…）以外だとエラー**になります。Index がデフォルトでない場合、.reset_index(drop=True) などで Index をリセットして下さい。
 - また、**Featherフォーマットは、重複したカラム名や文字列以外のカラム名をサポートしていません**ので、カラム名には注意して下さい。
 - Featherフォーマットのヴァージョンは、Ver.２が広く使われていますが、Julia側の Feather.jl がVer.２に対応していない為、Ver.１で連係しました。（2021.12.05現在）

# ■ Python と Julia が動く環境の構築方法
 - 私の場合は、**dockerhub から [jupyter/datascience-notebook](https://hub.docker.com/r/jupyter/datascience-notebook) という docker image をプルして構築しました**。参考までに docker run スクリプトはこんな感じです。

```
docker run -v D:\DS\temp\work:/home/jovyan/work -p 9998:8888 --name prj-env jupyter/datascience-notebook
```

 - なお、**D:\DS\temp\work と 9998 と prj-env の箇所は、任意に決めていただいて結構です**。   
この環境では、Python と Julia だけでなく Ｒ も JupyterNotebook上で動きます。