裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

Julia に翻訳--220 ppnd,正規分布のパーセント点(0.975 を与えると 1.96 を返すような)

2021年05月07日 | ブログラミング

#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

algorithm as241  appl. statist. (1988) vol. 37, no. 3, 477- 484.
https://jblevins.org/mirror/amiller/as181.f90

ファイル名: ppnd.jl  関数名: ppnd

翻訳するときに書いたメモ

元は FORTRAN プログラム。書き方も古風なので(GO TO があったり),少し新しめに。

以下の処理を明確化
p = 0, 1 ==> -Inf, Inf
p < 0, p > 1 ==> NaN

==========#

function ppnd(p)
  #=====
  algorithm as241  appl. statist. (1988) vol. 37, no. 3, 477- 484.

  produces the normal deviate z corresponding to a given lower tail area of p;
  z is accurate to about 1 part in 10^7.
  =====#

# coefficients for p close to 0.5

  a0 = 3.3871327179; a1 = 50.434271938; a2 = 159.29113202; a3 = 59.10937472
  b1 = 17.895169469; b2 = 78.757757664; b3 = 67.1875636

# coefficients for p not close to 0, 0.5 or 1.

  c0 = 1.4234372777; c1 = 2.7568153900; c2 = 1.3067284816; c3 = 0.17023821103
  d1 = 0.7370016425; d2 = 0.12021132975

# coefficients for p near 0 or 1.

  e0 = 6.6579051150; e1 = 3.0812263860; e2 = 0.42868294337; e3 = 0.017337203997
  f1 = 0.24197894225; f2 = 0.012258202635

  q = p - 0.5
  if abs(q) <= 0.425
    r = 0.180625 - q^2
    z = q * (((a3 * r + a2) * r + a1) * r + a0) / (((b3 * r + b2) * r + b1) * r + 1)
  else
    r = q < 0 ? p : 1 - p
    if r < 0
      z = NaN
    elseif r == 0
      z = Inf
    else
      r = sqrt(-log(r))
      if r <= 5
        r -= 1.6
        z = (((c3 * r + c2) * r + c1) * r + c0) / ((d2 * r + d1) * r + 1)
      else
        r -= 5
        z = (((e3 * r + e2) * r + e1) * r + e0) / ((f2 * r + f1) * r + 1)
      end
    end
    q < 0 && (z = -z)
  end
  z
end

R では qnorm() に相当する。

using Rmath
function check(x)

  println("ppnd($x) = $(ppnd(x)), qnorm($x) = $(qnorm(x)), abs(diff) = $(abs(ppnd(x)-qnorm(x)))")
end

check.([0.975, 0.0001, 0.4, -1, 0, 1, 2])
# ppnd(0.975) = 1.9599641740135167, qnorm(0.975) = 1.9599639845400536, abs(diff) = 1.8947346314135416e-7
# ppnd(0.0001) = -3.719016535339939, qnorm(0.0001) = -3.71901648545568, abs(diff) = 4.988425894580928e-8
# ppnd(0.4) = -0.2533470936835343, qnorm(0.4) = -0.2533471031357998, abs(diff) = 9.452265470333288e-9

# ppnd(-1.0) = NaN, qnorm(-1.0) = NaN, abs(diff) = NaN
# ppnd(0.0) = -Inf, qnorm(0.0) = -Inf, abs(diff) = NaN
# ppnd(1.0) = Inf, qnorm(1.0) = Inf, abs(diff) = NaN
# ppnd(2.0) = NaN, qnorm(2.0) = NaN, abs(diff) = NaN

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia に翻訳--219 トーラス,3次元プロット

2021年05月06日 | ブログラミング

    

#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

MATLAB や Python(matplotlib) の例はよくあるが。

ファイル名: torus.jl  関数名: torus

翻訳するときに書いたメモ

meshgrid って,結局は単純な物だ

==========#

using Plots
function torus(n=100, a=2, b=9)
    pyplot()
    u = reshape(repeat(range(0, 2π, length=n), n), n, n);
    v = u';
    x = (b .+ a .* cos.(u)) .* cos.(v);
    y = (b .+ a .* cos.(u)) .* sin.(v);
    z = a .* sin.(u);
    surface(x, y, z, lims=(-10, 10))
end

torus(30)

torus(50, 5, 10)
savefig("fig.png")

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia に翻訳--218 バットマン,方程式による描画

2021年05月05日 | ブログラミング

#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

バットマン方程式- バットサインの数式による描画 
http://www.r-bloggers.com/the-batman-equation/

ファイル名: batman.jl  関数名: batman

翻訳するときに書いたメモ

最初にプロット領域を宣言しなくてよいのは楽

==========#

using Plots

