LoginSignup
15
22

More than 3 years have passed since last update.

Python使いやRuby使いにとってのJuliaの基礎 ①文法のさわり

Last updated at Posted at 2019-04-30

序 : Juliaの良さを3行で

  • Linux/Mac環境なら導入は簡単
  • PythonやRubyのテイストを取り入れた言語なので、データの前処理を簡潔に書けるよ。
  • ベクトル、行列、実数・虚数等を扱う数値計算のコーディングを簡潔にできて速い。

(自身が理解できている数式を用いた)数値計算が楽ちんということは、今さら自分が言う必要がないだろうから、ここでは、データマエショリストとして、データの前処理周りにjuliaを使うことを念頭に書いておきたい。PythonやRubyと同じようにデータの前処理を書けるスクリプト言語としても、Juliaが使えるを検証することが目的。

ちょっと補足しておこう:

自分的Juliaの良さ① : Windows10のWSLでも簡単導入

たいていのLinuxでは、juliaバージョン1.1は以下の3行で導入できる。

curl https://julialang-s3.julialang.org/bin/linux/x64/1.0/julia-1.1.0-linux-x86_64.tar.gz
tar zxvf julia-1.1.0-linux-x86_64.tar.gz
echo 'export PATH="$PATH:/home/kmr/julia-1.1.0/bin"' >> ~/.bashrc

すなわち、業務用のWindows10では、謎のウィルス対策ソフトが入っている関係でapt updateができなかったりするWSL(Ubuntu)でも導入できるということ。
また、ひとまずJulia1.1が導入できれば、scikit-learnやsparkを使うためのパッケージ導入もサクサクできた(ウィルス対策ソフトの設定次第なのかもしれないが...)。

自分的Juliaの良さ② : けっこうbatteries included

batteries included(バッテリー同梱)とは、標準ライブラリが充実しているpythonのうたい文句のひとつ。JuliaもディフォルトでDataframeが使えるし、データを扱うための言語機能や標準ライブラリが豊富(なのだと思う)。

周辺ライブラリの充実はまだまだこれからだろうけど、個人的にはなんとかなりそう(postgresへの接続、sparkの活用など)。

自分的Juliaの良さ③ : Fortranに替えての、今風の教育用言語になりそう

中高一貫校あたりに通っていて方程式を覚え始めたばかりの中学生くらいの教育用言語として、juliaははまる気がする。
子供たちに数値計算を教える時に、良いのではと思ったり。

数値計算ならば、まずは、C/Fortran書かねばという方々は、アセンブラからC/Fortran作るところから始める別の道を作ってくださいませ。

Juliaの基礎知識

「Python使いやRuby使いが」と題したものの、以下、1.0以前のJuliaの分かりやすい解説である『PythonistaのためのJulia入門』をフォーク(?)させてもらう形で、Python使いがJuliaを使う必要に迫られた際に覚えておくべき構文などをメモしていきます。Rubyはワンライナー書く時くらいにした使わないもので。
ただし、そもそもJuliaの文法はどちらからというRuby寄りだし、今やPythonも書けるRubyistも多いだろうから、Rubyistの皆さんも斜め読みしてください。なお、以下、Juliaのバージョンは1.1で。
なお、Juliaの導入法などは省いているので、そのあたりは、Julia 入門①などをご参考に。

まずは、REPLでハローワールド。

julia> print("Hello World!")
Hello World!

また、juliaでは(Fortranと同じく)listなどのindexは0からではなく 1 から始まる。
※ コードは;で区切ることで、1行で書くことができる。

julia> List = [0, 1, 2];print(List[1])
0

文字列のスライスも、同じくindexは1 からであること確認しておこう。
※ スライスはpython風の表記。ブロックの考え方はrubyに近い。

helloworld2.jl
s = "hello julia world."
for n = s[7:11]
    print(n)
end
println()
for n = s[13:18]
    println(n)
end

ワンランナーにしておこう:
※ print関数は改行なし、println関数は改行あり。


