行列の行を追加したり集計したりをcore.matrixでやりたい

できるのかやってみた。（行列をRでいうデータフレームとして使いたいのです）
集計はIncanterとか使えばいいんだけど、数十MBのデータ読み込みでOutOfMemoryになるとかマジありえないんですけどーって感じなのであきらめる。（もうすぐ出るかも？な2.0になったら考えよう）



### 単純な行・列の追加 : `join`, `join-along`

```sample.clj
(ns matrix.sample
  (:require [clojure.core.matrix :as m]
            [clojure.core.matrix.operators :as o]
            [clojure.core.matrix.select :as $]))

;; 単純な行・列の追加
(def a (m/inverse (m/diagonal-matrix (range 1 5))))
(def b (m/join a (o/* a [9 8 7 6] -1) [100 101 102 103]))

(def c (m/join-along 1 b (range -100 0)))
(m/pm c)
```

```:結果
[[  1.000   0.000   0.000   0.000 -100.000]
 [  0.000   0.500   0.000   0.000  -99.000]
 [  0.000   0.000   0.333   0.000  -98.000]
 [  0.000   0.000   0.000   0.250  -97.000]
 [ -9.000  -0.000  -0.000  -0.000  -96.000]
 [ -0.000  -4.000  -0.000  -0.000  -95.000]
 [ -0.000  -0.000  -2.333  -0.000  -94.000]
 [ -0.000  -0.000  -0.000  -1.500  -93.000]
 [100.000 101.000 102.000 103.000  -92.000]]
```

`join`で行の追加、`join-along`の最初の引数を1にすると列の追加になる。列の追加の場合はサイズが違ってもエラーにならないっぽい

### 単純な行・列の変更 : `set-row`, `set-column`, `set-selection`

```sample.clj
;; 単純な行・列の変更
(-> c
    (m/set-row 1 [1 1 2 2 3])
    (m/set-column 3 999)
    m/to-nested-vectors
    (m/mset 2 2 :abc)
    m/pm)
```

```:結果
[[  1.000   0.000   0.000 999.000 -100.000]
 [  1.000   1.000   2.000 999.000    3.000]
 [  0.000   0.000    :abc 999.000  -98.000]
 [  0.000   0.000   0.000 999.000  -97.000]
 [ -9.000  -0.000  -0.000 999.000  -96.000]
 [ -0.000  -4.000  -0.000 999.000  -95.000]
 [ -0.000  -0.000  -2.333 999.000  -94.000]
 [ -0.000  -0.000  -0.000 999.000  -93.000]
 [100.000 101.000 102.000 999.000  -92.000]]
```
`set-row`, `set-column`で行・列の変更、`mset`で1要素の変更ができる。

```sample.clj
;; 単純な行・列の変更（複数）
(-> c
    m/to-nested-vectors
    (m/set-selection [0 2] :all [[0 1 22 333 4444] :x])
    (m/set-selection :all [2 1]  [:y :z])
    m/pm)
```

```:結果
[[  0.000 :z :y 333.000 4444.000]
 [  0.000 :z :y   0.000  -99.000]
 [     :x :z :y      :x       :x]
 [  0.000 :z :y   0.250  -97.000]
 [ -9.000 :z :y  -0.000  -96.000]
 [ -0.000 :z :y  -0.000  -95.000]
 [ -0.000 :z :y  -0.000  -94.000]
 [ -0.000 :z :y  -1.500  -93.000]
 [100.000 :z :y 103.000  -92.000]]
```

複数いっぺんに変更したい場合は`set-selection`が使える。


### 単純な行・列の削除  : `exclude` 

```sample.clj
;; 単純な行・列の削除
(-> c
    ($/sel ($/exclude [1 3 5]) ($/irange))
    m/pm)

(-> c
    ($/sel ($/exclude [1 3 5]) ($/exclude 0))
    m/pm)
```

