おはようございます。次男は、このところ、就寝時もオムツを卒業してパンツで寝ていますが、たまぁに失敗しちゃいます@kjunichiです。
まえがき
ちょっと前にCSV.jlでゼータ関数のクリティカルライン上のプロットを 良い感じに出来たのに気をよくして
Juliaでファイルを読み込んで処理するというテーマのもと、今回は 長年自分でやってみたかったこれまでの自分のツイートからのワードクラウドの生成を Juliaでチャレンジしたが、いろいろ罠にはまった。
CSV.jlだと完全には読み込めなかった
集計作業まで行けたのだが、集計結果をながめると 古いツイートがどうも反映されていないと、気になり、よくよく中身を確認すると 途中で読み込みが途切れていた。
そこで、素のJuliaでテキストファイルとみなして読み込むことで対処した。
前処理として、ツイッターから取得した全ツイートのcsvファイルからtext列のみを 抽出したテキストをGoogleスプレッドシートで作成。 (しょっぱなからJulia以外の処理系を使っているという。。)
f = open("Dropbox/Untitled\ spreadsheet\ -\ Sheet1.csv") text = readlines(f);
Juliaでワードカウント
準備
日本語なので、分かち書きが必要になるが、定番のMeCabがJuliaにも用意されており、 これを使った。
MeCab本体のインストールが必要だが、何度かこの手の日本語テキスト処理にチャレンジしようと していたので、すでにインストールしていた。
Windows環境では数年前は64ビット版を用意すうには手動でパッチを当てる必要があったが、 最近はpipで一発で入るパッチ済みのパッケージが用意されているのを見かけたりするので、 ちょっと調べれば、昔のように手動でパッチせずとも64ビット版のMeCabを用意できるはず。
Juliaでの処理
先ほどのMeCab.jlで分かち書きを行い、結果を配列に詰め直している。 (この辺り、もっとJuliaらしい書き方や処理方法がありそうな気が。。)
using MeCab mecab=Mecab() words=[] for i in text res = parse_surface(mecab,string(i)) for j in res push!(words, j) end end
Dict型を使ってワードカウント。
counts = Dict{String, Int}() for word in words counts[word] = get(counts, word, 0) + 1 end
カウント結果をソートして、1語の単語を除外。
res = sort(collect(counts), by = tuple -> last(tuple), rev=true) res2=[] for i in res if(length(i[1])>1 && i[2]>10) #println(i[1],i[2]) item = Dict("word" =>i[1],"count"=>i[2]) push!(res2,item) end end
Vega.jlでワードクラウドと思いきや
Vega.jlでワードクラウドがサポートされており、JuliaはString型がUTF-8の文字列なので、 2バイトの文字化けと言った20世紀的な問題には悩むわけないと。
が、結果は、真っ白。
エラー解析
仕方ないので、Vega.jlのGithubページよりコードを読んで、 内部でJupyterに出力している箇所を見つけて、そこから、jsを切り出して、ウェブページとして ブラウザで動かして、2バイト文字があるとVegaのレベルでJavaScriptエラーでNG
Juliaから直接D3.jsでwordcloud
頑張ってVega.jlのwordcloudを日本語対応する作戦もなくもないが、 内部でD3.jsを使っていることが分かり、かつD3.jsのワードクラウドライブラリを直接使うなら、 日本語表示に問題なさそうだったので、JuliaというかJupyterから直接D3.jsでワードクラウドを描画する 事にした。
using JSON function wordcloud(res) divid = "d3" * randstring(3) spec = JSON.json(res) display("text/html", """ <body> <svg id=\ "$divid\" width="800" heigth="800"></svg> <script type="text/javascript"> require.config({ paths: { d3: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min", cloud: "https://cdnjs.cloudflare.com/ajax/libs/d3-cloud/1.2.5/d3.layout.cloud.min", } }); require(["d3", "cloud"], (d3, cloud) => { window.d3 = d3; window.d3.layout.cloud = cloud; const data = $spec const countMax = d3.max(data, (d) => { return d.count }) const sizeScale = d3.scale.linear().domain([0, countMax]).range([10, 100]) colorScale = d3.scale.category20c() const words = data.map((d) => { return { text: d.word, size: sizeScale(d.count) //頻出カウントを文字サイズに反映 }; }); d3.layout.cloud().size([800, 800]) .words(words) .rotate( ()=>{return ((1.2 - Math.random())|0)*90}) .fontSize(function(d) { return d.size; }) .on("end", draw) .start(); function draw(words) { d3.selectAll('text').remove(); d3.select("#$divid") .attr({"width": 800, "height": 800}) .append("g") // without the transform, words words would get cutoff to the left and top, they would // appear outside of the SVG area .attr("transform", "translate(400,400)") .selectAll("text") .data(words) .enter().append("text") .style("font-size", function(d) { return d.size + "px" }) .style("fill", function(d, i) { return colorScale(i); }) .attr({ "text-anchor": "middle", "transform": function(d) { return "translate( " +[d.x, d.y] + ")rotate( "+ d.rotate + ")" } }) .text(function(d) { return d.text; }); } }) </script> </body> """) end
結果
URLが分解されてしまい、httpや://が上位に表示さてしまったり、改善点はあるが、 まえからやりたかった自前のワードクラウド生成が出来たのでひとまずは満足。
学べたこと
- Juliaでテキストファイルとして一気に読み込む方法
- UTF8Stringは0.4までで、0.5以降はString型に統一された
- ストップワード設定しないと結果が微妙
- Jupyterではどうやらrequire.jsが使われているっぽい
- JuliaでJupyterにJavaScriptを送りつける方法
参考資料
- https://chezou.hatenablog.com/entry/20140915/1410750592chezou.hatenablog.com
- shimz.me
- github.com
- muddydixon.hatenablog.com
関連記事
- JulialangにHTTP2サーバーをさせたら
- IJuliaをHerokuの無料枠で動かした
- mruby-juliaでPythonもmrubyから呼び出せるようになった
- aobenchをjuliaでやってみた
- 1/7がつくる楕円をJulia言語でプロットする
- Julia言語で任意の点を散布図を描画するには
- Windows(MSVC)でmrubyからGPU対応のTensorflowを動かせた
- Juliaでaobenchを使って並列処理を試した その1
- JuliaでYoutuberを目指す
- MacBook ProでPaSoRi(RC-S320)を繋いでJuliaでPASMOの残高を表示した
- Julia言語でTwitterのAPIを叩いてみた