0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

jupyter上で書いたコードの振る舞いをテストする時の流れ

0
Posted at

jupyter上でユニットテスト

何らかの実現したいことがあって、それをするためにコードを書くときに、必ずテストケースを書いて、本当に正しい振る舞いかどうか確かめる必要性が出てくる。これをjupyter上で行う際のチップスをまとめた。

実現したいことの例

今回は、冗長なkeysとそのkeysに対応するパラメータの位置の情報が与えられており、同じkeysに対応するパラメータの値は、同じにするという問題を考える。
例えば、以下のような場合を考える。

keys = [(1,2), (1,3), (1,1,2), (1,1,2), (1,2,1), (1,2,1), (1,2), (1,3)]
paraminfo = [((1,2), 1), ((1,3), 2), ((1,1,2), 3), ((1,1,2),4), ((1,2,1), 5), ((1,2,1), 6), ((1,2), 7), ((1,3), 8)] # (keys, パラメータの位置)が配列の要素
thetas = [-1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0]

期待する結果は、[-1.0, -2.0, -3.0, -3.0, -5.0, -5.0, -1.0, -2.0] である。

コードを書く。

とりあえずコードを書いてみる。今回は辞書を使って、実装する。

keys = ["a", "b", "c", "c", "d", "d", "a", "b"]
paraminfo = [(("a"), 1), (("b"), 2), (("c"), 3), (("c"),4), (("d"), 5), (("d"), 6), (("a"), 7), (("b"), 8)]
thetas = [-1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0]
d = Dict()
θunique = []
for (i,k) in enumerate(keys)
    if haskey(d, k) # ここで冗長なkeysは落としている。
        continue
    end
    @show (i,k)
    d[k] = i
    push!(θunique, thetas[i]) 
end
d

冗長性を省いた辞書を定義した。こちらの情報をもとに

θ = zeros(Float64, length(thetas))
for (ik, k) in enumerate(keys)
    #println(ik, k)
    i = d[k] #dは上で定義した辞書
    θ[ik] = thetas[i] 
end
θ

テスト+関数化する

最初に関数を書いて、それによる出力結果と期待される結果が一致するというテストコードを最初に書く。

function update_param(keys, paraminfo, thetas)
    *****
end

output = [-1.0, -2.0, -3.0, -3.0, -5.0, -5.0, -1.0, -2.0]
@assert update_param(keys, paraminfo, thetas) == output 

次に上で書いたコードを関数化する。こうすることで、関数の振る舞いが正しいか正しくないかをセルを実行する度にチェックできる。

function update_param(keys, paraminfo, thetas)
    d = Dict()
    θunique = []
    for (i,k) in enumerate(keys)
        if haskey(d, k) # floatが入るとややこしい。
            continue
        end
        #@show (i,k)
        d[k] = i
        push!(θunique, thetas[i]) 
    end

    θ = zeros(Float64, length(thetas))
    for (ik, k) in enumerate(keys)
        #println(ik, k)
        i = d[k]
        θ[ik] = thetas[i] # d は辞書ではなく、配列にする。
    end
    return θ
end

# このセルだけを実行すると、関数だけでなくテストも実行してくれるので楽。
output = [-1.0, -2.0, -3.0, -3.0, -5.0, -5.0, -1.0, -2.0]
@assert update_param(keys, paraminfo, thetas) == output 

リファクタリングによっていい感じにする。

さらに関数化して、良い感じにする。こちらも同様に、期待される結果と関数の結果が一致するというテストコードを書いておく。

# make_compact_param_set
function make_compact_paraminfo(keys)
    d = Dict()
    #θunique = []
    for (i,k) in enumerate(keys)
        if haskey(d, k) # floatが入るとややこしい。
            continue
        end
        #@show (i,k)
        d[k] = i
    end
    return d
    #push!(θunique, thetas[i]) 
end

@assert make_compact_paraminfo(keys) == Dict{Any, Any}(
(1, 2, 1) => 5,
(1, 2)    => 1,
(1, 3)    => 2,
(1, 1, 2) => 3
)
## パラメータの情報も一つのセルの中に含ませておくと、自己完結的で良いかも。

keys = [(1,2), (1,3), (1,1,2), (1,1,2), (1,2,1), (1,2,1), (1,2), (1,3)]
paraminfo = [((1,2), 1), ((1,3), 2), ((1,1,2), 3), ((1,1,2),4), ((1,2,1), 5), ((1,2,1), 6), ((1,2), 7), ((1,3), 8)]
thetas = [-1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0, -8.0]

function update_param(keys, paraminfo, thetas)
    d = make_compact_paraminfo(keys)
    
    θ = zeros(Float64, length(thetas))
    for (ik, k) in enumerate(keys)
        #println(ik, k)
        i = d[k]
        θ[ik] = thetas[i] # d は辞書ではなく、配列にする。
    end
    return θ
end

# このセルだけを実行すると、関数だけでなくテストも実行してくれるので楽。
output = [-1.0, -2.0, -3.0, -3.0, -5.0, -5.0, -1.0, -2.0]
@assert update_param(keys, paraminfo, thetas) == output 

まとめ

jupyterで書いたコードが期待される振る舞いかどうかテストするときの流れをまとめてみた。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?