某所で,Julia ではヒートマップを簡単に描くことができないとこぼしている人がいた。その人は行と列の並べ替えすらしないで,もっと簡単に描けないのかと言っている。
ヒートマップって,データのビジュアライゼーションという点ではそんなに優れているものとも思わないが,せめて適切に行と列を並べないと何の意味もないグラフができてしまうだけだ。
julia> using PyPlot, Plots, DataFrames, CSV
julia> pyplot()
julia> using Random
julia> Random.seed!(123)
julia> df = DataFrame(Location = ["NY", "SF", "NY", "NY", "SF", "SF", "TX", "TX", "TX", "DC", "DC", "DC"],
Class = ["M","M","H","L","L","H", "H","L","M","M","H","L"],
Score = rand(12))
12×3 DataFrame
Row │ Location Class Score
│ String String Float64
─────┼─────────────────────────────
1 │ NY M 0.768448
2 │ SF M 0.940515
3 │ NY H 0.673959
4 │ NY L 0.395453
5 │ SF L 0.313244
6 │ SF H 0.662555
7 │ TX H 0.586022
8 │ TX L 0.0521332
9 │ TX M 0.26864
10 │ DC M 0.108871
11 │ DC H 0.163666
12 │ DC L 0.473017
julia> CSV.write("data.csv", df)
縦軸にLocation, 横軸にClassを持つピボットテーブルに変形する
julia> pivot = DataFrames.unstack(data, :Location, :Class, :Score)
4×4 DataFrame
Row │ Location M H L
│ String Float64? Float64? Float64?
─────┼─────────────────────────────────────────
1 │ NY 0.768448 0.673959 0.395453
2 │ SF 0.940515 0.662555 0.313244
3 │ TX 0.26864 0.586022 0.0521332
4 │ DC 0.108871 0.163666 0.473017
ここまでだと,行も列も乱雑に並んでいるだけなので,適切に並べ替える。データフレームの操作は色々方法があるが,Query を使う例を挙げておく。
julia> using Query
julia> pivot2 = pivot |>
@select(1, 4, 2, 3) |>
@orderby(_.Location) |> DataFrame
4×4 DataFrame
Row │ Location L M H
│ String Float64? Float64? Float64?
─────┼─────────────────────────────────────────
1 │ DC 0.473017 0.108871 0.163666
2 │ NY 0.395453 0.768448 0.673959
3 │ SF 0.313244 0.940515 0.662555
4 │ TX 0.0521332 0.26864 0.586022
julia> x = names(pivot2)[2:end]
3-element Array{String,1}:
"L"
"M"
"H"
julia> y = pivot2.Location
4-element Array{String,1}:
"DC"
"NY"
"SF"
"TX"
julia> heatmap(x, y, Matrix(pivot2[:, 2:4]))
freqtable を使うやり方では行と列は辞書順になるが,任意の行と列の並べ替えはたいへんなので,そのまま描画。
julia> using DataFrames, FreqTables, NamedArrays
julia> using Plots
julia> pivot3 = freqtable(data, :Class, :Location, weights=-df.Score)
3×4 Named Array{Float64,2}
Class ╲ Location │ DC NY SF TX
─────────────────┼───────────────────────────────────────────
H │ 0.163666 0.673959 0.662555 0.586022
L │ 0.473017 0.395453 0.313244 0.0521332
M │ 0.108871 0.768448 0.940515 0.26864
julia> heatmap(pivot3)
行と列の並べ替えを簡単にできるように,意味のある並べ替えが自動的にできるように,色使いも選べるように,ブロック中に数値を描けるようにとか,要望は多々ある。
ないものは,作る,しか,ないの,かな?
いやいや,R がもうあるんだから,それでいいだろう。R の heatmap を使うべし。
julia> rownames, colnames = names(pivot3)
julia> using RCall
julia> R"""
mat = $pivot3
colnames(mat) = $colnames
rownames(mat) = $rownames
heatmap(mat)
"""