2022年
3月
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

setup diary

2007|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|06|08|11|
2015|01|02|03|04|05|06|07|08|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|

2022-03-07 行列の計算の言語による違い

_ Rとjuliaとpythonとruby

プログラム言語で数値計算をしようとするときに,行列を扱う必要がある場合がある.そのやり方が言語毎に特徴があるので,比較してみた.例として,行列を定義して,固有値を固有ベクトルを求めて,対角化を計算する場合について,やり方を見てみよう.

まず,私が数値計算をするときによく使っているRでは,インストールするだけで,行列を使うことができる.逆行列を求めるコマンドがsolveである点と,行列の掛け算が%*%であることに注意すれば,簡単に使うことができる.

a<-t(matrix(1:4,2,2))
r<-eigen(a)
r$values
r$vectors
solve(r$vectors)%*%a%*%r$vectors

次に,近年人気が出てきたjuliaであるが,これもインストールした時点で行列自体は使えて,さらにLinearAlgebraを組み込むことによって,固有値などの計算をすることができる.

a=[1 2; 3 4]
using LinearAlgebra
r=eigen(a)
r.values
r.vectors
inv(r.vectors)*a*r.vectors

数値計算の分野でもシェアを広げているpythonでは,numpyを使う必要がある.pipなどでこれをインストールできる.私の場合は,debianでaptitudeからpython3-numpyを入れた.numpyをimportして,linalgを使うと計算ができる.行列の掛け算がnp.dot()で書かないといけないのが面倒だったのだが,新しいversionでは@を使えるようになったようだ.

import numpy as np
a=np.array([[1,2],[3,4]])
r=np.linalg.eig(a)
r[0]
r[1]
#np.dot(np.dot(np.linalg.inv(r[1]),a),r[1])
np.linalg.inv(r[1])@a@r[1]

最後にrubyであるが,数値計算は比較的苦手である.行列計算はnarrayを使えば良いのだが,固有値の計算などは困難である.そこで,numo-linalgというものを使ってみた.このインストールは少し手間取ったが,以下のようにしたらdebianにインストールすることができた.

sudo apt install liblapacke libopenblas0
sudo apt install git ruby gcc ruby-dev rake make
sudo gem install specific_install
sudo gem specific_install https://github.com/ruby-numo/numo-narray.git
sudo gem install numo-linalg -- --with-backend=openblas --with-openblas-lib=/usr/lib/x86_64-linux-gnu

すると,numo/linalgをrequireしたら計算できるのだが,いちいちNumoと書くのが面倒なので,それをincludeした.narrayの場合には,NMatrixを定義すると,行列の積は*で書けるのだが,numoの場合には,numo-narrayのdotを使って書かないといけないのが面倒に感じた.

require "numo/linalg"
include Numo
a=NArray[[1,2],[3,4]]
r=Linalg.eig(a)
r[0]
r[2]
Linalg.inv(r[2]).dot(a).dot(r[2])

これらの4つの言語について,インストールのしやすさと,使いやすさを主観でまとめると,下の表のようになった.Rとjuliaはそれなりに使いやすいかな.pythonは行列の積が書きやすくなったことにより,昔よりは書きやすくなった.rubyはインストールが面倒だし,methodをうまく定義して,もっと使いやすくできるポテンシャルを秘めているが,まだまだのように感じる.ニーズが無いのかな.

installuse
R
julia
python△→○
ruby

数値計算をする場合には,Rを中心にやっていくことになりそうだ.juliaも使うようにすると,Rが苦手な処理を書きやすくなるかも知れない.


2022-03-14 Rとjuliaとrubyとpython

_ 数値の取り扱い

juliaを少しいじり始めたのだが,複数の言語の文法を混同して分からなくなってしまうので,並べて比較してみることにした.まずは,数値や数学関係の取り扱い方を,4つの言語について表にしてみた.
Rjuliarubypython3
5%%25.0%2.05.0%2.05.0%2.0
5%/%25.0÷2.05/2 or 5.0.div(2.0)5.0//2.0
分数5//25r/2from fractions import Fraction;Fraction(5,2)
xorbitwXor(3, 5)3⊻53^53^5
累乗2^0.52^0.52**0.52**0.5
平方根sqrt(2)√2Math.sqrt(2)import math;math.sqrt(2)
複素数(1+2i)^0.5(1+2im)^0.5(1+2i)**0.5(1+2j)**0.5
複素数sqrt(1+2i)√(1+2im)Math.sqrt(1+2i)import numpy;numpy.sqrt(1+2j)
実部 Re(1+2i) real(1+2im) (1+2i).real (1+2j).real
虚部 Im(1+2i) imag(1+2im) (1+2i).imag (1+2j).imag
共役 Conj(1+2i) conj(1+2im) (1+2i).conj (1+2j).conjugate()
偏角 Arg(1+2i) angle(1+2im) (1+2i).arg import cmath;cmath.phase(1+2j)
絶対値abs(-1)abs(-1)-1.absabs(-1)
円周率piπMath::PIimport math;math.pi
Euler数exp(1)Math::Eimport math;math.e
それぞれ,書き方に特徴がある.同じ記号でも,言語によって意味が違う場合があるので,注意が必要である.また,rubyではMathを使わないといけない場合があり,pythonはmathやnumpyなどを使わないといけない場合があり,どの場合にそれらを使わないといけないかを覚えるのが面倒に感じた.Rやjuliaは必要なものは,標準で大体は揃っているように感じるが,juliaではunicode文字を使えるのが特徴的である.eとℯが違うというのも少し驚いた.pythonの複素共役は関数なので括弧が必要というのが奇妙に感じた.