x11 = 3:0.001:7
x12 = 7:-0.001:4
y1 = vcat(3*sqrt.(1 .- (x11 ./ 7) .^ 2), -3sqrt.(1 .- (x12 ./ 7) .^2));
x2 = 4:-0.001:0
y2 = x2 ./ 2 .- (3*sqrt(33)-7) .* x2 .^ 2 ./112 .- 3 .+ sqrt.(1 .- (abs.(x2 .- 2) .- 1) .^ 2);
x345 = [1, 0.75, 0.5, -0.5, -0.75, -1, 1];
y345 = [1, 3, 2.25, 2.25, 3, 1, 1];
x6 = 1:0.001:3;
y6 = 1.5 .- 0.5 .* x6 .+ 6sqrt(10) .* (1/7 .- sqrt.(4 .- (x6 .- 1) .^2) ./14);
plt = plot(x345, y345, seriestype=:shape, grid=false, tick_direction=:out, ticks=false, showaxis=false,
               color=:black, size=(500, 215), aspect_ratio=1, label="")
plot!(vcat(0, x6, x11, x12, x2, 0), vcat(1, y6, y1, y2, 1), seriestype=:shape, color=:black, label="")
plot!(-vcat(0, x6, x11, x12, x2, 0), vcat(1, y6, y1, y2, 1), seriestype=:shape, color=:black, label="")
display(plt)
savefig("batman.png")

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

1/3 ずつに分割せよ...変わったケーキカット

2021年05月05日 | ブログラミング

円を二本の平行な直線で分割して,3分割された面積が等しくなるようにする方法を求める。

単位円で,第1象限のみを考える。YP が 片方の直線で,直径から Y だけ離れた点を通る平行線で切るということだ。OP より下の扇形の面積を S3,OP より上の扇形の面積を S1+S2 とする。S1 = 2(S2 + S3) であれば,題意を満たす。
S1 + S2 = (π - θ) / 4
S2 = sin(θ) * cos(θ) / 2
S3 = θ / 2
Y = sin(θ)

using Plots

function drawcake()
    θ = range(0, π/2, length= 2000)
    x, y = cos.(θ), sin.(θ)
    plt = plot(x, y, grid=false, tick_direction=:out, ticks=false, showaxis=false,
               color=:black, size=(400, 400), aspect_ratio=1, label="")
    plot!([0, 0, 1], [1, 0, 0], color=:black, label="")
    θ0 = 0.5
    x, y = cos(θ0), sin(θ0)
    plot!([0, x], [y, y], color=:black, label="")
    plot!([0, x], [0, y], color=:black, linestyle=:dash, label="")
    plot!([x, x], [0, y], color=:black, linestyle=:dash, label="")
    annotate!.([0, x, 0, 1, 0], [0, 0, y, 0, 1],
               text.(["O", "X", "Y ", "1", "1 "], 8, :right, :top))
    annotate!.([x, 0.4, 0.2, 0.6], [y, 0.7, 0.25, 0.2], text.([" P", "S1", "S2", "S3"], 8, :left))
    display(plt)
end

drawcake(); savefig("fig.png")

S1, S2, S3 の関係から,f(θ) = sin(θ) * cos(θ) + θ - π / 6 = 0 を満たす θ を求めればよい。
二分法により θ を求める。 

using Roots
func(θ) = sin(θ)*cos(θ) + θ - π/6
θ0 = find_zero(func, (0, π/2))
println("θ0 = $θ0,  func(θ0) = $(func(θ0))") # θ0 = 0.26813348949444527,  func(θ0) = 0.0
Y の y 座標値は sin(θ0)
println("sin(θ0) = $(sin(θ0))") # sin(θ0) = 0.26493208460277684

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia の小ネタ--023 match 文

2021年05月04日 | ブログラミング

Python 3.10 で導入される match 文 [構造的パターンマッチングの機能]
すげー!!と絶賛するむきもあるようだが

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the Internet"

Julia には既に実装済み。
Julia のほうが,短くて,わかりやすい。

using Match

function httperror(status)
    @match status begin
        400 => "Bad request"
        404 => "Not found"
        418 => "I'm a teapot"
        _ => "Something's wrong with the Internet"
    end
end

httperror(400) # "Bad request"
httperror(404) # "Not found"
httperror(418) # "I'm a teapot"
httperror(999) # "Something's wrong with the Internet"

色々使い方はあるけど。

def where_am_i(point):
    match point:
        case (0, 0):
            return "Origin"
        case (0, y):
            return f" Y={y}"
        case (x, 0):
            return f" X={x}"
        case (x, y):
            return f" X={x}, Y={y}"
        case _:
            raise ValueError("Not a point")

やはり,Julia の方が可読性が高いと思う。(Not a point はどういうとき?)

function whereami(point)
    @match point begin
        (0, 0) => "Origin"
        (0, y) => " Y=$y"
        (x, 0) => " X=$x"
        (x, y) => " X=$x, Y=$y"
        _      => "Not a point"
    end
end

