数 - Alexandria

概要

このページではCommon Lispの汎用ユーティリティであるAlexandriaの「数」に関するオペレータを紹介します。

clamp関数: 範囲内に収まるように調整

検査をしたい数が特定の範囲に収まる場合はその数を、収まらない場合は最も近い範囲内の数を返すという関数がclampです。
(alexandria:clamp -5 1 5)
; => 1
(alexandria:clamp 3 1 5)
; => 3
(alexandria:clamp 10 1 5)
; => 5
第1引数が検査をする数、第2・3引数が範囲です。

gaussian-random関数: 正規分布に従う乱数の生成

Common LispにはANSI標準で一様乱数を生成する関数が定められています(第12章「」)。また、MT19937という良質な擬似乱数生成ライブラリもあるため、一様乱数が必要な時はこれらを使用することができます。

Alexandriaのgaussian-random関数はガウス確率、すなわち正規分布に従う乱数を生成する関数です。0.0d0を基準とする乱数を生成します。引数はオプショナルで、範囲を指定することも可能です。
(alexandria:gaussian-random -1 1)
; => 0.8726597297126646d0 ;
;    -0.17264114012888226d0

iota関数: 数列の生成

iota関数は定番の数列生成オペレータです。使い方は3通りあります。

まず、引数を1つだけ指定すると0から指定した数個の数列を作ります。
;; 定番なので、あらかじめインポートしておく
(shadowing-import 'alexandria:iota)
; => T

(iota 5)
; => (0 1 2 3 4)

次に、:startキーワードで開始位置を指定することもできます。
(iota 5 :start 10)
; => (10 11 12 13 14)

最後に、:stepキーワードで間隔を指定することができます。
(iota 5 :step 5)
; => (0 5 10 15 20)

Common Lispは分数もネイティブにサポートしているので、当然このような分数の数列を生成することも可能です。
(iota 5 :step 1/3)
; => (0 1/3 2/3 1 4/3)

map-iota関数: 数列のマッピング(高階関数)

map-iota関数は生成した数列に対してマッピングを行います。ただし、マッピングの結果は返り値とはなりませんので、副作用を目的として使用されます。
(defun tri (n) (print (expt n 3)))
; => TRI

(alexandria:map-iota #'tri 10)
; 
; 0 
; 1 
; 8 
; 27 
; 64 
; 125 
; 216 
; 343 
; 512 
; 729 
; => 10

lerp関数: 線形補間

Alexandriaのlerp関数は最も基本的な補間アルゴリズムである線形補間(Linear interpolation)を行うオペレータです。第1引数に補間係数を、第2・3引数に点の座標を与えます。

ここでは、CLOS (Common Lisp Object System) を用いた二次元座標における線形補間のサンプルを示します。CLOSの詳細については第4章「型とクラス」及び第7章「オブジェクト」を参照してください。
;; 2次元座標における点を示すpointクラスを定義する
(defclass point ()
  ((x :initarg :x
      :accessor point-x)
   (y :initarg :y
      :accessor point-y)))
; => #<STANDARD-CLASS POINT>

;; print-object総称関数を定義しておく
(defmethod print-object :before ((p point) stream)
  (format stream "(x, y) = (~a, ~a)~%" (point-x p) (point-y p)))
; => #<STANDARD-METHOD :BEFORE (#<STANDARD-CLASS POINT> #<BUILT-IN-CLASS T>)>

;; 補間係数と2点を取り、補間後の点オブジェクトを返す point-lerp 関数
(defmethod point-lerp ((v real) (a point) (b point))
  (make-instance 'point
                 :x (alexandria:lerp v (point-x a) (point-x b))
                 :y (alexandria:lerp v (point-y a) (point-y b))))
; => #<STANDARD-METHOD
;   (#<BUILT-IN-CLASS REAL> #<STANDARD-CLASS POINT> #<STANDARD-CLASS POINT>)>

;; サンプル点1
(defparameter p1 (make-instance 'point :x 1 :y 3))
; => P1
;; サンプル点2
(defparameter p2 (make-instance 'point :x 5 :y 8))
; => P2

;; point-lerp 関数を試す
(point-lerp 1/4 p1 p2)
; (x, y) = (2.0, 4.25)
; => #<point x000000020043aa91="">

mean関数: 平均

Alexandriaのmean関数はリストやベクトルなどのシーケンスの平均を求める関数です。
;; リスト
(alexandria:mean '(1 2 3 4 5))
; => 3

;; ベクトル
(alexandria:mean #(1 2 3 4 5))
; => 3

median関数: 中央値

Alexandriaのmedian関数はシーケンスの中央値を求める関数です。
(alexandria:mean '(2 5 1 3 4))
; => 3

variance関数: 分散

variance関数は分散を求める関数です。分散とは、平均との差分の2乗の和を個数で割ったものです。確率論では平均が「1次のモーメント」、分散が(中心まわりの)「2次のモーメント」と呼ばれます。

例えば'(1 2 3 4 5)の平均は3なので、それぞれの値の3との差分を取ると'(-2 -1 0 1 2)となります。そしてそれを2乗すると'(4 1 0 1 4)となり、その和は10となります。最後に10を要素数である5で割ると2になります。
(alexandria:variance '(1 2 3 4 5))
; => 2
なお、統計の世界では要素数で直接割るのではなく、1を引いてから割ることが多いです。これは「自由度」と呼ばれています。分散は平均との差分を使って求めますが、基準(平均)となる値1つ分は基準から離れることができないため、5ではなく4を使って割ります。このような分散を「標本分散」と呼び、「母分散」と区別されます。

Alexandriaでは:biasedキーワード引数をnilにすることで標本分散を得ることができます。
(alexandria:variance '(1 2 3 4 5) :biased nil)
; => 5/2

standard-deviation関数: 標準偏差

分散は値の散らばりを見るための指標ですが、分散を求める際に2乗しているので、元の単位が失われています。そこで元の値の単位と同じにするために分散を平方根した「標準偏差」がよく使われます。Alexandriaではstandard-deviation関数で求めることができます。
(alexandria:standard-deviation '(1 2 3 4 5) :biased nil)
; => 1.5811388
なお、テストでよく聞く「偏差値」は平均を50、標準偏差を10として標準化した指標です。分布が正規分布に近い場合は、例えば偏差値70は平均点を2標準偏差上回っていることを意味するので、全体の上位約2〜3%であることを意味します。

maxf, minf関数: 最大値・最小値のモディファイマクロ

ANSI Common Lispではmax関数とmin関数が定められており、最大値と最小値は標準仕様の範囲内で求めることができます。Alexandriaが提供するmaxfminfは「モディファイマクロ」で、求めた最大値・最小値を変数に束縛するところまでを提供します。
;; 変数の準備
(defparameter v 0)
; => V
v
; => 0

;; モディファイマクロを使用
(alexandria:maxf v 1 2 3 4 5)
; => 5

;; 変数の値が変わっている
v
; => 5

モディファイマクロはdefine-modify-macroマクロを使って簡単に定義できます。Alexandriaのmaxfminfはそれぞれ以下のように定義されています(ドキュメント文字列は省略)。
;; maxfの定義
(define-modify-macro maxf (&rest numbers) max)

;; minfの定義
(define-modify-macro minf (&rest numbers) min)

0 件のコメント :

コメントを投稿