2014年2月11日火曜日

行列の対角化とは何か?

はじめてのパターン認識」の観測データの無相関化の節を読んでいて、行列の対角化ってなんだっけ?という、そもそものところでつまづいたので(※1)、行列の対角化について、ここで少し整理しようと思う。

今回は純粋に線形代数学の話題に終始して、本来のデータの無相関化については、また後日書く予定。

■対角化を理解するまでの道筋

すこし長くなるので、「行列の対角化とは何か?」を理解するための道筋を整理すると
  1. 固有値と固有ベクトルの意味を理解する。
  2. 固有ベクトルを並べた変換行列の性質を理解する。
  3. 対角化操作を理解する。
になると思う。というわけでこの道筋に従って話しを進めようと思う。
なお、ここでは話しの分かりやすさを優先するので、数学的な一般性(※2)はひとまずおいておいて、わかりやすいシチュエーションの話だけをしていきたいと思います。一般的な状況でのより詳しいことはここ(PDF)を参照すると良いです。(上記、1、2の話題について、非常にわかりやすく整理&説明されています。)


■固有値と固有ベクトルの意味を理解する。

▼固有値と固有ベクトルの定義

まずは、固有値、固有ベクトルを定義をしておくと以下のとおり。
任意の正方行列 \(A\) について, \(A \mathbf{v} = \lambda \mathbf{v}\)を満たす \(\lambda \) を\(A \) の固有値といい、\(\mathbf{v} \) を\(A \) の固有ベクトルという.
n次の正方行列にはn個の固有値とそれに対応した固有ベクトルを持つ(※3)。

▼固有値と固有ベクトルの意味

上記の定義だけだといまいちなので、これらが図形的に何を意味しているのかを少し説明しておく。
一般にベクトル\(\mathbf{v} \) に行列\(A \)を作用させるということは、ベクトルを線形変換しそのベクトルの「方向」と「長さ」を変更する操作にあたる。

たとえば、
行列\(A=\left(
\begin{array}{cc}
3 & 1 \\
2 & 4 \\
\end{array}
\right)\)
をベクトル \(\mathbf{v} = (5, 1)^T\) (下図:青)に作用させた場合、作用後のベクトルは\(A\mathbf{v} = (16, 14)^T\)(下図:赤)になる。行列を作用させることによって方向と長さが変更されたことがもわかる。



今回は2次元行列を考えているので、2次元の\(\mathbb{R}^2\)空間でのベクトルは(2つ特別なベクトルを除いて)どんなベクトルも上の例と同じように方向が変更される。

その2つの特殊なベクトルが固有ベクトルであるわけだ。

固有ベクトルの定義を見直すとわかるとおり、固有ベクトルに行列\(A \)を作用させても、元のベクトルの定数倍(固有値倍)にしかならない。つまり「方向が変更されない」のである。

実際の例を見てみよう。行列\(A \)の固有値は、\(\lambda_1 = 5\), \(\lambda_1 = 2\)の2つであり、それに対応する固有ベクトルは、\(\mathbf{u}_1 = (1, 2)^T\), \(\mathbf{u}_2 = (1, -1)^T\)である(※4)。例えばそのうちの1つの固有ベクトル\((1,2)^T\)に行列\(A \)を作用させると\((5,10)^T=5(1,2)^T\)であり元のベクトルの固有値(定数)倍で方向は変わらないのである。下図はそれを図示したもので、青が行列\(A \)作用前、赤が作用後のベクトルとなっている。わざわざ図示するまでもないけれど、方向に変化がないことがわかる。



\(\mathbf{x} = a_1 \mathbf{u}_1 +  a_2 \mathbf{u}_2\)
というように、固有ベクトルを線形結合することで、2次元\(\mathbb{R}^2\)空間の任意のベクトル\(\mathbf{x}\)が表現できることに注意すると、任意のベクトルに行列\(A \)を作用させるということは、
\(A\mathbf{x} = a_1 A \mathbf{u}_1 +  a_2 A \mathbf{u}_2 = a_1 \lambda_1 \mathbf{u}_1 +  a_2 \lambda_2 \mathbf{u}_2\)
であり、それぞれの固有ベクトル方向に固有値倍ずつ伸縮結果に他ならない。