whereami((0, 0)) # "Origin"
whereami((0, 4)) # " Y=4"
whereami((5, 0)) # " X=5"
whereami((8, 3)) # " X=8, Y=3"

セイウチ演算子のときもそうだったけど,他を知らずに自画自賛するのも程があるよね。

なお,R の switch  文は,最悪。。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia に翻訳--217 quade.test()

2021年05月04日 | ブログラミング

#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

R の quade.test() の移植

ファイル名: quedetest.jl  関数名: quedetest

翻訳するときに書いたメモ

行列で与えられるときのみをインストールする。

==========#

using StatsBase, SpecialFunctions, Rmath

function quadetest(y)
  ndims(y) != 2 && error("matirx is expected")
  b, k = size(y)
  groups = vcat([repeat([i], k) for i = 1:b]...)
  blocks = repeat(1:k, b)
  r = transpose(reshape(vcat([tiedrank(y[i, :]) for i = 1:b]...), k, :))
  q = tiedrank(maximum(y, dims=2) .- minimum(y, dims=2))
  s = q .* (r .- (k + 1) / 2)
  A = sum(s .^ 2)
  B = sum(sum(s, dims=1) .^ 2) / b
  if A == B
    statistic = NaN
    parameter = [NaN, NaN]
    pvalue = gamma(k + 1) ^ (1 - b)
  else
    statistic = (b - 1) * B / (A - B)
    df1, df2 = k - 1, (b - 1) * (k - 1)
    pvalue = pf(statistic, df1, df2, false)
  end
  println("Quade F = $statistic,  df1 = $df1,  df2 = $df2,  p value = $pvalue")
  Dict(:statistic => statistic, :df1 => df1, :df2 => df2,
       :pvalue => pvalue, :method => "Quade test")
end


y = [ 5  4  7 10 12
      1  3  1  0  2
     16 12 22 22 35
      5  4  3  5  4
     10  9  7 13 10
     19 18 28 37 58
     10  7  6  8  7 ];

quadetest(y);
# Quade F = 3.8292515841753727,  df1 = 4,  df2 = 24,  p value = 0.015189020073274592

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia に翻訳--216 poisson.test(),ポアソン検定

2021年05月04日 | ブログラミング

#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

R の poisson.test() を移植

ファイル名: poissontest.jl
関数名:   exactpoissontest()
         comparisonofpoissonrates()
         binomialtest()

翻訳するときに書いたメモ

Exact Poisson test と Comparison of Poisson rates に分割した。
後者で用いる binom.test() も移植した。

==========#

using SpecialFunctions, Rmath

function exactpoissontest(x, timebase = 1; r = 1, conflevel = 0.95,
                          alternative = "twosided") # or "less" or "greater"

    plower(x, α) = x == 0 ? 0 : qgamma(α, x)

    pupper(x, α) = qgamma(1 - α, x + 1)

    m = r * timebase
    if alternative == "less"
        pvalue = ppois(x, m)
        confint = [0, pupper(x, 1 - conflevel)]
        word = "less than"
    elseif alternative == "greater"
        pvalue = ppois(x - 1, m, false)
        confint = [plower(x, 1 - conflevel), Inf]
        word = "greater than"
    else # alternative == ""twosided"
        if m == 0
            (x == 0) + 0
        else
            relErr = 1.0000001dpois(x, r * timebase)
            if x == m
                1
            elseif x < m
                N = ceiling(2m - x)
                while dpois(N, m) > d
                    N *= 2
                end
                i = seqint(from = ceiling(m), to = N)
                y = sum(dpois(i, m) <= relErr)
                pvalue = ppois(x, m) + ppois(N - y, m, false)
            else
                i = 0:floor(Int, m)
                y = sum(dpois.(i, m) .<= relErr)
                pvalue = ppois(y - 1, m) + ppois(x - 1, m, false)
            end
        end
        α = (1 - conflevel) / 2
        confint = [plower(x, α), pupper(x, α)]
        word = "not equal to"
    end
    confint /= timebase
    estimatedeventrate = x / timebase
    method = "Exact Poisson test"
    println(method)
    println("number of events = $x,  time base = $timebase,  ",
            "p value = $pvalue")
    println("alternative hypothesis: true event rate is $word 1")
    println("$(100conflevel)% conficence interval = ",
            "[$(confint[1]), $(confint[2])]")
    println("sample estimates: event rate = $estimatedeventrate")
    Dict(:numberofevents => x, :timebase => timebase, :pvalue => pvalue,
         :confint => confint, :estimatedeventrate => estimatedeventrate,
         :nullvalue => r, :alternative => alternative, :method => method)
end

