sudachiPy を、python から使うのと、PyCall 経由の julia で使うのはどちらが早いのか

sudachiPy を、python から使うのと、PyCall 経由の julia で使うのはどちらが早いのか比べてみます。

例文は、なぜか、あの古典で、その訳を青空文庫から落して来ます。青空文庫は shift_JIS のエンコードで、 CR/LF の改行記号です。ターミナルでダウンロードして、エンコードを UTF-8、改行記号を LF に nkf を使って変更します。なお、"さっきダウンロードしたフォルダー" というフォルダーの中にターミナルで `cd` 移動してから開始の前提です。

[ターミナル]
% wget https://www.aozora.gr.jp/cards/000052/files/5016_ruby_9746.zip
--2020-03-14 16:24:54--  https://www.aozora.gr.jp/cards/000052/files/5016_ruby_9746.zip
www.aozora.gr.jp (www.aozora.gr.jp) をDNSに問いあわせています... 59.106.13.115
www.aozora.gr.jp (www.aozora.gr.jp)|59.106.13.115|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 16790 (16K) [application/zip]
`5016_ruby_9746.zip.1' に保存中

5016_ruby_9746.zip.1         100%[=============================================>]  16.40K  --.-KB/s 時間 0s       

2020-03-14 16:24:54 (71.5 MB/s) - `5016_ruby_9746.zip.1' へ保存完了 [16790/16790]

[ターミナル]
% unzip 5016_ruby_9746.zip 
Archive:  5016_ruby_9746.zip
inflating: 01kiritsubo.txt   

[ターミナル]
% nkf --guess 01kiritsubo.txt                             
Shift_JIS (CRLF)
[ターミナル]
% nkf -Lu -w --overwrite 01kiritsubo.txt;                            
[ターミナル] ~/Downloads
% nkf --guess 01kiritsubo.txt            
UTF-8 (LF)

さて、まず、julia からです。

julia> using PyCall, Dates
julia> sudachipy = pyimport("sudachipy");
julia> dictionary = pyimport("sudachipy.dictionary");
julia> tokenizer = pyimport("sudachipy.tokenizer");
julia> tokenizer_obj = dictionary.Dictionary().create();
julia> mode = tokenizer.Tokenizer.SplitMode.C;


julia> function main(text::String)
        start = now()
        textToken = tokenizer_obj.tokenize(text, mode)
        println(now() - start)
        return textToken
    end

julia> text = "いずれの御時にか、女御・更衣、あまたさぶらい給いける中に、いとやむことなき際にはあらぬが、すぐれて時めき給ふありけり。"

julia> hoge = main(text);
23 milliseconds

julia> hoge1 = map(x -> x.surface(), hoge);

julia> print(hoge1)
["いずれ", "の", "御", "時", "に", "か", "、", "女御", "・", "更衣", "、", "あまた", "さぶ", "らい", "給", "いける", "中", "に", "、", "いと", "やむ", "こと", "なき", "際", "に", "は", "あら", "ぬ", "が", "、", "すぐれ", "て", "時めき", "給ふ", "あり", "けり", "。"]

自分よりも文節を分けるのが上手かもしれません。sudachiPy を第1章に丸ごと使ってみます。時間は Python に @time に相当する機能に揃えるため、now() をわざわざ使っています。

julia> text1  = read("さっきダウンロードしたフォルダー/01kiritsubo.txt", String);

julia> text1[1:30]
"源氏物語\n桐壺\n紫式部\n"

julia> function main(text::String)
        start = now()
        textToken = tokenizer_obj.tokenize(text, mode)
        println(now() - start)
        return textToken
    end

julia> hoge = main(text1);
4668 milliseconds

ここは、"\n" で区切って split() で Array にするとわずかに遅くなる傾向があるようです。ただ、先に区切る方が、あとの処理はやりやすい場面もあるかもしれません。

では、Python3 で同じような事をしてみます。

>>> f = open('さっきダウンロードしたフォルダー/01kiritsubo.txt')
>>> text1 = f.readlines() # 1行毎にファイル終端まで全て読む(改行文字も含まれる)
>>> f.close()
>>> text1
['源氏物語\n', '桐壺\n', '紫式部\n', ...]

>>> def main2(text):
...     textToken = tokenizer_obj.tokenize(text, mode)
...     return textToken
>>>
>>> def mainMap(text1):
...     start = time.time()
...     textToken = list(map(main2 , text1))
...     elapsed_time = time.time() - start
...     print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")
...     return textToken
...
>>> mainMap(text1)
elapsed_time:4.5818140506744385[sec]

今回の読み込み方では、python では既に区切られたリストになっていました。加えて、ネイティブの強みなのか、PyCall 経由の julia よりわずか早い傾向があるようでした。

以上です。ご精読ありがとうございました。

B! LINE