RユーザーのためのJulia100問100答
R Adevnt Calendar 8日目の記事です。大幅に遅れて大変申し訳ないです。
この記事ではR言語ユーザーのために100問100答形式でJuliaを紹介していこうと思います。
Julia言語
Juliaってどういう言語なの?
Juliaは高レベルでハイパフォーマンスな技術計算のための動的言語だよ。書きやすさと実行速度の両立がウリの言語だよ。
誰が作ってるの?
主にボストンのMITの人達が中心に作っている言語だよ。特にJeff Bezonson, Stefan Karpinski, Viral Shah, Alan Edelmanの4人が初期の重要人物だよ。
自由に使えるの?
Juliaの処理系はMITライセンスで配布されているから、商用でもなんでもかなり自由に使えるよ。
どれくらい速いの?
すごく速いよ!大体C言語の2倍以内くらいの収まる速度だよ。
Rと比較してどうなの?
数倍から数百倍くらい高速かな。特にループや関数呼び出しがたくさんある場合には顕著な差が出るよ。
公式サイトにあるベンチマークの抜粋を載せておくよ (C言語=1.0)。
実例はある?
forループがあるような場合はかなりはっきり差が出るよ。
例えば1からNまでのコラッツ予想を実証する関数collatz
をJuliaとRで書いてみたよ。
function collatz(N) for n in 1:N while n != 1 if iseven(n) n = div(n, 2) else n = 3n + 1 end end end end
collatz <- function (N) { for (n in 1:N) { while (n != 1) { if (n %% 2 == 0) { n = n %/% 2 } else { n = 3 * n + 1 } } } }
N=100,000で試してみるとJuliaはRの300倍ぐらい高速だったよ。
julia> @time collatz(100000)
0.026903 seconds (4 allocations: 160 bytes)
R> system.time(collatz(100000))
user system elapsed
8.429 0.028 8.479
どうして速いの?
LLVMというコンパイラの基盤ライブラリをつかって実行時にコンパイルを行っているからだよ。あとJulia言語自体が最初からパフォーマンスを考慮して設計されているよ。詳しくはBezansonら論文を参照してね。
どこが技術計算に向いてるの?
実行速度が速く、かつ動的プログラミング言語で気軽に実行できるから短いスクリプトで計算するのに向いてるよ。あと、数値計算でよく用いられるデータ型や関数が最初から用意されているから、インストールしてすぐ使い始められるよ。例えば、線形代数のためにBLASやLAPACKの関数が標準で入ってるよ。
Juliaのレポジトリはどこ?
GitHubのレポジトリがここにあるよ: https://github.com/JuliaLang/julia
インストール用のバイナリは?
公式サイトのダウンロードページにWindows, Mac, Linux用のが用意してあるよ: http://julialang.org/downloads/
Juliaのマニュアルやチュートリアルは?
Juliaはドキュメントがよく書かれているから、公式マニュアルを読むのがオススメだよ。 日本語だと私が書いたJuliaのチュートリアルやM.Hiroiさんのサイトがあるよ。
環境
どうやって実行するの?
次のスクリプトをhello.jlとしてファイルに保存したとしよう。
println("hello, world")
Juliaをインストールしてあるならjulia
コマンドがあるはずなので、これにさっきのファイルを渡せばRscript
みたいに実行できるよ。
$ julia hello.jl
hello, world
対話セッション(REPL)を使うには、引数無しでjulia
を実行しよう。そうすると、下のようにRみたいなJuliaのREPLが立ち上がるよ!
$ julia
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.5.0 (2016-09-19 18:14 UTC)
_/ |\__'_|_|_|\__'_| |
|__/ | x86_64-apple-darwin14.5.0
julia> 1 + 2
3
julia>
ヘルプの調べ方は?
RみたいにREPLに?
と打ってみよう。そうするとプロンプトがhelp?>
に変わるから、知りたい関数の名前をそこに打ってEnterを押そう!
help?> sum
search: sum sum! sumabs summary sumabs2 sumabs! sum_kbn sumabs2! cumsum cumsum! consume cumsum_kbn isnumber isalnum SlotNumber
sum(itr)
Returns the sum of all elements in a collection.
sum(A, dims)
Sum elements of an array over the given dimensions.
sum(f, itr)
Sum the results of calling function f on each element of itr.
キーワード検索をする場合は、help?>
プロンプトでキーワードを"..."
で囲んで入力しよう!
help?> "variance"
Base.var
Base.cov
Base.varm
RStudioみたいなのはあるの?
RStudioほどじゃないかもしれないけど、JunoというAtomエディターをベースにした開発環境が人気だよ。他にはEclipse向けのプラグイン(https://github.com/JuliaComputing/JuliaDT)やVS Code向けのプラグイン(https://github.com/JuliaEditorSupport/julia-vscode)もあるよ。
EmacsやVimの人は?
Emacs用プラグイン(https://github.com/JuliaEditorSupport/julia-emacs)とVim用プラグイン(https://github.com/JuliaEditorSupport/julia-vim)ももちろんあるよ。
ノートブックはあるの?
IJulia.jlを使って、Jupyter Notebookを利用できるよ。すぐ試してみるのにJuliaBoxを使うといいんじゃないかな?
CRANみたいなパッケージのレポジトリはあるの?
あるよ!パッケージの一覧がhttp://pkg.julialang.org/から閲覧できるよ。
パッケージのインストールはどうするの?
Rのinstall.packages
に当たるのがPkg.add
だよ。もちろん依存解決もしてくれるよ。
GitHubにしかないパッケージのインストールは?
Pkg.clone
にレポジトリのURLを入れると野良パッケージでもインストールできるよ。ここでも依存解決をしてくれるよ。
Rを呼び出したいんだけど?
RCall.jlを使おう! RCall.jlはJuliaのコードにRを埋め込んだりRのREPLを使ったりできるよ。
Pythonも呼び出したいんだけど?
PyCall.jlを使おう! ついでに、C++が呼び出せるCxx.jlとかMATLABが呼び出せるMATLAB.jlなんてのもあるよ。
CやFortranのコードの呼び出しは?
JuliaはCやFortranのコードを呼び出す仕組みを標準で用意しているよ。 詳しくは後で説明するよ。
Rのサンプルデータを読みたいんだけど?
RDatasets.jlにRでよく使われるデータセットがパッケージされているよ!
ワークスペースを保存するにはどうするの?
JLD.jlの@save
マクロを使おう。
julia> using JLD
julia> n = 5
5
julia> x = randn(n, n)
5×5 Array{Float64,2}:
-2.18618 0.0831716 2.19386 0.806268 1.11444
-0.99689 -0.187922 -0.138358 -0.141601 0.19058
0.0971969 0.149858 -1.19826 1.15507 1.0969
-0.140956 -0.727159 0.780267 1.17143 0.979918
-0.161376 -0.162103 -0.175158 -0.402853 0.916248
julia> @save "workspace.jld"
ワークスペースを復元するには?
同じくJLD.jlの@load
マクロを使おう。
julia> using JLD
julia> @load "workspace.jld"
3-element Array{Symbol,1}:
:ans
:n
:x
julia> n
5
julia> x
5×5 Array{Float64,2}:
-2.18618 0.0831716 2.19386 0.806268 1.11444
-0.99689 -0.187922 -0.138358 -0.141601 0.19058
0.0971969 0.149858 -1.19826 1.15507 1.0969
-0.140956 -0.727159 0.780267 1.17143 0.979918
-0.161376 -0.162103 -0.175158 -0.402853 0.916248
コミュニティ
Juliaのコミュニティはどんな感じなの?
Juliaのコミュニティは小さいけれど、とてもオープンなコミュニティを形成しているよ。 特に初心者に優しい(Juliaユーザはだいたい初心者)ので、気軽にコミュニケーションを取れるよ。
質問はどこですればいいの?
英語ならDiscourseかStack Overflowだね。Stack Overflowで質問する時は"julia-lang"のタグをつけるようにしよう。 Discourseの方がJuliaハッカーが見てる率が高い気がするから、Juliaに限定した質問ならDiscourseの方がオススメかも。
日本語話者のコミュニティは?
日本ではJulia Tokyoが知る限り唯一のコミュニティかな? Facebook・Slack・GitHubのアカウントがあるし、不定期でミートアップも開催してるよ。
他にはどんなコミュニティがあるの?
Juliaのコミュニティは各ドメインに分かれてゆるくつながっているよ。 コミュニティのリストはここ(http://julialang.org/community/)にあるよ。 いくつか挙げると以下のドメインのコミュニティは結構活発かな。
ドメイン | GitHub |
---|---|
統計 | JuliaStats |
最適化 | JuliaOpt |
データベース | JuliaDB |
GPU | JuliaGPU |
生物学 | BioJulia |
微分 | JuliaDiff |
グラフィクス | JuliaGraphics |
計量経済学 | QuantEcon |
これらで活発に開発されているパッケージは概ね安心して使えるかな。
どんな人達がJuliaを使ってるの?
Juliaの使い方は色々あるけれど、やっぱり数値計算目的に使っているユーザが多いかな。 Julia Computing, Inc.の事例を見ると、金融・経済分野を始めとしたデータ分析界隈で使われ始めている印象があるな。
HPCでの事例や科学論文でJuliaを使った計算の実装も最近よく見るようになってきたよ。
他には、StanfordやMITでは技術計算の授業にもJuliaが使われているよ。
トークとかの映像は?
YouTubeのチャンネルにカンファレンスの動画などがたくさんあるよ!
https://www.youtube.com/user/JuliaLanguage
Julia界のHadley Wickhamは?
Julia界には(良くも悪くも)あれくらい目立っている人はいないかな。 Juliaの重要なパッケージは各organizationがコミュニティとして開発・管理してるよ。
文法
Rの構文との対応関係を教えて?
いいよ!
代入
# R x <- 100
# Julia x = 100
分岐
# R if (x == 0) { print("zero") } else if (x < 0) { print("negative") } else { print("positive") }
# Julia if x == 0 println("zero") elseif x < 0 println("negative") else println("positive") end
for文
# R for (i in 1:10) { print(i) if (i > 5) { break } }
# Julia for i in 1:10 println(i) if i > 5 break end end
関数
# R add <- function (x, y) x + y add <- function (x, y) { return (x + y) }
# Julia add(x, y) = x + y function add(x, y) return x + y end
ライブラリ読み込み
# R library(ggplot2)
# Julia using DataFrames
たまにJuliaのコードにある@
は何?
@
から始まるコードはJuliaのマクロ呼出しだよ。
マクロはJuliaのコードを別のコードに書き換えたりするメタプログラミングの一種だよ。
例えば次のコードに出てくる@inbounds
は配列アクセスの境界チェックを無くして少し高速化することができるし、@show
はその時の値をいい感じに表示してくれるよ。
x = randn(10) s = 0 @inbounds for i in 1:endof(x) s += x[i] end @show s
たまにJuliaのコードにあるr"..."
は何?
それもJuliaのマクロだよ!
標準ライブラリではr"..."
と書くことで文字列でなく正規表現を作ることができるよ。
julia> r"foo"
r"foo"
julia> typeof(r"foo")
Regex
julia> b"foo"
3-element Array{UInt8,1}:
0x66
0x6f
0x6f
julia> typeof(b"foo")
Array{UInt8,1}
この仕組はユーザからも拡張可能なので、例えばBio.jlではDNA配列を作ったりするのに使ってるよ。
julia> using Bio.Seq
julia> dna"ACGTAG"
6nt DNA Sequence:
ACGTAG
データ
主な数値型は?
整数はInt
型、倍精度浮動小数点数はFloat64
型がデフォルトでよく使われるよ。
Int
は32-bit環境なら32-bit、64-bit環境なら64-bitで表現されるよ。
Juliaは数値の型も豊富で、8-bitから128-bitまで符号の有り無しの組み合わせがすべて用意されているし、複素数(Complex{T}
)や有理数(Rational{T}
)もあるよ。
TRUE
やFALSE
は?
Juliaでは全部小文字のtrue
とfalse
だよ。
欠損値は扱えるの?
JuliaではNullable{T}
という型があって、型T
の欠損値を表すよ。
nothing
という値もあるけどパフォーマンス上の理由であまりお勧めしないよ。
JuliaもRみたいに常に配列として数値を扱うの?
Juliaでは単一の値と配列は区別されるよ。例えば、3
と書いたら整数の3を意味するし、[3]
と書いたら1つの整数3からなるベクトルだよ。
3
と書いたら浮動小数点数じゃなくて整数なの?
そうだよ、Rと違ってJuliaでは整数として扱われるよ。
じゃぁ浮動小数点数の3を作るには?
3.0
と書けば浮動小数点数として扱われるよ。
どうやって確認するの?
Rみたいにtypeof
という関数を使おう!
julia> typeof(3)
Int64
julia> typeof(3.0)
Float64
R> typeof(3)
[1] "double"
R> typeof(3.0)
[1] "double"
演算子はどんな感じ?
ほとんどRと同じだよ。
julia> 3 + 4
7
julia> 3 - 4
-1
julia> 3 * 4
12
julia> 3 / 4
0.75
R> 3 + 4
[1] 7
R> 3 - 4
[1] -1
R> 3 * 4
[1] 12
R> 3 / 4
[1] 0.75
Bool演算(&&
, ||
, !
)も同じだよ。排他的論理和はv0.5では$
だけど次期バージョンでxor
という名前に変更される予定だよ。
list
はあるの?
Juliaで一番近いのはDict
かな?
Pythonのdict
と同じハッシュを使った連想配列だよ。
julia> d = Dict("one" => 1, "two" => 2, "three" => 3)
Dict{String,Int64} with 3 entries:
"two" => 2
"one" => 1
"three" => 3
julia> d["two"]
2
data.frame
は?
残念ながらJuliaの標準ライブラリにはないよ。でもDataFrames.jlというパッケージがJuliaのデータフレームの標準的な実装だよ。 この辺は後で詳しく述べるよ。
多次元行列も扱えるの?
もちろん扱えるよ! Rのmatrix
みたいなことが次のようにできるよ。
julia> [1 2 3
4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> [1 2 3; 4 5 6] # セミコロンは改行と同じ扱い
2×3 Array{Int64,2}:
1 2 3
4 5 6
R> matrix(c(1, 2, 3, 4, 5, 6), nrow=2)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
空の配列の作成は?
ベクトル(1次元配列)なら[]
だよ。
julia> []
0-element Array{Any,1}
ただ要素の型が分かっている場合はそれを教えてあげるとJuliaは高速に動くよ。
julia> Int[]
0-element Array{Int64,1}
julia> Float64[]
0-element Array{Float64,1}
matrix(0, 3, 4)
みたいに0で初期化された配列の作成は?
zeros
関数を使おう!
julia> zeros(3, 4) # 3行4列の行列
3×4 Array{Float64,2}:
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
julia> zeros(Int, 3, 4)
3×4 Array{Int64,2}:
0 0 0 0
0 0 0 0
0 0 0 0
1で初期化された配列ならones
だよ。
配列要素へのアクセスはどうするの?
基本的にRと同じだよ。Juliaの配列も1始まりでcolumn majorだよ。
ただ、Rだとx[i,]
とかx[,j]
と書くところをJuliaではx[i,:]
とかx[:,j]
とか書くよ。
julia> x = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> x[1,2]
2
julia> x[2,2:3]
2-element Array{Int64,1}:
5
6
julia> x[:,2]
2-element Array{Int64,1}:
2
5
2:3
みたいなのはベクトル?
Juliaではm:n
はm
からn
までの範囲(Range
)を表すよ。
julia> 2:3
2:3
julia> typeof(2:3)
UnitRange{Int64}
ベクトルと違ってメモリーを消費しないので、長い範囲でも一瞬で作れるよ。
character
みたいな文字列型は?
JuliaではString
型があるよ。
文字列はUnicodeも使える?
使えるよ! JuliaではUTF-8でエンコーディングしてあるよ。
文字列操作関数を教えて?
stringrパッケージの関数と大雑把に対応を付けたよ。
R (stringr) | Julia |
---|---|
str_c |
string |
str_detect |
ismatch |
str_extract |
match |
str_dup |
^ |
str_split |
split |
str_replace |
replace |
str_trim |
strip , lstrip , rstrip |
str_pad |
lpad , rpad |
str_to_lower |
lowercase |
str_to_upper |
uppercase |
as.double
とかas.integer
みたいな型変換はどうするの?
Juliaの型変換は基本的にconvert
関数を使うよ。
julia> convert(Float64, 42)
42.0
julia> convert(Int64, 42.0)
42
ただし文字列をパースして数値にするにはparse
を使うよ。
julia> parse(Int, "42")
42
julia> parse(Float64, "42")
42.0
行名や列名はどうつけるの?
Juliaの標準では行名や列名をサポートしていないよ。 でもNamedArrays.jlという配列に名前を付けられるようにするパッケージはあるよ。
欠損値のある配列はどう扱えばいいの?
欠損値の扱いはまだJulia界隈でも完全な合意に達してない課題なので、ちょっとむずかしいな。
前にも述べたようにNullable{T}
というデータ型があるけど、これに関する操作が将来変わる可能性があるよ。
でも、基本的にはNullableArrays.jlを使おう!
因子(factor)を扱うにはどうするの?
これもまだJuliaではちょっと扱いが難しいけど、CategoricalArrays.jlというパッケージがあるよ。 NullableArrays.jlやCategoricalArrays.jlは近いうちにDataFrames.jlに採用される予定のようだよ。
関数
関数はどうやって定義するの?
function
キーワードを使ったスタイルと短縮記法があるよ。
# 通常の記法 function add(x, y) return x + y end # 短縮記法 add(x, y) = x + y
デフォルト引数やキーワード引数は?
あるよ! でもJuliaではデフォルト引数とキーワード引数で記法が分かれているよ。
# デフォルト引数 function default(x, y=1, z=10) return x + y + z end # キーワード引数 (セミコロンに注目) function keyword(x; y=1, z=10) return x + y + z end
試しに実行してみよう
julia> default(1)
12
julia> default(1, 0)
11
julia> default(1, 0, 5)
6
julia> keyword(1)
12
julia> keyword(1, z=5)
7
julia> keyword(1, z=5, y=0)
6
クロージャも作れる?
もちろん!
function counter() i = 0 function x(n=1) i += n return i end end
julia> c = counter()
(::x) (generic function with 2 methods)
julia> c()
1
julia> c()
2
julia> c()
3
julia> c(3)
6
julia> c()
7
+
とかは関数じゃないの?
関数だよ! 前置記法で書くこともできるよ!
julia> +(1, 2)
3
R> `+`(1, 2)
[1] 3
じゃぁRみたいにif
とかfor
も関数なの?
Juliaではif
・for
・while
は関数じゃないよ。
遅延評価はあるの?
Juliaには遅延評価はなくてすべて正格評価だよ。つまり関数に渡された引数は呼び出し前にかならず評価されるよ。
apply
みたいな関数を配列の要素に適用する関数は?
map
を使おう! ただし関数が最初の引数だよ。
julia> map(log, [1,2,3])
3-element Array{Float64,1}:
0.0
0.693147
1.09861
julia> map(exp, [1,2,3])
3-element Array{Float64,1}:
2.71828
7.38906
20.0855
R> sapply(c(1,2,3), log)
[1] 0.0000000 0.6931472 1.0986123
R> sapply(c(1,2,3), exp)
[1] 2.718282 7.389056 20.085537
ただ最近はブロードキャストを使う方法が一般的なので、こちらを使ったほうが良いよ。
julia> log.([1,2,3])
3-element Array{Float64,1}:
0.0
0.693147
1.09861
julia> exp.([1,2,3])
3-element Array{Float64,1}:
2.71828
7.38906
20.0855
この関数名の後のドットは何?
ブロードキャスト関数呼び出しの構文糖衣だよ。例えばf.(x)
はbroadcast(x, f)
に変換されるよ。
broadcast
はmap
の凄い版だよ。
ベクトル同士の足し引きとかは?
+
や-
がそのまま使えるよ。でも.
を付けた.+
や.-
なら左右で配列のサイズが違った場合でもRのように動いてくれるよ。
julia> [1,2,3] + [4,5,6]
3-element Array{Int64,1}:
5
7
9
julia> [1,2,3] .+ [4]
3-element Array{Int64,1}:
5
6
7
julia> [1,2,3] .+ 4
3-element Array{Int64,1}:
5
6
7
R> c(1, 2, 3) + c(4, 5, 6)
[1] 5 7 9
R> c(1, 2, 3) + c(4)
[1] 5 6 7
R> c(1, 2, 3) + 4
[1] 5 6 7
書いた関数が思ったより遅いんだけど?
一番よくある原因が関数内で使われている変数の型が不安定になっているせいだよ。
例えば次のコードはxs
の要素がInt
のときには高速に動くけど、浮動小数点数の配列とかを渡すとすごく遅いよ。
function sumup(xs) s = 0 for x in xs s += x end return s end
julia> xs = rand(1:10, 10000);
julia> sumup(xs); # ウォームアップ
julia> @time sumup(xs)
0.000011 seconds (5 allocations: 176 bytes)
54649
julia> xs = rand(10000);
julia> sumup(xs); # ウォームアップ
julia> @time sumup(xs)
0.000337 seconds (30.00 k allocations: 468.906 KB)
5015.030044010504
原因は変数s
は整数型で初期化されてるのに、ループの中で浮動小数点数と足すことでs
の型が整数か浮動小数点数かJuliaには分からなくなってしまうせいだよ。これをJulia界隈では型の不安定さ(type instability)と言ってるよ。
これを回避するにはeltype
とzero
関数を次のように使うことで、s
の型をxs
に合わせて設定できるよ。
function sumup(xs) s = zero(eltype(xs)) for x in xs s += x end return s end
こうすることでさっきより何十倍も速くなったね!
julia> sumup(xs);
julia> @time sumup(xs)
0.000015 seconds (5 allocations: 176 bytes)
5015.030044010504
関数のプロファイルを取るにはどうするの?
@profile
マクロと、Profile.print()
をあわせて使おう!
@profile <code>
でコード実行のプロファイルをとって、Profile.print()
でプロファイル結果をプリントできるよ。
C言語の関数の呼び出し方法を教えて!
Juliaにはccall
というC言語を呼び出す専用の命令があるよ。例えば、GNU libcに実装されているexp
関数を呼び出すなら次のように書けるよ。
julia> ccall((:exp, "libc"), Float64, (Float64,), 1.0)
2.718281828459045
julia> ccall((:exp, "libc"), Float64, (Float64,), -1.0)
0.36787944117144233
ccall
は最初に呼び出す関数を指定して、その後に返り値の型と引数の型を指定して、最後に引数を渡すよ。上の例で言えば、(:exp, "libc")
が呼び出す関数で、Float64
が返り値の型、(Float64,)
が引数の型で、1.0
や-1.0
がCの関数に渡される実際の引数だよ。
Juliaは数値以外にも文字列やより複雑な構造体をCのライブラリとやり取りすることができるように設計されているので、より詳しくはマニュアルのここを読んでみてね。 具体的な例としてはJuliaの標準ライブラリやLibz.jlなんかが勉強になるよ。
型システムとメソッド
Juliaの型システムはどうなってるの?
Juliaの型は大きく具体型(concrete type)と抽象型(abstract type)に分けられていて、メソッドの選択は多重ディスパッチというシステムを中心に構築されているよ。
具体型とか抽象型って何?
具体型はインスタンス化(オブジェクトを作れる)できる型で、抽象型はそうでない型だよ。
例えばFloat64
は1.0
など値を作れるけどReal
という抽象型は値を作れないよ。
値を作れない抽象型は何の役に立つの?
複数の型をまとめるのに使われるよ。KeitaNakamuraさんのコードを使わせてもらうと、例えばReal
を頂点とする型は次のような構造になっているよ。
julia> print_tree(Real)
Real
├─── AbstractFloat
| ├─── BigFloat
| ├─── Float16
| ├─── Float32
| └─── Float64
├─── Integer
| ├─── BigInt
| ├─── Bool
| ├─── Signed
| | ├─── Int128
| | ├─── Int16
| | ├─── Int32
| | ├─── Int64
| | └─── Int8
| └─── Unsigned
| ├─── UInt128
| ├─── UInt16
| ├─── UInt32
| ├─── UInt64
| └─── UInt8
├─── Irrational{sym}
└─── Rational{T<:Integer}
function print_tree(typ) println(typ) print_tree(typ, []) end function print_tree(typ, level) stypes = subtypes(typ) for stype in stypes if stype !== stypes[end] println(join(level) * "├─── $stype") push!(level, "| ") else println(join(level) * "└─── $stype") push!(level, " ") end print_tree(stype, level) pop!(level) end end
クラス(型)の定義はどうやるの?
RのS4に似た仕組みがJuliaにはあるよ。例えば以下の2つの定義は大体対応しているよ。
# R setClass("Person", representation(name = "character", age = "numeric"))
# Julia type Person name::String age::Int end
Juliaはデフォルトコンストラクタを準備しているから、オブジェクトは次のように作成できるよ。
julia> hadley = Person("Hadley", 31)
Person("Hadley",31)
julia> hadley.name
"Hadley"
julia> hadley.age
31
ただし、Juliaのtype
で宣言したオブジェクトは変更可能なのでその振る舞いはRの参照クラス(RC)に近いかな。
継承は?
JuliaはsetClass
のcontains
引数に当たるような継承の仕組みはないよ。つまり、複数の型間で構造を継承する方法はないよ。
その代わり、定義する型をある抽象型のサブタイプにする仕組みはあって、Juliaではこちらを使うよ。
例えば、Juliaで要素の数が3つのベクトルっぽい型を作る場合には、次のようにAbstractVector
のサブタイプとして宣言すると良いよ。
type Triplet{T} <: AbstractVector{T} x::T y::T z::T end
ここで、T
と書かれているのは型パラメータで、T = Int64
やT = Float64
が代入されて具体的な型になるよ。
また、各抽象型には実装していることが期待されるメソッドがあるので、それを実装するべきだよ (AbstractVector
ならBase.size
・Base.getindex
などを実装すべき)。
メソッドの定義は?
通常の関数定義に型指定したものがRのsetMethod
に近いよ。
# R setGeneric("greet", function(x) standardGeneric("greet")) setMethod("greet", signature("Person"), function(x) paste("Hello, ", x@name))
# Julia function greet(x::Person) return string("Hello, ", x.name) end
型指定は複数に引数に対しても指定できるし、抽象型も指定できるよ。これをJuliaでは多重ディスパッチと言うよ。
前処理
CSV/TSVファイルの読み込みは?
3通りの方法があるよ!
- 標準ライブラリの
readcsv
- DataFrames.jlの
readtable
- CSV.jlの
CSV.read
どれがいいの?
標準ライブラリのreadcsv
は標準なのですぐ使えるけど、行列としてデータを読み込むから、場合によってはちょっと使いづらいかな?
DataFrames.jlのreadtable
はデータフレームを読み込むけど、将来的に使われなくなる可能性が高いよ。
なので、現在ではCSV.jlのCSV.read
を使うのがオススメだよ。
julia> using DataFrames
julia> using CSV
julia> head(CSV.read("iris.csv"))
6×5 DataFrames.DataFrame
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species │
├─────┼─────────────┼────────────┼─────────────┼────────────┼──────────┤
│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │ "setosa" │
│ 2 │ 4.9 │ 3.0 │ 1.4 │ 0.2 │ "setosa" │
│ 3 │ 4.7 │ 3.2 │ 1.3 │ 0.2 │ "setosa" │
│ 4 │ 4.6 │ 3.1 │ 1.5 │ 0.2 │ "setosa" │
│ 5 │ 5.0 │ 3.6 │ 1.4 │ 0.2 │ "setosa" │
│ 6 │ 5.4 │ 3.9 │ 1.7 │ 0.4 │ "setosa" │
詳しい使い方はCSV.jlのヘルプを参照してね。
SQLiteのデータを読みたいんだけど?
SQLite.jlを使おう。SQLを発行した結果はDataFrame
として返してくれるよ。
JSONを扱うには?
JSON.jlを使おう。
julia> using JSON
julia> JSON.parse("""{"foo": 100, "bar": [1.1, 2.0]}""")
Dict{String,Any} with 2 entries:
"bar" => Any[1.1,2.0]
"foo" => 100
XMLやHTMLのデータを処理するには?
拙作のEzXML.jlがオススメだよ。長く使われているLightXML.jlというのもあるけれど、機能が少ないし、あまりインターフェースがきれいじゃないね...
julia> using EzXML
julia> readxml("ex1.xml")
EzXML.Document(EzXML.Node(<DOCUMENT_NODE@0x00007fcda9030400>))
julia> readxml("ex1.xml") |> print
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="COOKING" tag="first">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
でもHTMLに関してはGoogleのgumboをラップしたGumbo.jlの方が良いかな?
dplyrは?
残念ながらdplyrほどの完成度のパッケージは今のところJuliaには無いかな。 ただJuliaの人にはR使いも多いので、dplyrの利便性は誰もが認めるところだね。 それで最近は似たことをJuliaでやろうとしている人達が出てきて、いくつかパッケージができているよ。
Juliaのデータフレームの近況と将来についてはここにまとまってるよ。
UTF-8以外のファイルを読み込みたいんだけど?
StringEncodings.jlを使おう! libiconvを使ってるのでSJISみたいなアレなエンコーディングでもちゃんと扱えるよ!
統計/機械学習
平均とか分散の計算は?
mean
, median
, var
, cov
, cor
はRと同名の関数が標準ライブラリにあるよ。標準偏差はsd
でなくstd
になってるので注意だよ。
rowSums
とかcolSums
とかは?
sum(array, dim)
が使えるよ。
julia> x
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> sum(x, 1) # colSums
1×3 Array{Int64,2}:
5 7 9
julia> sum(x, 2) # rowSums
2×1 Array{Int64,2}:
6
15
他にもmean
やvar
なんかでも同じことができるよ。
乱数生成はどうするの?
一様乱数runif(n)
に対応するのはrand(n)
、正規分布rnorm(n)
に対応するのはrandn(n)
だよ。
ガンマ分布とかポアソン分布みたいな他の分布は?
Distributions.jlを使おう。
PCA(主成分分析)をしたいんだけど?
MultivariateStats.jlを使おう。
julia> using MultivariateStats
julia> using RDatasets
julia> iris = dataset("datasets", "iris")
julia> pca = fit(PCA, Matrix(iris[:,1:4])') # 行列に変換して転置
PCA(indim = 4, outdim = 3, principalratio = 0.99479)
julia> transform(pca, Matrix(iris[:,1:4])')
3×150 Array{Float64,2}:
2.68413 2.71414 2.88899 2.74534 2.72872 2.28086 … -1.94411 -1.52717 -1.76435 -1.90094 -1.39019
0.319397 -0.177001 -0.144949 -0.318299 0.326755 0.74133 0.187532 -0.375317 0.0788589 0.116628 -0.282661
0.0279148 0.210464 -0.0179003 -0.0315594 -0.0900792 -0.168678 -0.177825 0.121898 -0.130482 -0.723252 -0.36291
GML(一般化線形モデル)を扱いたいんだけど?
GLM.jlを使おう。Rでも有名なDouglas Bates先生の作ったパッケージだから安心だね!
Lassoは?
Julia実装のLasso.jlかglmnetをラップしたGLMNet.jlが良いと思うよ。
Stanを使いたいんだけど?
Stan.jlを使おう!
行列積の計算は?
Rの%*%
がJuliaでは*
だよ。
julia> A = randn(2, 3);
julia> B = randn(3, 4);
julia> A * B
2×4 Array{Float64,2}:
2.42828 -1.39917 0.28215 -1.61981
0.292669 -0.411146 0.234041 1.82686
R> A <- matrix(rnorm(6), 2)
R> B <- matrix(rnorm(12), 3)
R> A %*% B
[,1] [,2] [,3] [,4]
[1,] 0.8448714 -0.6084743 -0.7458281 -0.653775
[2,] 0.2133118 -0.9305351 0.3933490 1.105863
solve
みたいな線形方程式の解の計算は?
A * X = B
を解くには、A \ B
と計算するよ。
julia> A = randn(3, 3)
3×3 Array{Float64,2}:
0.864382 -0.945314 -0.496754
0.119709 0.83993 -0.962021
-0.737123 0.221293 0.205341
julia> X = randn(3, 2)
3×2 Array{Float64,2}:
-0.224859 1.64374
0.0726233 0.898944
-0.387804 0.697085
julia> B = A * X
3×2 Array{Float64,2}:
-0.0703728 0.224752
0.407157 0.28121
0.102188 -0.869566
julia> A \ B
3×2 Array{Float64,2}:
-0.224859 1.64374
0.0726233 0.898944
-0.387804 0.697085
julia> A \ B ≈ X
true
A
が実対称行列であることが分かってるんだけど?
cholfact(A)
でコレスキー分解してからでも同様に計算できるよ!
julia> A = randn(3, 3);
julia> A = A'A
3×3 Array{Float64,2}:
1.13074 2.65079 -0.0602727
2.65079 7.18991 -0.474305
-0.0602727 -0.474305 0.488933
julia> issymmetric(A)
true
julia> X = randn(3, 2)
3×2 Array{Float64,2}:
0.809623 0.595824
-0.25161 -2.33654
0.97426 1.46868
julia> B = A * X;
julia> A \ B
3×2 Array{Float64,2}:
0.809623 0.595824
-0.25161 -2.33654
0.97426 1.46868
julia> cholfact(A) \ B
3×2 Array{Float64,2}:
0.809623 0.595824
-0.25161 -2.33654
0.97426 1.46868
log(sum(exp(x)))
とかlog(exp(x)+1)
とかを安定的に計算したいんだけど?
StatsFuns.jlに標準ライブラリにはないけど、数値計算でよく見る関数の実装があるからそっちを探してみよう。
julia> x = randn(10)
10-element Array{Float64,1}:
0.0410153
-0.407537
1.26758
-0.52522
-0.0969684
-2.52716
-0.633663
-1.2695
-0.474312
-0.800294
julia> log(sum(exp(x)))
2.165782421890441
julia> logsumexp(x)
2.165782421890441
julia> log(sum(exp(1000x))) # 1000倍すると計算できない
Inf
julia> logsumexp(1000x) # StatsFuns.jlの実装なら大丈夫
1267.5802777924926
プロット作るにはどうするの?
残念ながら、今のところJuliaには決定的なプロットのための仕組みがあるわけではないので、次のものを参考に好みに合ったのを使おう!
- Gadfly.jl
- 最も歴史のあるJuliaの
- 一番スターが多い
- Plots.jl
- 新興で急成長中のライブラリ
- 開発が活発
- PlotlyJS.jl
- Plot.lyのラッパーライブラリ
- インタラクティブな可視化が可能
- PyPlot.jl
- Pythonのmatplotlibのラッパーライブラリ
- 最も高機能かも
- GR.jl
- GRフレームワークのラッパーライブラリ
- パフォーマンスに優れる
- UnicodePlots.jl
- Unicode文字を使ってターミナル上でプロットできるライブラリ
- ごく簡単なプロットをチラッと見たいときに向いてる
関数の最大・最小値を探したいんだけど?
Optim.jlを使おう!
julia> using Optim
julia> rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
rosenbrock (generic function with 1 method)
julia> optimize(rosenbrock, randn(2))
Results of Optimization Algorithm
* Algorithm: Nelder-Mead
* Starting Point: [0.4289709134439212,-1.3041568238701216]
* Minimizer: [1.0000314591723356,1.0000648302370259]
* Minimum: 1.354834e-09
* Iterations: 69
* Convergence: true
* √(Σ(yᵢ-ȳ)²)/n < NaN: false
* Reached Maximum Number of Iterations: false
* Objective Function Calls: 136
R> rosenbrock <- function (x) (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2
R> optim(rnorm(2), rosenbrock)
$par
[1] 0.9995882 0.9991591
$value
[1] 2.002849e-07
$counts
function gradient
129 NA
$convergence
[1] 0
$message
NULL
Juliaの機械学習パッケージはどうなってるの?
Juliaユーザには機械学習を常用する人も多いけれど、PythonやRほど充実はしてないよ。 一応、ScikitLearn.jlというscikit-learnのラッパーがJuliaのパッケージになってるので、scikit-learnでできることはできるはずだよ。
Gradient boostingとかは?
XGBoost.jlが使えるよ! 名前から分かる通りXGBoostへのJuliaのインターフェースだよ。
Deep learningのライブラリは?
MXNet.jlというMXNetのパッケージがあるよ。またDMLCだね。他にはMocha.jlというJulia製のフレームワークもあるけれど、メインの開発者がmxnetの方に移ったようなので今はそれほど開発が活発でもないかな。 他にはTensorFlow.jlというPythonのTensorFlowのラッパーライブラリもあるよ。
もっとJuliaっぽいやつだと、Transformations.jlとかNAISTの進藤先生が作っているMerlin.jlというパッケージもあるよ。
結局、Juliaでデータ解析はどうなの?
Juliaは機械学習のアルゴリズムを組むには良い言語だと思うけど、ライブラリやツールもとても少ないね。 なので現状、インタラクティブな探索的データ解析(exploratory data analysis)をするような場合にはJuliaよりRの方をオススメするよ。
ただ、最近JuliaMLという機械学習に特化したコミュニティができてJuliaで気軽に機械学習ができるようにしていたり、データフレームに本格的に見直そうとしていたりとか、改善に向けて動いているよ。今ならやることがたくさんあるので、活動に参加してみてはどうかな?