■固有ベクトルを並べた変換行列の性質を理解する

行列Aに、一次独立なn個の固有ベクトルが存在し、それを並べた
\(P=(\mathbf{u}_1, \cdot\cdot\cdot , \mathbf{u}_n)\)
を考える。
このとき、基底ベクトル \(\mathbf{e}_i  (i = 1, 2, ..., n )\)に\(P\)を作用させると、
\(P\mathbf{e}_i = \mathbf{u}_i\)
と固有ベクトルに変換されることがわかる。
結果、任意のベクトル
\(\mathbf{x} = \sum_{i=1}^n a_n \mathbf{e}_i\)
に\(P\)を作用させると
\(P\mathbf{x} = P \sum_{i=1}^n a_n \mathbf{e}_i = \sum_{i=1}^n a_n P\mathbf{e}_i  = \sum_{i=1}^n a_n \mathbf{u}_i \)
と変換される。

先述の具体的な行列を例に見ていく。
固有値ベクトルを並べた変換行列\(P = (\mathbf{u}_1,\mathbf{u}_2)\)を考える。この行列を基底ベクトル、
\(\mathbf{e}_1 = (1, 0)^T\),\(\mathbf{e}_2 = (0, 1)^T\)
に作用させると、
\(P\mathbf{e}_1 = (1, 2)^T = \mathbf{u}_1\), \(P\mathbf{e}_2 = (1, -1)^T = \mathbf{u}_2\)
となり、基底を固有空間に移す行列になっていることがわかる。
例えば、
\(\mathbf{x} = (5, 1)^T = 5\mathbf{e}_1+ \mathbf{e}_2 \)
に\(P\)を作用させると、
\(P\mathbf{x} = 5\mathbf{u}_1+\mathbf{u}_2\)
となる。


■対角化操作

上記のように、変換行列を書けることで、任意のベクトルを基底\(\mathbf{e}_i  (i = 1, 2, ..., n )\)での表現から、行列Aの固有ベクトルの固有空間の表現に変換される。
このような変換後、行列Aを作用させると\(\mathbf{u}_i\)は向きが変わらず、長さが \(\lambda_i\)倍になるだけ。
\[AP\mathbf{x} = A \sum_{i=1}^n a_n \mathbf{u}_i = \sum_{i=1}^n \lambda_i a_i \mathbf{u}_i \]
これにさらに\(P^{-1}\)を作用させると\(\mathbf{u}_i\)は元の\(\mathbf{e}_i\)に戻り、
\[P^{-1}AP\mathbf{x} = \sum_{i=1}^n \lambda_i a_i P^{-1}\mathbf{u}_i = \sum_{i=1}^n \lambda_i a_i \mathbf{e}_i \ = D\mathbf{x}\]
ここで、
\[
  D = \left(
    \begin{array}{cccc}
      \lambda_1 & 0         & \cdots & 0 \\
      0         & \lambda_1 & \cdots & 0 \\
      \vdots    & \vdots    & \ddots & 0 \\
      0         & 0         & \cdots & \lambda_n
    \end{array}
  \right)
\]

となり、\(P^{-1}AP\)が対角化行列となるわけである。


(追伸)
ここで使った図はpython&matplotlibを使って描いた。そのソースはここを参照のこと。

  • (※1)昔は、嫌というほど線形代数学を勉強したのに、情けない話だ・・・
  • (※2)固有値が重解になる場合はどうなんだ、とかそんな話。
  • (※3)固有値が重解を持つ場合などは、一見 n個よりも少ない固有値しかないようにみえることもあるが・・・。また、回転行列は実数の固有値はないが、複素数まで考えるとちゃんと固有値を持つ。
  • (※4)求め方はやはりここ(PDF)が参考になる。
  • (※5)つまり、2つの固有ベクトルが2次元\(\mathbb{R}^2\)空間の基底であるということ。