function comparisonofpoissonrates(x::Vector{Int}, n::Vector{Int};
                                  r = 1, conflevel = 0.95,
                                  alternative = "twosided") # or "less" or "greater"
    k = length(x)
    k > 2 && error("the case k > 2 is unimplemented")
    length(n) != k && error("'x' and 'n' have incompatible length")
    results = binomialtest(x[1], sum(x), r * n[1] / (r * n[1] + n[2]); alternative, conflevel)
    pvalue = results[:pvalue]
    count1 = results[:x]
    expectedcount1 = sum(x) * r * n[1] / (n[1] + r*n[2]) # .* [1, r])
    rateratio = (x[1] / n[1]) / (x[2] / n[2])
    pp = [results[:lcl], results[:ucl]]
    confint = pp ./ (1 .- pp) * n[2] / n[1]
    method = "Comparison of Poisson rates"
    println(method)
    println("count1 = $count1,  expected count1 = $expectedcount1,  ",
            "p value = $pvalue")
    println("alternative hypothesis: true rate ratio is $(results[:word]) 1")
    println("$(100conflevel)% conficence interval = [$(confint[1]), $(confint[2])]")
    println("sample estimates: rate ratio = $rateratio")
    Dict(:count1 => count1, :expectedcount1 => expectedcount1,
         :rateratio => rateratio, :confint => confint, :method => method )
end

function binomialtest(x, n, p = 0.5; conflevel = 0.95,
                      alternative = "twosided") # "less", "greater"
    plower(x, α) = x == 0 ? 0 : qbeta(α, x, n - x + 1)
    pupper(x, α) = x == n ? 1 : qbeta(1 - α, x + 1, n - x)
    if alternative == "less"
        pvalue, lcl, ucl = pbinom(x, n, p), 0, pupper(x, 1 - conflevel)
        word = "less than"
    elseif alternative == "greater"
        pvalue, lcl, ucl = pbinom(x - 1, n, p, false), plower(x, 1 - conflevel), 1
        word = "greater than"
    else
        if p == 0
            pvalue = float(x == 0)
        elseif p == 1
            pvalue = float(x == n)
        else
            relerr = 1.0000001dbinom(x, n, p)
            m = n * p
            if x == m
                pvalue = 1
            elseif x < m
                y = sum(dbinom.(ceil(Int, m):n, n, p) .<= relerr)
                pvalue = pbinom(x, n, p) + pbinom(n - y, n, p, false)
            else
                y = sum(dbinom.(0:floor(Int, m), n, p) .<= relerr)
                pvalue = pbinom(y - 1, n, p) + pbinom(x - 1, n, p, false)
            end
        end
        α = (1 - conflevel) / 2
        lcl, ucl = plower(x, α), pupper(x, α)
        word = "not equal to"
    end
    Dict(:x => x, :n => n, :pvalue => pvalue, :lcl => lcl, :ucl => ucl, :nullvalue => p, :word => word)
end

x = 137
timebase = 24.19893
exactpoissontest(x, timebase);
# Exact Poisson test
# number of events = 137,  time base = 24.19893,  p value = 2.845227264114483e-56
# alternative hypothesis: true event rate is not equal to 1
# 95.0% conficence interval = [4.753124804848751, 6.692709334176073]
# sample estimates: event rate = 5.661407343217241

exactpoissontest(x, timebase, alternative="less");
# Exact Poisson test
# number of events = 137,  time base = 24.19893,  p value = 1.0
# alternative hypothesis: true event rate is less than 1
# 95.0% conficence interval = [0.0, 6.524017866487051]
# sample estimates: event rate = 5.661407343217241

exactpoissontest(x, timebase, alternative="greater");
# Exact Poisson test
# number of events = 137,  time base = 24.19893,  p value = 2.845227264114483e-56
# alternative hypothesis: true event rate is greater than 1
# 95.0% conficence interval = [4.889990033069891, Inf]
# sample estimates: event rate = 5.661407343217241

x = [11, 21];
timebase = [800, 3011];
comparisonofpoissonrates(x, timebase);
# Comparison of Poisson rates
# count1 = 11,  expected count1 = 6.717397008659145,  p value = 0.07966863303332952
# alternative hypothesis: true rate ratio is not equal to 1
# 95.0% conficence interval = [0.8584264033916392, 4.277265943654071]
# sample estimates: rate ratio = 1.9714880952380953

comparisonofpoissonrates(x, timebase, alternative="less");
# Comparison of Poisson rates
# count1 = 11,  expected count1 = 6.717397008659145,  p value = 0.975931823227312
# alternative hypothesis: true rate ratio is less than 1
# 95.0% conficence interval = [0.0, 3.827386407850879]
# sample estimates: rate ratio = 1.9714880952380953

comparisonofpoissonrates(x, timebase, alternative="greater");
# Comparison of Poisson rates
# count1 = 11,  expected count1 = 6.717397008659145,  p value = 0.05600865978769969
# alternative hypothesis: true rate ratio is greater than 1
# 95.0% conficence interval = [0.9775843474967454, Inf]
# sample estimates: rate ratio = 1.9714880952380953