julia> s = "hello julia world."; for n = s[7:11];print(n);end; println(); for n = s[13:18];println(n);end
julia
w
o
r
l
d
.

なお、文字列はfor文中で、直接扱える(イテレータということだろうね)。

julia> for s = "aiueo";println(s);end
a
i
u
e
o

付記 C言語風のprintf

Printfパッケージを使えば、C言語風のprintfを行える。
参考:
https://qiita.com/CORDEA/items/6164b3d1465c3c1a195a#printf

julia> e = 
 = 2.7182818284590...

julia> typeof(e)
Irrational{:}

julia> str  = "オイラー数"
"オイラー数"

julia> using Printf

julia> @printf "%sは、%f に近似されるIrrationalである。" str e
オイラー数は、2.718282 に近似されるIrrationalである。

printfマクロではカッコやカンマが省略できる。

制御構造(Control flow)

取り急ぎ、forとif周りと例外処理を押さえておこう。

for Loop statements

pythonでfor i in range(10)と書くところ、Juliaはスライスで書く。

for n = 0:9
    println(n)
end

イコールの代わりに、for x in イテレータといった形でも書ける。


julia> for n in 0:9;print("$n.");end
0.1.2.3.4.5.6.7.8.9.

個人的には、julia使う時は何かを計算したいという時だろうから、なるべくイコールをガンガン書きたい。
$nのところは、モダンな言語のたしたみ、string interpolation(文字列補間)。

If statements

pythonでif~elif~elseであるところ、juliaではif~elseif~else
また、Juliaでは、and&&or||となる。

hoge = "hoge"
if hoge[1] == 'h' && hoge[2:4] == "oge"
    println("hoge is hoge")
elseif hoge == "huge" || hoge == "hige"
    println("hoge is huge or hige")
else
    println("hoge is ", hoge)
end

応用: ifとforを組み合わせてのList complemention

List complemention(内包表記)が、pythonと同様につかえる。

julia> [x^3 for x in 0:9]
10-element Array{Int64,1}:
   0
   1
   8
  27
  64
 125
 216
 343
 512
 729

マイナスにステップするイテレータと組み合わせると:

julia> [x for x = 5:-2:-5]
6-element Array{Int64,1}:
  5
  3
  1
 -1
 -3
 -5

後置ifと組み合わせることもできる。

julia> [x for x in 0:30 if x % 5 == 1 ]
6-element Array{Int64,1}:
  1
  6
 11
 16
 21
 26

juliaらしく、虚数を扱う例もおまけに:

julia> [[x + y * im for y = -2:3] for x = 0:4]
5-element Array{Array{Complex{Int64},1},1}:
 [0-2im, 0-1im, 0+0im, 0+1im, 0+2im, 0+3im]
 [1-2im, 1-1im, 1+0im, 1+1im, 1+2im, 1+3im]
 [2-2im, 2-1im, 2+0im, 2+1im, 2+2im, 2+3im]
 [3-2im, 3-1im, 3+0im, 3+1im, 3+2im, 3+3im]
 [4-2im, 4-1im, 4+0im, 4+1im, 4+2im, 4+3im]

内包表記は行列を扱う際にも使える。

julia> A = reshape([x^2 for x in 0:11], 3,4)
3×4 Array{Int64,2}:
 0   9  36   81
 1  16  49  100
 4  25  64  121

Juliaでは、行列は簡単に転置ができる。

julia> A'
4×3 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}:
  0    1    4
  9   16   25
 36   49   64
 81  100  121

Exception Handling (例外処理)

例外処理は、try~catchでおこなえる:

err.jl
vec = [x for x = 5:-2:-5]

for i in 1:8 
    try
        println("$(vec[i])の平方根は、$(√vec[i])")
    catch e
        println("Err! : ",e)
    end
end

実行結果:

$ julia err.jl
5の平方根は、2.23606797749979
3の平方根は、1.7320508075688772
1の平方根は、1.0
Err! : DomainError(-1.0, "sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")
Err! : DomainError(-3.0, "sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")
Err! : DomainError(-5.0, "sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).")
Err! : BoundsError([5, 3, 1, -1, -3, -5], (7,))
Err! : BoundsError([5, 3, 1, -1, -3, -5], (8,))

関数・函数

基礎

pythonのdefの代わりはjuliaではfunction(関数)だが、7文字もあるのは嫌なので、
個人的には、数学的なイコール表記のmethods(自分訳:函数?)で押し通すことにしている。

julia> function add(x,y);x+y;end
add (generic function with 1 method)

julia> [[ add(x,y) for y = 0:3] for x = 0:2]
3-element Array{Array{Int64,1},1}:
 [0, 1, 2, 3]
 [1, 2, 3, 4]
 [2, 3, 4, 5]

julia> add(x,y) = x+y
add (generic function with 1 method)

julia> [[ add(x,y) for y = 0:3] for x = 0:2]
3-element Array{Array{Int64,1},1}:
 [0, 1, 2, 3]
 [1, 2, 3, 4]
 [2, 3, 4, 5]

Juliaの基礎知識として、function(関数)・methods(函数)がコンパイルの単位となることがある。
コンパイル後はインタープリタ実行に比べ相当に(私の環境では約100倍)、実行速度が速くなる。
コードの見通しも良くなるし使わない手はない。

函数も、let~endでブロックを作ることで副作用のある操作を書ける。
前述のif文をもとに、函数を作ってみる。

hoge.jl
isHoge(h)= let
  print(h*"を受け取りました: ")
    if h[1] == 'h' && h[2:4] == "oge"
        "hoge is hoge."
    elseif h == "huge" || h == "hige"
        "hoge is not huge or hige."
    else
        "hoge is not $(h)."
    end
end

for s = "aiueo"
    ret = isHoge("h$(s)ge")
    println(ret)
end

等号が入ることでぱっと見、Ocamlやscalaなどの関数型言語に近い見た目となる。

実行結果:

$ julia hoge.jl
hageを受け取りました: hoge is not hage.
higeを受け取りました: hoge is not huge or hige.
hugeを受け取りました: hoge is not huge or hige.
hegeを受け取りました: hoge is not hege.
hogeを受け取りました: hoge is hoge.

Anonymous Functions(匿名函数)

pythonのlambda x, y : x + yは、juliaでは、(x, y) -> x + y
pythonのlambdaは可読性が低いと感じているため、これはうれしい。
なお、juliaの場合、関数・函数の引数xやyには、整数・有理数の他、和(足し算)が成り立つ無理数や虚数も取ることができる(もちろん、無理数は近似値を返す)。

julia> z = (x, y) -> x + y
#3 (generic function with 1 method)

julia> z(-2,3)
1

julia> z(im,3-2im)
3 - 1im

julia> z(im, .3)
0.3 + 1.0im

julia> z(im,π)
3.141592653589793 + 1.0im

ファイルを扱う関数の例

データ前処理に欠かせない、ファイルの読み書きを扱う関数を見ておこう。
ファイルの読み書きでは、pythonのwith open(ファイル名) as fと同じようなopen(ファイル名) do fといった書き方をする。

Read

loadrile.jl
open("hoge.jl") do f
    for line in eachline(f)
        println(line)
    end
end

Write

先ほどのisHoge函数の出力をファイルに書き出す場合:

open("hogeout.txt", "w") do f
    for s = "aiueo"
        ret = isHoge("h$(s)ge")
        write(f, "$(ret)\n")
    end
end

クラス

Julisにクラスは無い。これはCやNimなどと同様で潔い。
もちろん、やろうと思えば、オブジェクト指向プログラミングはできる。
興味がある方は、Julia界の日本人エバンジェリスト黒木先生のツイートをどうぞ:
https://twitter.com/genkuroki/status/978716550268993536?lang=ja

続く

Dataframeやデータベースの扱いなどは、データ前処理編にて。

15
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
22