2014年2月4日火曜日

rpy2をインストールする。

IPython NotebookからRを利用するためには、Rmagicという機能拡張を使えばいいとのことなのだけど、これがrpy2というライブラリを使うため、これをインストールしなくてはならない。
折角なので、今回行ったインストール手順をまとめておく。

■インストール

▼前提

Windows7で、pythonとRはインストールされているものとする。

▼RのPATHを設定しておく。

これをしないと・・・
  • インストールの時に「Error: Tried to guess R's HOME but no R command in the PATH.」と、Rが見つからないよ!と怒られます。
  • pythonでモジュールをimportする際に、「RuntimeError: R_HOME not defined.」とか、「RuntimeError: R_USER not defined.」とか怒られます。
スタート>「コンピューター」を右クリック>プロパティ>左パネルの「システムの詳細設定」>環境変数 を開きます。その画面で次の3つを設定。

  • ユーザー環境変数のPATHを編集し、R.exeのあるbinフォルダをセミコロンで区切って末尾に追記します。つまり「;C:\Program Files\R\R-2.15.3\bin」(←僕の環境の場合)を末尾に追加する。
  • システム環境変数で、以下のPATHを追加。
    • 変数名「R_HOME」、変数値「C:\Program Files\R\R-2.15.3」(←僕の環境の場合)
    • 変数名「R_USER」、変数値「xxxx」(xxxxはWindowsのログイン名)

▼pipでインストール

上記で環境変数を指定した後、コマンドプロンプト(*1)を開き
$pip install rpy2
と打つ。簡単!


▼pipでエラーが出る場合・・・

環境によっては、pipでインストールしようとしたら、
"C:\PROGRA~1\R\R-215~1.3\bin\R" CMD config --ldflags
Invalid substring


みたいなエラーが出る場合がある(*2)。
この場合は、このページの環境に合わせたバイナリ(僕の環境の場合はrpy2 2.3.9.win32 py2.7.exe)をダウンロードし、あとはダブルクリックでインストールすればよい模様(参考)。

▼確認

コマンドプロンプトなりでpythonを起動して
import rpy2.robjects as robjects
を打って、エラーとかでないと、とりあえずインストール成功!

■Rmagic

rpy2をインストールしたら、IPython NotebookでRmagicを使ってRのコマンドが使えるようになる。
使い方はココが分かりやすい。


(*1)Windows標準のコマンドプロントでもいいし、scipyスタックのanacondaを使ってる場合、「anaconda command prompt」でもいい。ただしどちらの場合も、環境変数の更新を行った場合には、プロンプトを開きなおさないと環境変数の設定変更が反映されないことに注意!(これでだいぶハマッた)

(*2) 僕の職場のPCへのインストールはこれでハマる (+_+)。

2014年2月2日日曜日

科学計算用のscipyスタック(anaconda)

科学計算用(というより統計や機械学習系)のpython環境をwindowsにつくろうとして、いろいろ調べていると、scipyスタック(*1) として「anaconda」というものが存在することを知った

このanaconda、かなり便利でこれ1つインストールするだけで、主なところで、
  • python 2.7.5
  • theano 0.5.0 L
  • numpy 1.7.1
  • scipy 0.13.0
  • pip 1.4.1
  • matplotlib 1.3.1
  • pandas 0.12.0
とかが一緒にインストールされる。(全パッケージ情報はここ参照)

■インストール方法(Windows)

インストール方法は全くもって簡単で、ここからwindows用インストーラーをダウンロード。ダウンロードしたインストーラーをダブルクリックで起動するだけ。

インストール中は、基本的に画面に従ってデフォルト設定で「次へ」を押していけばいいが、一点だけ注意が必要で、英語で「自分のみにインストールするか?(推奨)、それともシステム全体にインストールするか?」と聞かれる箇所がある。この時デフォルトの設定では「システム全体にインストール」側にチェックが入っているので、推奨の「自分のみにインストール」をしたければ、チェックを付替えてから「次へ」でインストールを進める。