comparisonofpoissonrates(x, [1, 1], alternative="greater");
# Comparison of Poisson rates
# count1 = 11,  expected count1 = 16.0,  p value = 0.9749487701337785
# alternative hypothesis: true rate ratio is greater than 1
# 95.0% conficence interval = [0.25973679109843784, Inf]
# sample estimates: rate ratio = 0.5238095238095238

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Julia に翻訳--215 非線形回帰

2021年05月03日 | ブログラミング
#==========
Julia の修行をするときに,いろいろなプログラムを書き換えるのは有効な方法だ。
以下のプログラムを Julia に翻訳してみる。

非線形曲線回帰
http://aoki2.si.gunma-u.ac.jp/Python/nonlinear_fitting.pdf

ファイル名: nonlinearfitting.jl  関数名: nonlinearfitting

翻訳するときに書いたメモ

==========#

using LinearAlgebra, NamedArrays, Plots

function nonlinearfitting(x, y; inival=[], model="Asymptotic", method="Marquardt", # or "Simplex"
    maxit=1000, epsilon=1e-7)
    #
    residual(p, x, y) = sum((y .- func(p, x)) .^ 2)
    #
    function marquardt(x, y, inival; maxit, epsilon)
        #
        function solinvfit(p0, x, y)
            n = length(x)
            ip = length(p0)
            ff = zeros(ip)
            fj = zeros(n, ip + 1)
            d = zeros(n + ip)
            delta = zeros(ip)
            p = p0
            resid = residual(p, x, y)
            fval = func(p, x, fj=fj)
            fj[:, ip+1] = y - fval
            ff = fj[:, 1:ip]' * fj[:, ip+1]
            fj = vcat(fj, diagm(-1 => fill(sqrt(cterm), ip))[2:end, :])
            n += ip
            sl = 1e-30
            for j = 1:ip
                d[j:end] = fj[j:end, j]
                h = sum(d[j:end] .^ 2)
                if h < sl
                    g = 0
                else
                    g = sqrt(h)
                    f = fj[j, j]
                    f >= 0 && (g = -g)
                    d[j] = f - g
                    h -= f * g
                    for k = j + 1:ip + 1 # k = j+1
                        s = sum(d[j:end] .* fj[j:end, k]) / h
                        fj[j:end, k] -= d[j:end] .* s
                    end
                end
                fj[j, j] = g
            end
            for i = ip:-1:1 # i = 1
                tot = fj[i, ip + 1] - sum(delta[i + 1:end] .* fj[i, i + 1:ip])
                delta[i] = fj[i, i] == 0 ? 0 : tot / fj[i, i]
            end
            delta, ff, resid
        end
        #
        errset = false
        flag = false
        diverg = 0
        n = length(x)
        ip = ip0 = length(inival)
        p0 = inival
        p = zeros(ip)
        p1 = zeros(ip)
        cterm = 100
        for loop = 1:maxit
            delta, ff, res0 = solinvfit(p0, x, y)
            p1 = p0 + delta
            flag = any(abs.(delta ./ p1) .> epsilon)
            check = -sum((ff .+ cterm .* delta) .* delta)
            p = p1
            res1 = residual(p1, x, y)
            res1 == 0 && break
            rchange = res1 - res0
            if rchange <= 0
                diverg = 0
                errset = false
                check = rchange / check
                if -rchange / res1 < epsilon && flag == false
                    return p
                end
                if check > 0.75
                    cterm *= 0.5
                elseif check < 0.25
                    cterm *= 5
                end
                p0 = p1
            else
                diverg += 1
                errset = true
                if diverg > 10
                    flag && error("not converged")
                    p0 = p1
                else
                    cterm *= 5
                end
            end
        end
        error("not converged")
    end
    #
    function simplex(x, y, inival; maxit, epsilon)
        LO = 0.8
        HI = 1.2
        ip = length(inival)
        ip1 = ip + 1
        ip2 = ip + 2
        ip3 = ip + 3
        pa = float.(reshape(repeat(inival, ip3), ip, :))
        for i = 1:ip
            pa[i, i] = inival[i] * rand(1)[1] * (HI - LO) + LO
        end
        res = vcat([residual(pa[:, i], x, y) for i = 1:ip1], 0, 0)
        for loops = 1:maxit
            res0 = res[1:ip1]
            mx = argmax(res0)
            mi = argmin(res0)
            s = sum(pa[:, 1:ip1], dims = 2)
            if res[mx] < epsilon || res[mi] < epsilon ||
               (res[mx] - res[mi]) / res[mi] < epsilon
               return pa[:, mi]
            end
            i = ip2
            pa[:, ip2] = (2 * s - ip2 * pa[:, mx]) / ip
            res[ip2] = residual(pa[:, ip2], x, y)
            if res[ip2] < res[mi]
                pa[:, ip3] = (3 * s - (2 * ip1 + 1) * pa[:, mx]) / ip
                res[ip3] = residual(pa[:, ip3], x, y)
                res[ip3] <= res[ip2] && (i = ip3)
            elseif res[ip2] > res[mx]
                pa[:, ip3] = s / ip1
                res[ip3] = residual(pa[:, ip3], x, y)
                if res[ip3] >= res[mx]
                    for i = 1:ip1
                        if i != mi
                            pa[:, i] = (pa[:, i] + pa[:, mi]) * 0.5
                            res[i] = residual(pa[:, i], x, y)
                        end
                    end
                    i = 0
                else
                    i = ip3
                end
            end
            if i > 0
                pa[:, mx] = pa[:, i]
                res[mx] = res[i]
            end
        end
        error("not converged!")
    end
    #
    if  model == "Asymptotic"
        func = Asymptotic; ip = 3
        def = "\$y=ab^x+c\$"
    elseif model == "Power2"
        func = Power2; ip = 3
        def = "\$y=ax^b+c\$"
    elseif model == "Exponential1"
        func = Exponential1; ip = 2
        def = "\$y=ab^x\$"
    elseif model == "Power1"
        func = Power1; ip = 2
        def = "\$y=ax^b\$"
    elseif model == "Exponential2"
        func = Exponential2; ip = 2
        def = "\$y=a(1-\\exp(-bx))\$"
    elseif model == "Logistic1"
        func = Logistic1; ip = 3
        def = "\$y=a/(1+b\\exp(-cx))\$"
    elseif model == "Logistic2"
        func = Logistic2; ip = 4
        def = "\$y=a/(1+b\\exp(-cx))+d\$"
    elseif model == "Logistic3"
        func = Logistic3; ip = 3
        def = "\$y=1/(1+a\\exp(-bx))\$"
    elseif model == "Logistic4"
        func = Logistic4; ip = 4
        def = "\$y=a+\\frac{b-a}{1+(c/x)^d}\$"
    elseif model == "Gomperts"
        func = Gomperts; ip = 3
        def = "\$y=ab^\\exp(-cx)\$"
    elseif model == "Weibull"
        func = Weibull; ip = 2
        def = "\$y=1-\\exp(-x^a/b)\$"
    elseif model == "Sin"
        func = Sin; ip = 5
        def = "\$y=a\\sin(bx+c)+dx+e\$"
    elseif model == "Hyperbola1"
        func = Hyperbola1; ip = 3
        def = "\$y=a+\\frac{b}{x+c}\$"
    elseif model == "Hyperbola2"
        func = Hyperbola2; ip = 4
        def = "\$y=\\frac{a}{bx^2+cx+d}\$"
    elseif callable(model)
        func = model
        model = "user defined function"
        def = "\$y\$"
    else
        error("Not yet inplemented")
    end
    length(x) != length(y) && error("lengths of x && y are not equal")
    if model == "user defined function"
        ip = length(inival)
    elseif length(inival) == 0
        inival = fill(1, ip)
    elseif length(inival) != ip
        error("number of initial value must be $ip")
    end
    if method == "Marquardt"
        p = marquardt(x, y, inival; maxit, epsilon)
    else
        p = simplex(x, y, inival; maxit, epsilon)
    end
    predicted = func(p, x)
    resid = sum((predicted .- y) .^ 2)
    println("$model funciton by $(titlecase(method)) method")
    println("estimated parameters $def\n", NamedArray(hcat(Char.(96 .+ (1:ip)), p), (1:ip, ["parameter", "estimated"])))
    println("residual sum of squares $resid")
    println(NamedArray(hcat(x, y, predicted, y .- predicted), (1:length(x), ["x", "y", "pred.", "resid."])))
    Dict(:p => p, :predicted => predicted, :resid => resid, :x => x, :y => y, :model => model, :method => method, :func => func, :def => def)