```:結果
[[  1.000   0.000   0.000   0.000 -100.000]
 [  0.000   0.000   0.333   0.000  -98.000]
 [ -9.000  -0.000  -0.000  -0.000  -96.000]
 [ -0.000  -0.000  -2.333  -0.000  -94.000]
 [ -0.000  -0.000  -0.000  -1.500  -93.000]
 [100.000 101.000 102.000 103.000  -92.000]]

[[  0.000   0.000   0.000 -100.000]
 [  0.000   0.333   0.000  -98.000]
 [ -0.000  -0.000  -0.000  -96.000]
 [ -0.000  -2.333  -0.000  -94.000]
 [ -0.000  -0.000  -1.500  -93.000]
 [101.000 102.000 103.000  -92.000]]
```

`sel`の中で`exclude`を使うと特定の行･列を除いて取得できる。


### 特定の条件に合致した行を削除する

ここからはcore.matrixにないので自前で何とかする。

```sample.clj
(-> (remove #(zero? (first %)) c)
    m/to-nested-vectors
    m/pm)
```

```:結果
[[  1.000   0.000   0.000   0.000 -100.000]
 [ -9.000  -0.000  -0.000  -0.000  -96.000]
 [100.000 101.000 102.000 103.000  -92.000]]
```

単純に`remove`とか`filter`使えばいい
core.matrixが内部で使っている実装によっては`to-nested-vectors`を先に入れとかないとダメかもね

### 特定の列を関数適用して変更する

```sample.clj
(defn update-column [matrix index f]
  (let [c (m/select matrix :all index)]
    (m/set-column matrix index (map f c))))

(-> c
    (update-column 1 #(* 5 %))
    m/pm)
```

```:結果
[[  1.000   0.000   0.000   0.000 -100.000]
 [  0.000   2.500   0.000   0.000  -99.000]
 [  0.000   0.000   0.333   0.000  -98.000]
 [  0.000   0.000   0.000   0.250  -97.000]
 [ -9.000  -0.000  -0.000  -0.000  -96.000]
 [ -0.000 -20.000  -0.000  -0.000  -95.000]
 [ -0.000  -0.000  -2.333  -0.000  -94.000]
 [ -0.000  -0.000  -0.000  -1.500  -93.000]
 [100.000 505.000 102.000 103.000  -92.000]]
```

1列目が5倍になってる

### ソート（SQLでのorder byっぽく）

```sample.clj
(defn- parse-orders [orders]
  (->> (map #(when (number? %1)
               (if (= :desc %2) [%1 -1] [%1 1]))
            orders (concat (drop 1 orders) [nil]))
       (remove nil?)))
(defn order-by [matrix & orders]
  (let [o (parse-orders orders)
        f (fn [v1 v2]
            (reduce (fn [_ [i sign]]
                      (let [r (* sign (compare (nth v1 i) (nth v2 i)))]
                        (if-not (zero? r) (reduced r) 0)))
                    0 o))]
    (sort f (m/to-nested-vectors matrix))))

(-> c
    (order-by 1 2 :desc 3)
    m/pm)
```

```:結果
[[ -0.000  -4.000  -0.000  -0.000  -95.000]
 [  0.000   0.000   0.333   0.000  -98.000]
 [ -0.000  -0.000  -0.000  -1.500  -93.000]
 [  1.000   0.000   0.000   0.000 -100.000]
 [ -9.000  -0.000  -0.000  -0.000  -96.000]
 [  0.000   0.000   0.000   0.250  -97.000]
 [ -0.000  -0.000  -2.333  -0.000  -94.000]
 [  0.000   0.500   0.000   0.000  -99.000]
 [100.000 101.000 102.000 103.000  -92.000]]
```

1列目昇順、2列目降順、3列目昇順でソートできた


### 集計

```sample.clj
(defn aggregate [matrix aggregate-index f group-indices]
  (->> (group-by #(reduce (fn [m i] (conj m (nth % i))) [] group-indices) matrix)
       (mapcat (fn [[k v]] [k (reduce f (map #(nth % aggregate-index) v))]))
       (apply hash-map)))

(aggregate c 3 + [0 1])
```

```:結果
{[1.0 0.0] 0.0, [100.0 101.0] 103.0, [0.0 0.0] -1.25, [0.0 0.5] 0.0, [-0.0 -4.0] -0.0, [-9.0 -0.0] -0.0}
```

0列目と1列目でグルーピングして、3列目を合計してる