■動作確認

インストールが終わったら、「スタートボタン>全てのプログラム」に「Anaconda」の項目がある。
例えば、「Annaconda Command Prompt」を選択し、コンソールから
$python -V
と入力してバージョン情報が表示されれば、ひとまずインストールは成功。

また、anaconda本体は、「自分のみにインストール」を選択してインストールした場合、
「C:\Users\[XXX]\Anaconda」
以下にインストールされている。(ここで[XXX]はあなたのユーザーネーム)

これだけ簡単にインストールできるとなると、pythonでのデータ分析とかの敷居がどんどん低くなっていくなーと感じる。

■パッケージをアップデート

Anacondaで使われているパッケージは若干古いバージョンのものも含まれるので、使うパッケージは最新版にアップデートしておいた方がよい。Anacondaは独自のパッケージ管理ツール「conda」で管理されるので、例えばpandasを最新版にアップデートしたい場合は、
「Annaconda Command Prompt」を起動し、コンソールから
$conda update pandas
を実行すればOK。依存するパッケージも自動でアップデートしてくれる。
また、condaで管理していないパッケージについては、従来どおりpipでアップデートも可能。

2013年12月1日日曜日

ポアソン分布 まとめ

悲しいくらいに、「超」初心者な話題だけれど、いっつも「ポアソン分布」について忘れてしまうので、メモ代わりに、自分なりにまとめた。(詳細などはこれを参照)

■ポアソン分布とは
  ポアソン分布\(Po(\lambda)\)は、二項分布\(Bi(n,p)\)(※)で\(np\rightarrow\lambda\)となるように\(n\)を大きく、\(p\)pを小さくする極限での確率分布。
  二項分布と同じく特定の事象が起きる回数の分布なので、離散型の確率分布。

■ポアソン分布の確率分布の関数
  ポアソン分布は、たった1つのパラメータ「\(\lambda\)」だけで記述される。
  特定の事象が発生する回数を示す確率変数を\(X\)とするとき、それが\(k\)となる確率分布は
  \[Po(X=k) = \frac{\lambda ^ k e ^ {-\lambda}}{k!}\]
  と定式化される。

■ポアソン分布の性質
  期待値と分散が等しく\(\lambda\)となる。


(※)二項分布\(Bi(n,p)\)は、確率\(p\)で起きる特定の事象が、独立な試行を\(n\)回行った時に、起きる回数の確率分布。

2013年8月3日土曜日

Rで「隠れマルコフモデル」の解析

「隠れマルコフモデル」を少し勉強してみたので、まとめてみる。
モデルの考え方について一番参考になったのは、ここ(pdf)と、ここ(pdf)と、ここだ。

▼隠れマルコフモデルの考え方

  隠れマルコフモデルを一言でいうと、
時間的に非定常な観測事象を、「(隠れた)複数の定常状態が、マルコフ性を持つ確率過程で遷移し、それぞれの定常状態の確率分布に従って観測事象が生起される」という考え方で記述しようとするモデル。
といえる。文章で言っても伝わりづらいので、考え方のイメージを下の図に示す。

  観測事象が図上部の折れ線グラフに示されている。ここで観測事象は何でもよい。株価の騰落率の時間変化でも良いし、ある店舗の売り上げの時間変化でも良い。ここで例にあげた図の観測事象は、時間に関して初期・中期・後期のそれぞれで振る舞いが異なるように見える。

  これをモデルに落とし込むため隠れマルコフモデルは「隠れた定常状態(上の例では3つ)が存在し、各定常状態の確率分布(図下部の青・赤・緑で示された確率分布)に従って観測事象が表れ、かつ定常状態間は時間経過と共にマルコフ性を持つ確率過程で遷移する」という考え方をする。

  マルコフ性とは
