りんごがでている

何か役に立つことを書きます

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)。 f:id:bicycle1885:20161214151939p:plain

実例はある?

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ら論文を参照してね。

どこが技術計算に向いてるの?

実行速度が速く、かつ動的プログラミング言語で気軽に実行できるから短いスクリプトで計算するのに向いてるよ。あと、数値計算でよく用いられるデータ型や関数が最初から用意されているから、インストールしてすぐ使い始められるよ。例えば、線形代数のためにBLASLAPACKの関数が標準で入ってるよ。

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)もあるよ。

EmacsVimの人は?

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})もあるよ。

TRUEFALSEは?

Juliaでは全部小文字のtruefalseだよ。

欠損値は扱えるの?

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かな? Pythondictと同じハッシュを使った連想配列だよ。

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:nmから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ではifforwhileは関数じゃないよ。

遅延評価はあるの?

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)に変換されるよ。 broadcastmapの凄い版だよ。

ベクトル同士の足し引きとかは?

+-がそのまま使えるよ。でも.を付けた.+.-なら左右で配列のサイズが違った場合でも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)と言ってるよ。 これを回避するにはeltypezero関数を次のように使うことで、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)に分けられていて、メソッドの選択は多重ディスパッチというシステムを中心に構築されているよ。

具体型とか抽象型って何?

具体型はインスタンス化(オブジェクトを作れる)できる型で、抽象型はそうでない型だよ。 例えばFloat641.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はsetClasscontains引数に当たるような継承の仕組みはないよ。つまり、複数の型間で構造を継承する方法はないよ。

その代わり、定義する型をある抽象型のサブタイプにする仕組みはあって、Juliaではこちらを使うよ。 例えば、Juliaで要素の数が3つのベクトルっぽい型を作る場合には、次のようにAbstractVectorのサブタイプとして宣言すると良いよ。

type Triplet{T} <: AbstractVector{T}
    x::T
    y::T
    z::T
end

ここで、Tと書かれているのは型パラメータで、T = Int64T = Float64が代入されて具体的な型になるよ。 また、各抽象型には実装していることが期待されるメソッドがあるので、それを実装するべきだよ (AbstractVectorならBase.sizeBase.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通りの方法があるよ!

  1. 標準ライブラリのreadcsv
  2. DataFrames.jlのreadtable
  3. CSV.jlCSV.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

他にもmeanvarなんかでも同じことができるよ。

乱数生成はどうするの?

一様乱数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
  • PyPlot.jl
    • Pythonのmatplotlibのラッパーライブラリ
    • 最も高機能かも
  • GR.jl
  • 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で気軽に機械学習ができるようにしていたり、データフレームに本格的に見直そうとしていたりとか、改善に向けて動いているよ。今ならやることがたくさんあるので、活動に参加してみてはどうかな?