2022-03-21 Rとjuliaとrubyとpython

_ 文字列の取り扱い

前回,4つの言語の比較したが,数値関係の使いやすさはjulia, R, ruby, pythonの順のように感じられた.今回は第二弾で,文字列の扱い方について書きたいと思う.表にまとめると,以下のようになった.
Rjuliarubypython3
繰返 paste(rep("abc",3),collapse="") "abc"^3 "abc"*3 "abc"*3
連結 paste("abc","def",sep="") "abc"*"def" "abc"+"def" "abc"+"def"
結合 paste(1:5,collapse=", ") join(1:5,", ") [*1..5]*", " ", ".join(map(str,range(1,6)))
取出 substr("πℯ^2",2,2) collect("πℯ^2")[2] "πℯ^2"[1] "πℯ^2"[1]
部分 substr("πℯ^2",2,3) String(collect("πℯ^2")[2:3]) "πℯ^2"[1..2]
"πℯ^2"[1,2]
"πℯ^2"[1:3]
文字数 nchar("πℯ^2") length("πℯ^2") "πℯ^2".length
"πℯ^2".size
len("πℯ^2")
大文字 toupper("This") uppercase("This") "This".upcase "This".upper()
小文字 tolower("This") lowercase("This") "This".downcase "This".lower()
入れ替え chartr("A-Za-z","a-zA-Z","This") "This".swapcase "This".swapcase()
埋込 s="world"
"Hello $(s)!"
s="world"
"Hello #{s}!"
s="world"
f"Hello {s}!"
"Hello {}!".format(s)
書式 sprintf("%d %s",3,"times") using Printf;@sprintf("%d %s",3,"times") sprintf("%d %s",3,"times")
"%d %s"%[3,"times"]
"%d %s"%(3,"times")
文字列 as.character(123) string(123) 123.to_s str(123)
整数 as.integer("1") parse(Int,"1") "1".to_i int("1")
浮動小数点 as.numeric("1") parse(Float64,"1") "1".to_f float("1")
複素数 as.complex("1+2i") parse(Complex{Int},"1+2im") "1+2i".to_c complex("1+2j")
コード変換 utf8ToInt("A") Int('A') "A".ord ord("A")
文字変換 intToUtf8(960) Char(960) 960.chr(Encoding::UTF_8) chr(960)
検索 regexpr("[\\d\\.]+","pi=3.14",perl=TRUE) match(r"[\d\.]+","pi=3.14") "pi=3.14"=~/[\d\.]+/ import re;re.search("[\d\.]+","pi=3.14")
置換 sub("(\\d)\\.",".\\1","pi=3.14") replace("pi=3.14", r"(\d)\." => s".\1") "pi=3.14".sub(/(\d)\./,'.\1') import re;re.sub("(\d)\.",".\\1","pi=3.14")
分割 strsplit("1,2, 3",",\\s*")[[1]] split("1,2, 3", r",\s*") "1,2, 3".split(/,\s*/) import re;re.split(",\s*","1,2, 3")
Rは文字列処理がクセがあるが,一通りのことはできる.juliaはunicodeの文字を扱うときに,indexの指定が難しい.pythonは正規表現でimportが面倒なのと,joinの順序が感覚と異なる.文字列の使いやすさはruby, python, julia, Rの順かな.

2022-03-28 Rとjuliaとrubyとpython

_ フロー制御

4つの言語の比較の第三弾として,プログラムのフロー制御について,表にまとめてみた.
Rjuliarubypython3
if a<-3
if(a==1){cat(1)
}else if(a==2){cat(2)
}else{cat(3)}
a=3
if a==1 print(1)
elseif a==2 print(2)
else print(3)
end
a=3
if a==1 then p 1
elsif a==2 then p 2
else p 3
end
a=3
if a==1:print(1)
elif a==2:print(2)
else:print(3)
三項演算子 a<-2
cat(ifelse(a>0,"+","-"))
a=2
print(a>0 ? "+" : "-")
a=2
print(a>0?"+":"-")
a=2
print('+' if a>0 else '-')
switch i<-"a"
cat(switch(i,a=1,b=2))
i="a"
p case i
when "a" then 1
when "b" then 2
end
for for(i in 1:10){cat(i);cat("\n")} for i=1:10 println(i) end for i in 1..10 do p i end for i in range(1,11):print(i)
while i<-0
while(i<10){cat(i<-i+1);cat("\n")}
let i=0
while i<10 println(i+=1) end
end
i=0
while i<10 do p i+=1 end
i=0
while i<10:i+=1;print(i)
無限ループ repeat{cat(1);cat("\n")} while true println(1) end loop{p 1} while True:print(1)
ループを抜ける break break break break
次のループ next continue continue next
例外処理 tryCatch(cat("1"/0),
error=function(e)cat(-1))
try print("1"/0)
catch
print(-1)
end
begin
p "1"/0
rescue
p -1
end
try:print("1"/0)
except:print(-1)
終了処理 tryCatch({cat(1);cat("\n")},
finally=cat(2))
try println(1)
finally
println(2)
end
begin
p 1
ensure
p 2
end
try:print(1)
finally:print(2)
複文 a<-{cat(1);2} a=(print(1);2) a=(p 1;2)
いくつか,感想を羅列する.juliaとpythonはswitch文に相当する命令が無いので,if文などで書き下す必要がある.pythonは,ループなどの終了の記号が無いので,すっきりして感じられる.juliaの三項演算子はスペースが無いとエラーが出るのが面倒.python以外は値が返ってくるので,分かりやすい.フロー制御については,それぞれクセはあるけれど,どれが使いやすいか,甲乙つけ難しという感じでしょうか.