「状態間の遷移確率は、過去の経緯とか関係なく、「現在がどの状態か?」のみで決定される」
という性質である。例えば現在が定常状態Aであれば(過去にどういう状態遷移をしたに関わらず)状態Aから、Aに自己遷移する確率は何%、Bに遷移する確率は何%、Cに遷移する確率は何%というように決定されるという性質である。

▼隠れマルコフモデルを定式化する。

  上記のような考え方を定式化すると、以下のようになる。
  定常状態(上の例ではA・B・C)が時刻\(t = 1\)~\(n\)に、時間的に連続した系列\( Q:=\{q_1,q_2, \cdot \cdot \cdot, q_n\}\)となる場合に、観測事象が系列\( Y:=\{y_1,y_2, \cdot \cdot \cdot, y_n\}\)となる確率 \(P(Y|Q)\)は
\[P(Y|Q)=\pi_{q_0}\prod_{t=1}^{n} a_{q_t q_{t+1}}b_{q_t}(y_t)\]
ここで、

  • \(b_{q_t}(y_t)\)は、時刻\(t\)の隠れた定常状態\(q_t\)から観測事象\(y_t\)が現れる確率分布。(つまり上図での青や赤や緑で表わされた確率分布)
  • \(a_{q_t q_{t+1}}\)は、時刻が\(t\)から\(t+1\)に進む際に、隠れた定常状態\(q_t\)から\(q_{t+1}\)に遷移する確率。
  • \(\pi_{q_0}\)は、状態\(q_0\)が初期定常情報源となる確率。


▼隠れマルコフモデルで何が推定できるのか?

  隠れマルコフモデルには主に2つのアルゴリズムを用いて以下の推定が可能である。
  1つは、Baum-Welchアルゴリズムを用いて、上記定式化の各パラメータ\(\pi_{q_0}\)、\(a_{q_t q_{t+1}}\)、\(b_{q_t}(y_t)\)を推定すること。
  もう1つは、Viterviアルゴリズムを用いて、観測事象の系列\( Y:=\{y_1,y_2, \cdot \cdot \cdot, y_n\}\)が観測される場合に、尤度関数を最大化する、定常状態系列\( Q:=\{q_1,q_2, \cdot \cdot \cdot, q_n\}\)を求めることだ。

▼解析用のテストデータ作成

では、実際にRで隠れマルコフモデルの解析を行っていく。まずはじめに下図のような解析用のテストデータを作成しておく。
このテストデータは、

  • 定常状態A: 平均10、分散6の正規分布で観測事象が出現する状態
  • 定常状態B: 平均12、分散7の正規分布で観測事象が出現する状態

の2つの定常状態があり、時間1~200と401~600は定常状態A、時間201~400と601~800は定常状態Bとなっているデータだ。

データ作成用のRコードは以下のとおり。
set.seed(1) #乱数シード作成
size <- 200 #データセットの大きさ
mean.a <- 10 #定常状態Aの平均
var.a <- 6 #定常状態Aの分散
mean.b <- 12 #定常状態Bの平均
var.b <- 7 #定常状態Bの分散
x.1 <- rnorm(size, mean.a, sqrt(var.a)) #データ作成
x.2 <- rnorm(size, mean.b, sqrt(var.b)) #データ作成
x.3 <- rnorm(size, mean.a, sqrt(var.a)) #データ作成
x.4 <- rnorm(size, mean.b, sqrt(var.b)) #データ作成
x <- c(x.1, x.2, x.3, x.4) #データ連結
plot(x, xlab = "time", ylab = "observed quantity")

▼Baum-Welchアルゴリズム

実際にBaum-Welchアルゴリズムを用いて、上記定式化の各パラメータ\(\pi_{q_0}\)、\(a_{q_t q_{t+1}}\)、\(b_{q_t}(y_t)\)を推定する。