end

function plotfittedresult(obj)
    #pyplot()
    plt = scatter(obj[:x], obj[:y], grid=false, tick_direction=:out,
        xlabel="\$x\$", ylabel=obj[:def], title=obj[:model], label="")
    minx, maxx = extrema(obj[:x])
    x2 = range(minx, maxx, length=2001)
    y2 = obj[:func](obj[:p], x2)
    plot!(x2, y2, label="")
end

function Asymptotic(p, x; fj=[])
    if length(fj) != 0
        fj[:, 1] = p[2] .^ x
        fj[:, 2] = p[1] .* x .* p[2] .^ (x .- 1)
        fj[:, 3] .= 1
    end
    p[1] .* p[2] .^ x .+ p[3]
end

x = (0:10) / 2 # length(x)
y = [52, 53, 56, 60, 68, 81, 104, 144, 212, 331, 536];
inival=[1,1,1];
obj = nonlinearfitting(x, y, model="Asymptotic")
#=====
Asymptotic funciton by Marquardt method
estimated parameters $y=ab^x+c$
3×2 Named Matrix{Any}
A ╲ B │ parameter  estimated
──────┼─────────────────────
1     │       'a'    2.02823
2     │       'b'    2.99196
3     │       'c'    49.7351
residual sum of squares 0.4215805168503011
11×4 Named Matrix{Float64}
A ╲ B │          x           y       pred.      resid.
──────┼───────────────────────────────────────────────
1     │        0.0        52.0     51.7633    0.236676
2     │        0.5        53.0     53.2434   -0.243384
3     │        1.0        56.0     55.8035    0.196514
4     │        1.5        60.0     60.2318   -0.231767
5     │        2.0        68.0     67.8915    0.108511
6     │        2.5        81.0     81.1407   -0.140729
7     │        3.0       104.0     104.058  -0.0583134
8     │        3.5       144.0       143.7    0.300491
9     │        4.0       212.0     212.268   -0.268009
10    │        4.5       331.0     330.873    0.127114
11    │        5.0       536.0     536.027  -0.0271035
=====#

