juliaで前処理大全 7.展開

(src=https://pixabay.com/photos/food-salad-raw-carrots-1209503/)

juliaで前処理大全その6です。今回は展開をテーマに扱います。

準備

今回は準備としてホテルの予約レコードreserve.csvを読み込みます。

using DataFrames,CSV,Chain,Downloads
reserve_url = "https://raw.githubusercontent.com/hanafsky/awesomebook/master/data/reserve.csv"

reserve_df = @chain reserve_url Downloads.download CSV.File DataFrame
first(reserve_df,10) |> println
10×9 DataFrame
 Row │ reserve_id  hotel_id  customer_id  reserve_datetime     checkin_date  checkin_time  checkout_date  people_num  total_price
     │ String7     String7   String7      String31             Dates.Date    Dates.Time    Dates.Date     Int64       Int64
─────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1 │ r1          h_75      c_1          2016-03-06 13:09:42  2016-03-26    10:00:00      2016-03-29              4        97200
   2 │ r2          h_219     c_1          2016-07-16 23:39:55  2016-07-20    11:30:00      2016-07-21              2        20600
   3 │ r3          h_179     c_1          2016-09-24 10:03:17  2016-10-19    09:00:00      2016-10-22              2        33600
   4 │ r4          h_214     c_1          2017-03-08 03:20:10  2017-03-29    11:00:00      2017-03-30              4       194400
   5 │ r5          h_16      c_1          2017-09-05 19:50:37  2017-09-22    10:30:00      2017-09-23              3        68100
   6 │ r6          h_241     c_1          2017-11-27 18:47:05  2017-12-04    12:00:00      2017-12-06              3        36000
   7 │ r7          h_256     c_1          2017-12-29 10:38:36  2018-01-25    10:30:00      2018-01-28              1       103500
   8 │ r8          h_241     c_1          2018-05-26 08:42:51  2018-06-08    10:00:00      2018-06-09              1         6000
   9 │ r9          h_217     c_2          2016-03-05 13:31:06  2016-03-25    09:30:00      2016-03-27              3        68400
  10 │ r10         h_240     c_2          2016-06-25 09:12:22  2016-07-14    11:00:00      2016-07-17              4       320400

横持ちへの変換

Q 横持ち変換

結合の章では複数の列をまとめるのにstack関数を用いました。 ここでは1つの列を複数の列に展開するため、unstack関数を用います。

😲 Note

unstackを利用するには、データフレーム以外に以下のようにさらに二つの引数を指定する必要があります。

unstack(df::DataFrame, :新しい列名,:展開するデータ)

ここでは、新しい列名のカラムとして:people_num、値として:rsv_cntを指定しました。

実際に適用してみましょう。

unfold_df = @chain reserve_df begin
    groupby([:customer_id,:people_num]) 
    combine(nrow=>:rsv_cnt)
    unstack(:people_num,:rsv_cnt; fill=0)
    select(["customer_id","1","2","3","4"])
end

first(unfold_df,10) |> println

10×5 DataFrame
 Row │ customer_id  1      2      3      4
     │ String7      Int64  Int64  Int64  Int64
─────┼─────────────────────────────────────────
   1 │ c_1              2      2      2      2
   2 │ c_2              2      2      1      3
   3 │ c_3              2      2      2      2
   4 │ c_4              3      2      0      3
   5 │ c_5              2      0      0      2
   6 │ c_6              0      0      1      1
   7 │ c_7              2      3      2      0
   8 │ c_8              2      0      4      2
   9 │ c_9              0      3      1      1
  10 │ c_10             0      2      2      2
処理の流れを解説すると以下のようになります。

  1. :customer_id:people_num毎に場合分け

  2. nrow関数でグループの数を数え、:rsv_cntに格納

  3. unstack関数で:people_numの値毎に:rsv_cntの値を格納。missing値は0で埋める。

  4. select関数で並べ替え

スパースマトリックスへの変換

上の例のようにデータを展開するとmissingデータができるので、メモリの節約のために スパース行列にデータを格納しようというのが、この節のお題です。

juliaではビルトインモジュールのSparseArrays.jlsparseを使えば、スパース行列を利用することが可能です。 利用方法を確認してみましょう。

using SparseArrays
print(@doc sparse)
```
sparse(A)
```

Convert an AbstractMatrix `A` into a sparse matrix.

# Examples

```jldoctest
julia> A = Matrix(1.0I, 3, 3)
3×3 Matrix{Float64}:
 1.0  0.0  0.0
 0.0  1.0  0.0
 0.0  0.0  1.0

julia> sparse(A)
3×3 SparseMatrixCSC{Float64, Int64} with 3 stored entries:
 1.0   ⋅    ⋅
  ⋅   1.0   ⋅
  ⋅    ⋅   1.0
```

```
sparse(I, J, V,[ m, n, combine])
```

Create a sparse matrix `S` of dimensions `m x n` such that `S[I[k], J[k]] = V[k]`. The `combine` function is used to combine duplicates. If `m` and `n` are not specified, they are set to `maximum(I)` and `maximum(J)` respectively. If the `combine` function is not supplied, `combine` defaults to `+` unless the elements of `V` are Booleans in which case `combine` defaults to `|`. All elements of `I` must satisfy `1 <= I[k] <= m`, and all elements of `J` must satisfy `1 <= J[k] <= n`. Numerical zeros in (`I`, `J`, `V`) are retained as structural nonzeros; to drop numerical zeros, use [`dropzeros!`](@ref).

For additional documentation and an expert driver, see `SparseArrays.sparse!`.

# Examples

```jldoctest
julia> Is = [1; 2; 3];

julia> Js = [1; 2; 3];

julia> Vs = [1; 2; 3];

julia> sparse(Is, Js, Vs)
3×3 SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 1  ⋅  ⋅
 ⋅  2  ⋅
 ⋅  ⋅  3
```

最後の例を見るに、

sparse(行インデックス, 列インデックス, データ, 行数, 列数)

のように入力すれば使えそうです。[1]

[1] scipyのcsc_matrixとはデータの指定順が異なります。

Q スパースマトリックス

ここで問題になるのが、データが文字列の場合のインデックス取得です。 本では:customer_idなどをカテゴリーデータへ変換した後に、そのままcsc_matrixなどの関数にそのまま代入しています。 juliaではCategoricalArrays.jlでカテゴリーデータへの変換が可能ですが、sparseへそのまま代入することはできませんでした。 したがって、カテゴリーデータに対して、行番号を割り当ててやる必要があります。 とりあえず、CategoricalArray型のrefsを参照をInt型に変換して、新たにidというデータとして格納し、これを行番号として割り当てることにしました。

using CategoricalArrays
cnt_df = @chain reserve_df begin
    groupby([:customer_id,:people_num]) 
    combine(nrow=>:rsv_cnt)
    transform(:customer_id=>categorical=>:customer_id)
    @aside id = Int.(_.customer_id.refs)
    hcat(_, DataFrame(:id=>id))
end
sp_data=sparse(cnt_df.id, cnt_df.people_num, cnt_df.rsv_cnt,length(levels(cnt_df.customer_id)),length(levels(cnt_df.people_num)))
Matrix(sp_data) |> println
[2 2 2 2; 0 2 2 2; 2 1 2 0; 1 0 0 1; 2 1 1 1; 0 1 0 0; 3 1 2 2; 0 0 1 1; 0 1 1 0; 2 1 2 0; 3 0 1 1; 4 3 1 0; 0 1 1 1; 1 2 1 4; 0 1 1 0; 0 1 0 0; 1 2 1 2; 0 0 0 1; 1 3 2 2; 3 0 2 1; 1 1 2 4; 1 1 1 0; 2 2 3 1; 1 0 0 1; 4 1 1 0; 2 4 1 1; 0 0 0 2; 2 0 2 0; 0 3 1 3; 2 1 1 1; 3 1 2 1; 0 1 0 1; 1 1 1 1; 0 0 1 2; 0 0 0 1; 0 1 2 1; 1 3 1 3; 1 1 0 0; 0 1 1 0; 0 0 0 1; 1 2 2 2; 1 2 0 1; 0 1 2 2; 1 2 0 1; 1 3 1 3; 0 2 2 2; 1 0 0 1; 0 2 2 1; 2 1 3 2; 2 1 0 0; 1 0 3 0; 3 0 2 0; 0 2 2 4; 2 1 5 0; 0 0 3 0; 3 1 1 3; 2 0 0 3; 1 1 0 1; 0 4 0 0; 2 0 0 1; 2 1 2 1; 2 0 3 2; 0 0 2 2; 0 2 1 2; 0 2 1 0; 1 2 2 2; 0 1 1 1; 4 0 1 1; 3 0 3 1; 0 0 2 2; 1 0 0 0; 1 3 1 2; 2 2 2 1; 4 0 2 2; 2 1 3 1; 0 0 0 1; 0 2 2 2; 2 1 5 0; 0 2 1 1; 0 0 2 2; 1 0 0 0; 1 1 0 0; 1 0 0 2; 0 0 1 2; 1 0 0 0; 1 3 2 1; 0 1 3 0; 3 0 2 3; 1 1 1 1; 0 0 0 1; 3 0 0 2; 3 0 2 2; 0 1 1 1; 0 1 0 0; 1 0 1 1; 2 2 1 3; 3 1 4 0; 2 1 1 3; 0 2 1 0; 2 3 0 2; 1 3 0 2; 1 1 1 4; 0 0 0 1; 2 1 0 0; 0 1 2 0; 1 0 3 1; 3 0 2 1; 0 0 0 1; 0 1 2 1; 0 1 2 4; 3 0 1 1; 1 2 1 3; 1 1 0 3; 0 1 2 0; 1 0 0 1; 2 0 1 2; 2 3 2 1; 3 2 1 0; 1 0 0 2; 0 0 1 1; 0 4 2 1; 0 1 0 1; 0 2 1 1; 1 2 1 0; 0 0 2 0; 1 1 0 0; 0 0 1 0; 0 1 0 3; 1 0 0 0; 2 1 1 3; 1 1 2 0; 1 2 0 1; 1 2 2 1; 0 1 4 2; 0 2 0 2; 1 0 4 2; 2 1 0 1; 1 2 2 2; 1 0 0 1; 1 1 2 4; 0 0 1 1; 0 0 1 0; 2 4 1 1; 0 1 1 0; 3 2 0 1; 1 1 0 1; 1 0 0 1; 0 2 0 1; 0 3 3 2; 1 2 2 1; 3 0 0 3; 0 2 1 1; 0 1 0 0; 2 1 2 3; 0 0 0 1; 1 2 4 1; 0 0 1 2; 0 2 1 3; 3 3 1 0; 0 1 0 0; 1 4 3 0; 2 2 2 2; 2 3 3 0; 1 0 1 1; 2 3 2 0; 2 1 0 1; 1 3 2 1; 2 0 2 1; 2 3 1 2; 0 0 1 0; 1 1 2 1; 0 1 1 0; 0 1 0 1; 2 2 1 3; 1 0 0 2; 1 4 2 1; 1 1 0 0; 2 1 2 3; 0 3 2 0; 1 2 2 1; 0 1 1 1; 1 3 0 4; 2 1 3 1; 2 0 1 0; 1 0 3 1; 0 0 0 1; 0 1 2 3; 1 0 4 0; 2 0 1 1; 1 0 2 0; 3 2 0 0; 0 1 1 0; 2 2 2 2; 1 0 0 0; 0 4 1 2; 4 0 2 1; 0 1 0 5; 4 0 0 3; 2 1 0 3; 1 0 1 1; 0 1 1 1; 2 1 2 0; 0 0 0 1; 3 2 1 1; 3 0 1 2; 0 1 2 3; 0 0 0 1; 1 1 1 2; 1 0 2 0; 2 2 1 0; 1 1 4 1; 1 0 3 1; 0 0 0 1; 0 1 0 1; 3 0 1 1; 1 0 0 1; 1 1 3 2; 1 3 0 1; 5 1 0 2; 2 0 2 1; 2 1 2 1; 0 0 1 0; 0 0 0 2; 0 1 0 0; 1 1 0 0; 3 0 1 1; 0 0 1 1; 0 1 0 0; 0 2 2 1; 1 4 3 0; 1 2 2 3; 0 2 0 1; 0 3 1 0; 1 2 3 1; 1 2 3 2; 2 0 3 1; 2 1 2 1; 4 0 0 2; 0 1 0 0; 2 1 0 0; 1 2 2 2; 1 2 1 0; 1 1 1 1; 1 1 1 2; 0 3 2 2; 1 2 0 0; 1 3 0 2; 0 2 0 0; 1 1 0 1; 0 0 0 1; 3 0 0 0; 2 1 0 3; 1 3 1 2; 1 0 0 0; 0 0 1 3; 0 2 0 2; 1 2 1 1; 2 1 1 0; 3 2 0 3; 0 0 1 0; 0 2 0 1; 2 2 0 3; 1 2 0 0; 1 4 2 1; 2 1 0 2; 0 2 0 2; 1 1 2 2; 3 1 2 1; 1 2 1 1; 1 2 0 1; 1 1 2 3; 0 0 0 1; 4 2 1 0; 0 1 0 1; 1 1 3 1; 1 0 0 0; 0 1 1 3; 0 2 2 0; 1 0 1 1; 3 2 0 1; 1 1 1 0; 1 2 2 0; 2 1 0 2; 1 0 5 1; 0 1 1 0; 1 2 2 3; 0 0 1 1; 1 1 1 1; 2 0 0 0; 1 0 0 1; 1 1 0 2; 3 2 0 3; 1 1 0 0; 0 1 0 1; 2 2 1 1; 0 2 0 0; 0 1 0 0; 3 1 1 1; 2 3 0 2; 4 0 1 1; 1 1 2 3; 0 4 3 1; 3 1 1 1; 0 0 0 1; 2 1 1 0; 0 1 0 0; 2 3 1 0; 1 0 2 3; 0 0 0 3; 0 0 2 2; 0 1 1 1; 1 0 3 3; 1 2 1 0; 2 0 0 0; 1 0 4 2; 0 1 2 2; 3 3 1 1; 1 2 2 1; 1 2 1 2; 0 0 0 1; 1 2 0 0; 0 0 1 0; 0 1 3 1; 2 0 0 2; 0 0 1 0; 0 0 1 1; 2 0 0 0; 0 2 1 4; 0 1 0 1; 1 0 1 0; 2 2 2 0; 2 2 1 3; 2 1 1 4; 1 0 0 0; 0 0 0 2; 1 1 0 1; 2 3 2 1; 0 0 0 2; 2 2 2 2; 3 1 2 2; 1 2 0 0; 0 1 0 1; 0 0 3 1; 1 0 4 1; 1 1 3 1; 0 1 2 1; 0 4 2 2; 0 0 2 1; 0 0 1 1; 1 2 1 0; 1 1 1 1; 3 1 1 0; 1 1 3 1; 0 0 1 0; 2 1 1 1; 3 0 0 2; 1 0 2 2; 3 1 1 3; 0 3 1 0; 2 0 0 1; 1 3 1 1; 3 1 0 0; 1 0 0 0; 1 1 1 0; 2 0 0 3; 2 1 0 1; 2 2 3 1; 2 1 0 0; 0 1 1 1; 1 1 0 1; 0 1 1 0; 2 1 3 0; 3 1 2 2; 2 1 2 2; 0 1 0 1; 2 0 0 1; 2 0 0 0; 2 2 2 2; 1 0 0 2; 0 3 1 2; 1 0 0 0; 1 0 1 0; 0 0 1 1; 1 1 0 3; 2 1 1 0; 2 0 0 2; 2 2 1 0; 0 0 2 0; 1 4 0 3; 0 0 1 1; 0 1 1 1; 2 2 1 1; 1 0 1 2; 0 1 1 0; 0 3 3 1; 0 1 0 0; 0 1 0 0; 1 1 1 5; 1 1 1 1; 0 3 1 1; 1 2 0 2; 1 2 2 0; 2 2 1 3; 1 4 0 1; 0 1 2 3; 0 1 3 0; 3 3 2 0; 3 0 0 2; 1 2 0 3; 1 3 3 1; 1 3 3 1; 0 4 3 1; 2 0 2 1; 2 1 2 0; 1 1 1 3; 1 2 2 2; 1 2 2 2; 0 1 0 0; 1 1 0 1; 1 0 1 1; 1 1 1 2; 2 2 1 1; 0 2 0 0; 2 0 1 0; 0 0 2 2; 4 0 0 1; 0 1 1 1; 2 0 4 1; 2 0 2 3; 2 1 2 2; 0 1 0 0; 2 0 1 1; 0 0 1 0; 1 0 1 1; 1 1 1 0; 2 0 3 3; 2 1 0 3; 0 0 0 1; 0 0 0 1; 2 1 1 1; 0 3 0 3; 0 0 1 2; 0 0 1 0; 1 2 0 3; 1 0 0 0; 3 0 0 1; 0 0 0 1; 0 2 1 0; 0 1 0 0; 2 1 0 1; 0 3 2 2; 2 0 2 1; 1 2 2 1; 3 2 0 0; 1 0 4 0; 1 1 0 0; 0 0 0 1; 0 2 0 1; 1 1 0 1; 0 1 0 1; 0 0 2 0; 1 1 3 1; 1 1 1 5; 2 3 2 1; 0 1 0 1; 1 2 2 0; 0 0 3 2; 3 1 2 1; 1 4 2 0; 3 1 1 0; 2 1 0 0; 1 0 1 0; 3 0 2 1; 0 1 0 0; 0 0 0 1; 0 1 2 3; 1 0 0 2; 1 0 1 1; 2 1 0 0; 1 0 3 1; 1 5 0 1; 1 1 0 0; 0 1 0 1; 0 0 1 0; 0 1 0 2; 0 1 3 0; 2 4 1 1; 0 0 1 1; 1 0 0 1; 2 1 1 2; 3 3 2 0; 0 1 3 4; 1 2 2 1; 2 1 4 1; 2 2 2 1; 1 2 3 1; 4 1 1 2; 1 0 0 1; 0 1 0 0; 1 3 0 3; 1 0 1 0; 0 0 0 2; 1 1 2 1; 0 1 0 0; 2 0 1 2; 2 1 1 0; 0 0 1 0; 0 1 3 0; 0 2 1 0; 1 2 1 0; 1 2 1 4; 0 1 1 1; 1 2 2 1; 1 3 1 0; 0 1 2 2; 1 1 1 1; 1 0 0 0; 2 1 2 2; 1 0 1 1; 1 0 1 0; 1 0 1 0; 1 2 1 2; 2 1 2 2; 2 3 2 0; 0 0 0 1; 0 0 0 2; 2 1 3 2; 2 1 3 1; 0 1 3 2; 0 0 1 0; 0 4 2 1; 2 1 0 0; 2 1 2 1; 1 1 2 3; 2 1 3 2; 3 0 0 3; 0 1 2 0; 2 2 0 0; 1 0 1 4; 0 1 0 0; 3 2 0 3; 2 1 0 1; 3 1 0 1; 1 1 0 0; 0 0 2 0; 0 1 0 0; 0 0 0 1; 2 1 1 2; 2 0 1 1; 0 0 1 0; 1 2 0 0; 2 3 1 0; 0 0 0 2; 2 2 2 1; 0 1 0 0; 1 2 0 0; 1 0 2 3; 1 0 1 0; 1 1 2 1; 2 1 1 2; 1 1 0 2; 0 1 2 3; 0 1 1 1; 0 2 1 0; 1 1 0 0; 2 1 1 1; 1 1 1 0; 1 2 1 0; 3 2 1 2; 0 1 5 1; 1 0 0 0; 0 1 1 3; 0 1 2 0; 0 0 2 0; 0 3 2 1; 1 0 0 1; 1 3 1 3; 1 0 4 1; 1 0 0 2; 1 1 1 4; 1 2 2 1; 0 0 0 2; 0 1 2 2; 1 0 1 0; 1 0 2 1; 2 1 2 1; 2 3 2 0; 0 0 2 1; 1 1 3 0; 1 1 1 2; 1 1 2 2; 1 0 2 0; 1 0 2 1; 1 1 0 1; 0 5 0 2; 1 1 5 1; 1 0 0 1; 2 2 0 2; 1 0 2 1; 0 1 1 0; 2 0 1 3; 0 0 2 0; 0 1 0 1; 2 1 0 1; 4 0 1 0; 0 0 0 2; 2 1 0 2; 0 0 1 0; 0 2 2 0; 3 0 1 2; 2 1 0 2; 0 3 1 2; 1 1 3 3; 2 4 1 0; 1 1 2 1; 2 0 1 0; 1 3 0 1; 0 0 0 1; 4 1 1 1; 3 2 1 1; 2 1 0 5; 0 1 0 1; 0 1 1 1; 1 0 1 1; 0 0 0 1; 2 1 1 1; 1 0 2 2; 0 0 1 0; 0 0 1 0; 0 1 2 0; 1 1 3 2; 0 1 3 1; 0 0 0 2; 3 2 1 2; 2 2 1 3; 0 0 0 1; 1 1 1 5; 1 2 0 4; 1 0 2 1; 0 0 0 1; 3 1 2 0; 0 2 1 0; 0 0 1 1; 3 0 0 1; 1 0 1 1; 0 2 0 2; 1 0 1 1; 0 2 4 2; 0 0 2 2; 4 1 1 0; 0 0 1 0; 1 2 0 2; 2 3 0 0; 1 4 2 1; 4 3 0 1; 1 1 0 1; 2 1 2 2; 1 3 0 1; 1 0 2 1; 2 2 2 1; 0 1 1 1; 1 3 0 0; 2 1 2 3; 2 1 2 3; 0 1 1 3; 1 1 1 1; 0 1 0 0; 1 0 1 1; 0 2 0 0; 1 0 1 1; 3 3 2 0; 1 1 2 1; 2 1 2 1; 0 0 2 0; 3 0 1 2; 1 0 0 0; 1 0 1 1; 0 1 1 0; 5 0 2 1; 2 0 0 1; 5 2 0 1; 2 1 0 1; 3 1 1 3; 3 1 0 1; 0 0 2 0; 4 1 2 1; 2 0 4 2; 0 0 2 0; 2 1 1 1; 0 2 0 1; 0 2 2 2; 2 1 1 0; 1 0 3 0; 1 3 4 0; 2 0 3 1; 0 0 4 2; 0 1 0 1; 3 0 1 3; 1 0 0 1; 0 0 3 1; 0 1 0 2; 1 0 1 0; 0 2 1 2; 1 1 0 0; 0 1 1 1; 1 3 2 2; 2 3 2 1; 0 0 1 2; 1 1 0 2; 2 1 2 1; 0 4 0 2; 0 1 3 2; 1 2 1 1; 2 4 0 0; 1 1 1 5; 1 1 0 1; 3 2 1 0; 0 1 3 4; 1 1 2 1; 0 2 1 4; 0 2 2 0; 1 2 2 2; 0 1 0 2; 2 2 2 2; 3 1 2 2; 1 0 0 0; 1 0 1 3; 0 0 2 2; 2 1 0 0; 1 1 1 2; 1 0 1 1; 1 0 2 3; 2 0 0 3; 1 1 1 3; 1 1 3 3; 0 1 0 0; 1 0 0 1; 1 0 2 1; 1 1 1 2; 0 4 0 1; 0 1 1 1; 2 1 2 1; 0 0 3 3; 0 1 0 1; 1 0 2 1; 1 0 0 2; 0 0 1 2; 0 1 0 1; 3 1 2 1; 1 1 1 1; 0 1 1 0; 0 0 0 2; 3 1 0 0; 1 2 2 3; 4 1 1 0; 0 2 1 0; 3 0 0 3; 3 1 0 4; 2 1 1 0; 2 2 1 3; 0 1 1 1; 1 3 2 2; 2 2 1 1; 0 0 5 3; 0 1 0 0; 0 0 2 1; 0 4 0 1; 2 2 0 1; 3 3 0 1; 1 0 1 0; 0 1 0 0; 3 0 3 2; 4 1 1 1; 2 5 1 0; 4 1 0 3; 0 1 0 1; 1 1 4 1; 1 2 4 1; 0 0 0 1; 0 0 3 1; 3 2 0 2; 1 0 0 2; 1 1 1 1; 0 2 1 1; 0 0 1 0; 1 1 1 1; 0 0 0 1; 0 2 1 0; 0 3 1 1; 0 1 1 1; 0 5 1 1; 0 0 2 2; 0 0 1 1; 3 3 0 2; 1 0 1 2; 3 1 1 2; 1 1 2 4; 0 1 0 0; 1 0 1 0; 1 4 1 2; 0 1 1 1; 2 1 2 2; 2 0 1 0; 1 1 1 0; 0 0 0 1; 0 0 1 0; 1 2 0 4; 1 0 1 0; 1 1 2 2; 1 0 0 5; 4 1 1 2; 1 1 1 1; 0 1 0 0; 0 0 1 2; 0 1 0 0; 3 2 1 0; 0 0 1 0; 2 0 1 2; 3 0 2 3; 2 2 1 3; 0 1 0 1; 0 1 3 2; 5 1 0 1; 1 2 0 0; 0 0 1 0; 0 0 6 1; 1 0 1 2; 1 1 3 2; 0 0 2 1; 1 0 0 1; 4 0 3 0; 0 2 2 0; 0 0 2 1; 1 2 1 2; 3 0 1 1; 0 1 0 0; 0 3 2 3; 0 3 0 3; 1 0 5 2; 1 0 2 1; 0 1 2 1; 0 0 0 1; 3 0 3 2; 1 1 0 2; 0 1 4 3; 1 3 2 1; 2 1 0 2; 0 1 2 0; 2 3 2 0; 3 2 2 1; 4 0 3 1; 0 1 0 0; 0 1 0 1; 2 1 1 1; 0 2 1 0; 0 1 2 0; 2 2 0 2; 0 0 0 1; 0 2 2 3; 0 1 4 3; 1 1 0 0; 1 1 3 0; 0 2 0 1; 1 0 5 1; 3 0 1 1; 0 1 0 0; 0 0 0 1; 1 2 3 1; 2 2 0 1; 0 0 3 3; 1 2 0 2; 0 3 2 1; 3 1 2 0; 0 2 0 0; 2 2 2 0; 1 0 3 1; 0 2 2 2; 2 1 4 1; 0 0 1 1; 1 1 2 4; 1 0 0 2; 2 0 1 3; 2 2 3 0; 1 0 0 0; 2 2 1 3; 0 4 3 0; 0 1 1 0; 1 3 1 1]

少々冗長な書き方になってしまいました。私がCategoricalArrays.jlの使い方に習熟していないせいかもしれませんが、このあたりはまだjuliaの未成熟な領域かと思われます。

つづく