Rには隠れマルコフ解析用のパッケージ「RHmm」があるので、それを使えば簡単に推定できる(パッケージは前もってインストールしとく必要あり)。実際の解析用のコードは以下のとおり。
> library("RHmm") #隠れマルコフモデルのライブラリ読み込み
> hmm.fitted <- HMMFit(x, nStates = 2) #フィッティング(ステート数は2を設定)
> print(hmm.fitted$HMM) #Baum-Welchアルゴリズムでの推定量を表示
まずRHmmパッケージを読み込み、先のテストデータ「x」、定常状態数は2(今回はAとBの2つだから)を指定してHMMFit関数を実行する。この関数の戻り値はBaum-Welchアルゴリズムの解析結果も含むので、それをプリントする・・・だけ。

実行結果は以下のとおり。
Initial probabilities:
         Pi 1 Pi 2
  3.50879e-35    1

Transition matrix:
            State 1     State 2
State 1 0.997176507 0.002823493
State 2 0.005380641 0.994619359

Conditionnal distribution parameters:

Distribution parameters:
            mean     var
State 1 11.89274 7.75078
State 2  9.99124 6.01621

ここで、結果の内容を見ていく。

まずは、Distribution parametersの項。ここは先の\(b_{q_t}(y_t)\)の推定値、すなわち隠れた定常状態の確率分布について示されている。
・「State 1」がテストデータの定常状態B
・「State 2」がテストデータの定常状態A
を表わしている。
これらの結果に表示された平均と分散は、テストデータを用意した際のパラメータと良く一致している。

次にInitial probabilitiesの項。ここは先の\(\pi_{q_0}\)の推定値を示している。「Pi 2(=State2が初期状態として現れる確率)」がほぼ1であり、定常状態Aが最初に現れているテストデータと合致している。

最後にTransition matrixの項。これは先の\(a_{q_t q_{t+1}}\)の推定値を示している。
  • 定常状態Aの時、定常状態Aに(自己)遷移する確率は0.997程度。定常状態Bに遷移する確率は0.003程度。
  • 定常状態Bの時、定常状態Bに(自己)遷移する確率は0.995程度。定常状態Aに遷移する確率は0.005程度。
と推定されていることを示している。状態A・B共に、テストデータでは200回に199回は自己遷移(確率0.995)。1回はもう一方の状態に遷移(確率0.005)しているので、その状況と合致しているの分かる。

▼Viterviアルゴリズム

次にViterviアルゴリズムを用いて、テストデータのような観測事象が現れたとき、最も尤(もっと)もらしい(尤度関数を最大化する)、定常状態の系列(ここでは状態Aと状態Bの時間系列)を求めてみる。
解析用のRコードは以下のとおり。
> #先ほどのHMMFitの戻り値とテストデータXからViterbiアルゴリズムフィッティング
> vitervi.fitted = viterbi(hmm.fitted,x)
> #Viterviアルゴリズムで求めた、最も尤もらしい状態の系列をプロットする。
> plot(vitervi.fitted$states, xlab = "time", ylab = "Most Likely Status ID")
結果は、次のグラフで、テストデータ作成時に設定した状態遷移の時系列とよく合致している結果が得られている。


以上。

2013年5月26日日曜日

中心極限定理をRでシミュレーション

中心極限定理とは、大まかに言えば、
母集団の確率変数\(X\)がどんな確率分布であっても、その平均と分散が\(\mu\)と\(\sigma^2\)であれば、その標本(サンプル数\(n\))の確率変数\(X\)の和や平均は、それぞれ正規分布 \(N(n\mu, n\sigma^2)\)、 \(N(\mu, \sigma^2/n)\)に従うということである。

それが本当かどうか確かめたかったので、Rのプログラムを書いて検証してみた。
ここでは、「指数分布に従う確率変数の平均」で検証した。

以下にコードを置いておく。
実際にCONSTANTSの部分をいろいろ変えて
  • 分布が正規分布に従い、その平均と分散が中心極限定理の予言通りか?
  • 標本数が大きくなれば、分散は実際に小さくなっていくのか?
などを確認してみるとよい。