plotfittedresult(obj) # savefig("fig1.png")
その他の関数への当てはめ例
function Power2(p, x; fj=[])
    temp1 = x .^ p[2]
    if length(fj) != 0
        fj[:, 1] = temp1
        fj[:, 2] = p[1] .* log.(x) .* temp1
        fj[:, 3] .= 1
    end
    p[1] .* temp1 .+ p[3]
end

x = float.(1:10);
y = [7, 21, 59, 133, 255, 436, 691, 1029, 1463, 2005];
obj = nonlinearfitting(x, y, model = "Power2")
plotfittedresult(obj)

function Exponential1(p, x; fj=[])
    if length(fj) != 0
        fj[:, 1] = p[2] .^ x
        fj[:, 2] = p[1] .* x .* p[2] .^ (x .- 1)
    end
    p[1] .* p[2] .^ x
end

x = 1:10;
y = [6, 18, 54, 162, 486, 1458, 4374, 13102, 39366, 118098];
obj = nonlinearfitting(x, y, model="Exponential1")
plotfittedresult(obj)

function Power1(p, x; fj=[])
    temp = x .^ p[2]
    if length(fj) != 0
        fj[:, 1] = temp
        fj[:, 2] = p[1] .* temp .* log.(x)
    end
    p[1] .* temp
end

 x = 1:10;
 y = [2, 16, 54, 128, 250, 432, 680, 1024, 1458, 2000];
 obj = nonlinearfitting(x, y, model="Power1")
 plotfittedresult(obj)

function Exponential2(p, x; fj=[])
    temp = exp.(-x .* p[2])
    if length(fj) != 0
        fj[:, 1] = 1 .- temp
        fj[:, 2] = p[1] .* temp .* x
    end
    p[1] .* (1 .- temp)
end

x = 1:10;
y = [0.518, 0.902, 1.187, 1.398, 1.530, 1.669, 1.755, 1.819, 1.866, 1.900];
obj = nonlinearfitting(x, y, model="Exponential2")
plotfittedresult(obj)

function Logistic1(p, x; fj=[])
    if length(fj) != 0
        temp1 = exp.(p[3] .* x)
        temp2 = exp.(p[3] .* x .* 2)
        temp3 = 1 ./ (temp2 .+ 2p[2] .* temp1 .+ p[2] ^ 2)
        fj[:, 1] = temp1 ./ (temp1 .+ p[2])
        fj[:, 2] = -p[1] .* temp1 .* temp3
        fj[:, 3] = p[1] * p[2] .* x .* temp1 .* temp3
    end
    p[1] ./ (1 .+ p[2] .* exp.(-p[3] .* x))
end

x = 1:10;
y = [1.538, 1.573, 1.606, 1.636, 1.675, 1.692, 1.717, 1.741, 1.762, 1.783];
obj = nonlinearfitting(x, y, model="Logistic1")
plotfittedresult(obj)

function Logistic2(p, x; fj=[])
    if length(fj) != 0
        temp1 = exp.(-p[3] .* x)
        temp2 = 1 .+ p[2] * temp1
        temp3 = 1 ./ temp2 .^ 2
        fj[:, 1] = 1 ./ temp2
        fj[:, 2] = -p[1] .* temp1 .* temp3
        fj[:, 3] = p[1] * p[2] .* temp1 .* x .* temp3
        fj[:, 4] .= 1
    end
    p[1] ./ (1 .+ p[2] * exp.(-p[3] .* x)) .+ p[4]
end

x = 0:10;
y = [2.538, 2.573, 2.606, 2.636, 2.655, 2.692, 2.717, 2.741, 2.762, 2.783, 2.801];
obj = nonlinearfitting(x, y, model="Logistic2")
plotfittedresult(obj)

function Logistic3(p, x; fj=[])
    temp1 = 1 ./ (1 .+ p[1] .* exp.(-p[2] .* x))
    if length(fj) != 0
        temp2 = exp.(-p[2] .* x) .* temp1 .^ 2
        fj[:, 1] = -temp2
        fj[:, 2] = p[1] .* x .* temp2
    end
    temp1
