Google Cloud の cloud shell ターミナル上の julia から、Cloud Natural Language API で感情分析をやってみよう

前の投稿 で動かした Google Cloud の cloud shell ターミナル上の julia から、Cloud Natural Language API で感情分析をやってみようという話しです。 なお、julia の PyCall は `/usr/bin/python3`に継いであります。

前提として、Cloud Natural Language API が python3 から動かないといけません。 この為には、 Cloud Natural Language のドキュメントのクイックスタート: 「 環境変数 GOOGLE_APPLICATION_CREDENTIALS を、サービス アカウント キーが含まれる JSON ファイルのパスに設定します。 」という作業が必要です。 JSON として秘密鍵をダウンロードして、cloud shell のターミナルの右上の ... が縦に並ぶアイコンで、JSON 鍵をアップロードします。この鍵の場所を .bashrc に書き込みます。 例は、 `export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"` のような感じです。 user が伏せ字になっています。 また、デフォルトでは Download フォルダーなるものは有りません。.bashrc を読み込ませ直すのに、ターミナルの再起動などをして下さい。

さて、いよいよ julia さんから PyCall 経由で使ってみます。

下準備から



               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.5.1 (2020-08-25)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |
julia> using PyCall
julia> argparse = pyimport("argparse");
julia> language = pyimport("google.cloud.language");
julia> enums = language.enums;
julia> types = language.types;
julia> client = language.LanguageServiceClient();

次に、content に感情分析をさせたい文字列を入れて、形式情報を付加した document にして、感情分析器に投入です。




julia> content = "Google Cloud の cloud shell で julia が動くなんて、めちゃくちゃ嬉しい。"
"Google Cloud の cloud shell で julia が動くなんて、めちゃくちゃ嬉しい。"
julia> document = types.Document(
           content=content,
           language = "ja",
           type=enums.Document.Type.PLAIN_TEXT)
PyObject type: PLAIN_TEXT
content: "Google Cloud \343\201\256 cloud shell \343\201\247 julia \343\201\214\345\213\225\343\201\217\343\201\252\343\202\223\343\201\246\343\200\201\343\20
2\201\343\201\241\343\202\203\343\201\217\343\201\241\343\202\203\345\254\211\343\201\227\343\201\204\343\200\202"
language: "ja"
julia> result = client.analyze_sentiment(document=document)
PyObject document_sentiment {
  magnitude: 0.8999999761581421
  score: 0.8999999761581421
}
language: "ja"
sentences {
  text {


magnitude: 0.90, score: 0.90 と、とても強めにポジティブな判定になりました。

もちろん。result の中に、文章全体と、それぞれの文の分析結果も含まれています。 尤も1文構成ですから、結果は同じです。



julia> result.document_sentiment.magnitude
0.8999999761581421
julia> result.document_sentiment.score
0.8999999761581421

# つぎは文の方です。
julia> result.sentences[1].text.content
"Google Cloud の cloud shell で julia が動くなんて、めちゃくちゃ嬉しい。"
julia> result.sentences[1].sentiment.magnitude
0.8999999761581421
julia> result.sentences[1].sentiment.score
0.8999999761581421

では、10個作文をしてみましたので、これを分析して頂きましょう。下準備として、documentの形式にする関数と、分析して magunitude と score を取り出す関数を作っておきます。



julia> arrayText = [
           "Google Cloud の cloud shell で julia が動くなんて、めちゃくちゃ嬉しい。",
           "作文するなんて、そう簡単にできる作業な訳ではない。",
           "作文は、頭の柔らかい小学生でも難しい。",
           "今日は暑くて死にそうだった。",
           "日記帳みたいになってきたが、例文を一生懸命書いているだけなのである。",
           "いったいこのブログに、どの程度の価値があるのだろうか? 皆目検討も付かない。いや、意味など無く、単なる環境負荷でしか無いのではないだろうか?",
           "もう、そろそろ、良いかずの文章が出きてきた。",
           "昨日のテレビ番組は、面白すぎて、腹が痛くなった。",
           "これで、終わり。バンザイ。",
           "おじいさんが竹の中を覗き込むと、光かがやく赤ん坊がいた。この世のものとは思えぬ、誠に美しい女の子であった。"
       ];
julia> function makeDoc(content::String)
           document = types.Document(
           content=content,
           language = "ja",
           type=enums.Document.Type.PLAIN_TEXT)
           return document
       end
makeDoc (generic function with 1 method)
julia> function sentimentAnalysis(content::String)
           document = makeDoc(content)
           result = client.analyze_sentiment(document=document)
           return result.document_sentiment.magnitude,  result.document_sentiment.score
       end
sentimentAnalysis (generic function with 1 methods)

まずは、for ループで無難に読んで、array の1つずつ10個の magnitude と score を取り出しましょう。



julia> function arrayAnalysis(arrayText::Array{String,1})
           arraySentiments = zero(rand(size(arrayText,1),2))
           for i in 1:size(arrayText,1)
               arraySentiments[i,:] .= collect(sentimentAnalysis(arrayText[i]))
           end
           return arraySentiments
       end
arrayAnalysis (generic function with 1 method)

julia> @time foo = arrayAnalysis(arrayText)
  1.476476 seconds (1.07 k allocations: 51.562 KiB)
10×2 Array{Float64,2}:
 0.9   0.9
 0.2  -0.2
 0.3  -0.3
 0.1  -0.1
 0.1  -0.1
 0.9   0.0
 0.4  -0.4
 0.3  -0.3
 0.6   0.0
 1.0   0.3
 
 julia> foo[1,1]
0.8999999761581421

表示は四捨五入してありますが、ちゃんと Float64 になっているので心配は無用です。「腹が痛い。」 が negative に評価されていたりしますね。 最も negative なのは、"もう、そろそろ、良いかずの文章が出きてきた。" でした。

では、ブロードキャストしてみましょう。



julia> @time foo2 = sentimentAnalysis.(arrayText)
  1.595585 seconds (1.03 k allocations: 49.281 KiB)
10-element Array{Tuple{Float64,Float64},1}:
 (0.8999999761581421, 0.8999999761581421)
 (0.20000000298023224, -0.20000000298023224)
 (0.30000001192092896, -0.30000001192092896)
 (0.10000000149011612, -0.10000000149011612)
 (0.10000000149011612, -0.10000000149011612)
 (0.8999999761581421, 0.0)
 (0.4000000059604645, -0.4000000059604645)
 (0.30000001192092896, -0.30000001192092896)
 (0.6000000238418579, 0.0)
 (1.0, 0.30000001192092896)

帰りが tuple ですが、ブロードキャストしてくれるようです。律速が Cloud Natural Language API なのでしょうが、この環境では for ループの方が早いかもしれません。コア数やメモリーなど違うのでしょうか?

というわけで動いたので良しとして下さい。

B! LINE