#中心極限定理が成り立つかをシミュレーションするRスクリプト
#ここでは、指数分布の確率分布に従う確率変数Xの平均値について検証。

## CONSTANTS
SAMPLE.NUM <- 10 #1回の試行での標本数。
TEST.NUM <- 50000 #試行回数(この数の試行を繰り返して分布が正規分布になるかをみる。)
EXP.LAMBDA <- 3 # 指数関数パラメータλ
PLOT.MAX.X <- 1 #こ

#各行が指数分布に従う確率変数の一つの標本を表わす行列を生成。
data.matrix <- matrix(rexp(TEST.NUM, rate = EXP.LAMBDA), ncol = SAMPLE.NUM)

#各試行(= 各行)の平均をとる。
means.of.each.test <- apply(data.matrix,MARGIN=1,mean)

#各試行の平均の、相対度数ヒストグラムを描画
hist(means.of.each.test, breaks=seq(0, PLOT.MAX.X, by=0.05), xlim=c(0, PLOT.MAX.X), probability = TRUE)

#中心極限定理が予言する平均と分散を求める。
#ここで母集団分布がλ=EXP.LAMBDAの指数分布であり、
#その平均と分散(母平均&母分散)がそれぞれ、
#母平均=1/λ、母分散=1/λ^2なので・・・
theorem.mean <- 1/EXP.LAMBDA
print(theorem.mean)
theorem.var <- 1/EXP.LAMBDA^2/SAMPLE.NUM
print(theorem.var)

#中心極限定理が予言する正規分布を描画する。
#ヒストグラムと正規分布曲線が一致すれば、中心極限定理は正しい!
x <- seq(0, PLOT.MAX.X, by=0.01)
lines(x, dnorm(x, theorem.mean, sqrt(theorem.var)), col="red")

2013年5月18日土曜日

R言語のcut関数の使い方

R初心者として、cut関数がいまいち分かりにくかったので、ここで少しまとめておく。

■cut関数は何をする関数?
一言でいうと「数値データを、指定した分割基準でカテゴリに変換する関数」だ。
もう少し詳しくいうと、例えば英語の試験を行い各人の試験結果を
> x <- c(90, 55, 79, 80, 100)
とする。80点未満を「不合格」、80点以上を「合格」と分けるとすると、xの変数の内容を「合格、不合格、不合格, 合格、合格」と変換したfactor型のオブジェクトを返すのがcut関数だ。

■実際にcut関数を動かしてみる。
上記の例を実際にR上で行ったのが以下。
> x <- c(90, 55, 79, 80, 100)
> cut(x,breaks=c(0,80,100), labels=c("不合格","合格"), right = FALSE, include.lowest = TRUE)

[1] 合格   不合格 不合格 合格   合格  
Levels: 不合格 合格
点数が先ほどの基準に従ってカテゴリ(合格、不合格)に変換されているのが分かる。

■right = FALSEのオプションは?
先のcut使用例で「right=FALSE」のオプションをしている。この説明をしなければならない。
cutのデフォルト動作は、例えばbreaks=c(0,80,100)と指定した場合、
  • (0,80]の区間を不合格
  • (80,100]の区間を合格
とカテゴリ分けする。
ここで丸括弧は開区間、角括弧は閉区間を示す。でも今回は
80点未満を不合格、80点以上を合格としたいから、
  • [0,80)の区間を不合格
  • [80,100)の区間を合格 (注:ここで100がカテゴリ分けに入らないのは後述)
であるべき。このように区間を分けるためにright = FALSE とする。

■include.lowest = TRUEのオプションは?
先のright=FALSEだけでは「100」がカテゴリ分けに含まれない。そこでカテゴリ分けの末端の開区間を閉区間にし、今回の例では100をカテゴリに含むようにするのが、このオプション。

「right = FALSE」「include.lowest = TRUE」を指定することで、今回我々が望む
  • [0,80)の区間を不合格
  • [80,100]の区間を合格
というカテゴリ分けが実現できる。