end

x = 0:10;
y = [0.333, 0.403, 0.477, 0.552, 0.604, 0.691, 0.752, 0.803, 0.846, 0.882, 0.909];
obj = nonlinearfitting(x, y, model="Logistic3")
plotfittedresult(obj)

function Logistic4(p, x; fj=[])
    temp1 = p[3] ./ x
    temp = 1 .+ temp1 .^ p[4]
    temp2 = temp .* temp
    if length(fj) != 0
        fj[:, 1] = 1 .- 1 ./ temp
        fj[:, 2] = 1 ./ temp
        fj[:, 3] = (p[1] - p[2]) * p[4] .* temp1 .^ (p[4] - 1) ./ temp2 ./ x
        fj[:, 4] = (p[1] - p[2]) .* temp1 .^ p[4] .* log.(temp1) ./ temp2
    end
    p[1] .+ (p[2] - p[1]) ./ temp
end

x = 1:10;
y = [0.976, 0.816, 0.733, 0.679, 0.631, 0.612, 0.59, 0.571, 0.555, 0.542];
obj = nonlinearfitting(x, y, model="Logistic4")
plotfittedresult(obj)

function Gomperts(p, x; fj=[])
    if length(fj) != 0
        temp1 = exp.(p[3] .* x)
        temp2 = p[2] .^ (1 ./ temp1)
        fj[:, 1] = temp2
        fj[:, 2] = p[1] .* temp2 ./ (p[2] .* temp1)
        fj[:, 3] = -log(p[2]) * p[1] .* x .* temp2 ./ temp1
    end
    p[1] .* p[2] .^ exp.(-p[3] .* x)
end

x = 1:10
y = [0.964, 1.284, 1.529, 1.699, 1.812, 1.884, 1.929, 1.956, 1.973, 1.984];
obj = nonlinearfitting(x, y, model="Gomperts")
plotfittedresult(obj)

function Weibull(p, x; fj=[])
    temp2 = x .^ p[2]
    temp = exp.(-temp2 ./ p[1])
    if length(fj) != 0
        fj[:, 1] = -temp .* temp2 ./ p[1] ^ 2
        fj[:, 2] = temp .* temp2 .* log.(x) ./ p[1]
    end
    1 .- temp
end

x = 1:10;
y = [0.283, 0.418, 0.513, 0.565, 0.642, 0.689, 0.728, 0.76, 0.788, 0.812];
obj = nonlinearfitting(x, y, model="Weibull")
plotfittedresult(obj)

function Sin(p, x; fj=[])
    temp = sin.(p[2] .* x .+ p[3])
    if length(fj) != 0
        temp2 = cos.(p[2] .* x .+ p[3])
        fj[:, 1] = temp
        fj[:, 2] = p[1] .* x .* temp2
        fj[:, 3] = p[1] .* temp2
        fj[:, 4] = x
        fj[:, 5] .= 1
    end
    p[1] .* temp .+ p[4] .* x .+ p[5]
end

x = 1:30;
y = [5.896, 6.539, 5.847, 4.427, 3.23, 3.1, 4.382, 6.754, 9.382,
    11.314, 11.922, 11.203, 9.777, 8.597, 8.5, 9.814, 12.203, 14.826,
    16.731, 17.305, 16.559, 15.127, 13.965, 13.901, 15.247, 17.653,
    20.269, 22.147, 22.686, 21.915];
obj = nonlinearfitting(x, y, model="Sin")
plotfittedresult(obj)

function Hyperbola1(p, x; fj=[])
    temp = x .+ p[3]
    if length(fj) != 0
        fj[:, 1] .= 1
        fj[:, 2] = 1 ./ temp
        fj[:, 3] = -p[2] ./ temp .^ 2
    end
    p[1] .+ p[2] ./ temp
end

x = 1:10;
y = [23.2, 16.5, 11.571, 9.667, 8.455, 7.615, 7, 6.529, 6.158, 5.857];
obj = nonlinearfitting(x, y, model="Hyperbola1")
plotfittedresult(obj)

function Hyperbola2(p, x; fj=[])
    temp = p[2] .* x .^ 2 .+ p[3] .* x .+ p[4]
    if length(fj) != 0
        fj[:, 1] = 1 ./ temp
        temp2 = -p[1] ./ temp .^ 2
        fj[:, 2] = temp2 .* x .^ 2
        fj[:, 3] = temp2 .* x
        fj[:, 4] = temp2
    end
    p[1] ./ temp
end

x = 1:10;
y = [3.922, 1.282, 0.623, 0.396, 0.241, 0.17, 0.127, 0.098, 0.078, 0.063];
obj = nonlinearfitting(x, y, model="Hyperbola2")
plotfittedresult(obj)
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村