koRpusライブラリで日本語のTTRを計算する

# はじめに

あるテキストが、どのくらい語彙が豊かかを評価するために、異なり語数(types)と延べ語数(tokens)という数値が使われます。

+ 異なり語数(types): 使われている語の種類の数
+ 延べ語数(tokens): 使われている語の総数

延べ語数が等しいテキストであれば、異なり語数が多いほど語彙が豊かだと考えられます。しかしテキストが長くなればなるほど(つまり延べ語数が多くなればなるほど)、異なり語数も大きくなっていきますので、長さの異なるテキスト同士では、異なり語数を直接比較することはできません。

そこで、テキストの長さに応じて異なり語数を調整した上で比較することが必要になります。最も単純な方法としては、TTR(Type-token ratio)が知られています。TTRは異なり語数Vを延べ語数Nで割ったもので、要するに延べ語数1語あたりの異なり語数を計算しています(従って0〜1の値になります)。

$$TTR=V/N$$

ところが、このような単純な割り算はVとNが比例している場合に初めて成立するものです。実際には、VはNの増加に従って大きくなっていきますが、比例はしていません。そのため、Nが大きくなるほどTTRは小さくなることが知られています。この欠点を補うために、TTRの様々な変種が提案されています。

```math
\begin{eqnarray}
\text{Guiraud's}\ R & = & V/\sqrt{N}\\
\text{Herdan's}\ C & = & \log V/\log N\\
\text{Dugast's}\ U & = & (\log N)^2 / (\log N - \log V)
\end{eqnarray}
```

Rでこれらの語彙多様性指標を計算するには、koRpusライブラリを使用するのが有用です。

https://github.com/unDocUMeantIt/koRpus

koRpusライブラリは様々なテキスト分析を行うためのライブラリで、その中には各種の語彙多様性指標の計算も含まれます。ただし、このライブラリは基本的にテキストをTreeTaggerで解析することを前提としており、日本語の分析には直接使えないようです。ですが、このパッケージの内部関数は単語リスト(文字列ベクトル)か、もしくはNとVの数値を引数として取るようになっているので、この内部関数を直接呼び出せば日本語の分析にも利用可能です。

この記事では、koRpusパッケージに含まれる語彙多様性関係の関数についてまとめます。このパッケージで計算できる指標には、以下のものが含まれます。

+ TTR
+ Herdan's C
+ Guiraud's Root TTR
+ Carroll's Corrected TTR
+ Dugast's Uber Index
+ Summer's index
+ Maas' indices
+ MSTTR
+ MATTR
+ HD-D
+ MTLD
+ MTLD-MA
+ Yule's K

これらの語彙多様性指標の計算式や解説については、以下のページも参照してください。

語彙多様性指標の解説
https://www.rdocumentation.org/packages/koRpus/topics/lex.div

# 語数から計算するもの

TTR、R、CTTR、C、Uber、S、$a^2$などの指標は、計算式にNとVを代入することで計算することができます。koRpusでは、これらの指標については```lex.div.num```というNとVを引数に取る外部関数が用意されているので、内部関数を直接呼び出さなくても計算が可能です。```lex.div.num```は第1引数に延べ語数N、第2引数に異なり語数Vを渡すことで、複数の指標を一括して計算します。```log.base```を指定すると対数を使う指標の底を変えることができます(デフォルトは10)。```quiet=T```は警告メッセージを非表示にします。

```R
> ld <- lex.div.num(1000, 300, log.base = 10, quiet=T)
```

```summary``` を使うと、結果の一覧をdata.frameで確認することができます。

```R
> summary(ld)
       index value
1        TTR   0.3
2 Herdan's C  0.83
3   Root TTR  9.49
4       CTTR  6.71
5 Uber index 17.21
6     Summer  0.83
7     Maas a  0.24
8  Maas lgV0  4.39
```

個々の値を取得するときは```@```を使います。

```R
ld @ TTR
ld @ C.ld
ld @ R.ld
ld @ CTTR
ld @ U.ld
ld @ S.ld
ld @ Maas
ld @ lgV0
ld @ lgeV0
```

# 単語リストから計算するもの

TTRなどの指標がテキスト全体のNとVから直接計算する指標であるのに対して、MSTTR、MVTTR、MTLD、MTLDMAなどの指標はテキストの部分集合についてTTRなどの指標を繰り返し計算し、その平均を求めることによってテキスト全体の語彙多様性を評価します。また、HD-DやYule's Kは繰り返し計算を行う代わりに、確率的にテキストの部分集合の特徴量を計算します。

これらの指標はテキスト全体のNとVだけで計算することはできないので、単語リストから計算する必要があります。koRpusでこれらの指標を計算するための外部関数は基本的に日本語の分析に対応していませんが、内部関数を直接呼び出して単語リスト(文字列ベクトル)を引数に渡すことで、これらの指標を計算することができます。

## MSTTR

MSTTRはMean segmental TTRの略です。テキストを一定の長さの部分(segment)に分割し、各セグメントごとにTTRを計算して、その平均値を計算します。koRpusライブラリでは、以下の内部関数を呼び出すことで、単語リスト(文字列ベクトル)による計算が可能です。第1引数には単語リストを、第2引数にはセグメント長(語数)を指定します。

```R
> koRpus:::MSTTR.calc(words, 42)
$MSTTR
[1] 0.6480331

$TTR.seg
 [1] 0.6904762 0.5714286 0.6904762 0.7380952 0.6428571 0.7619048 0.5476190 0.5714286 0.5238095 0.5714286 0.6904762
[12] 0.5952381 0.6904762 0.6666667 0.6428571 0.6428571 0.6428571 0.6666667 0.5476190 0.8095238 0.7857143 0.7380952
[23] 0.4761905

$dropped
[1] 34

$sd
[1] 0.08732155
```

```.$MSTTR```が各セグメントのTTRの平均値、```.$TTR.seg```が各セグメントのTTR、```.$dropped```はテキスト末尾で余ったため計算に使わなかった語の数です(上の例では、1000語のテキストを42語ごとに分割したため、```1000 %% 42``` = 34語を捨てています)。

## MATTR

MATTRはMoving average TTRの略です。簡単に言うとMSTTRの移動平均バージョンです。一定の長さの枠(window)をテキストの先頭から末尾まで移動させながら、その枠内のTTRを計算し、その値の平均値を求めます。

```R
> koRpus:::MATTR.calc(words, 42)
$MATTR
[1] 0.6632901

$TTR.win
(中略)

$sd
[1] 0.08043257
```

```.$TTR.win``` がwindowごとのTTRで、 ```.$MATTR``` がその平均です。

## HD-D

MSTTRやMATTRがテキストから連続する部分を取り出してTTRを測定したのに対して、テキストから一定数の語をランダム抽出して、そのTTR(の変種)を計算する考え方があります。代表的なものはvocdで、35〜50語の語を抽出し、各語数の時のTTRを計算して、その値からfittingしてDというスコアを求めます。

ところでN語のテキストからランダムにN語を抽出したときの異なり語数の期待値は、実際にランダム抽出を行わなくても超幾何分布(hypergeometric distribution)を使って確率的に計算することができます。この考え方を利用したものがHD-Dで、koRpusでは以下の内部関数で計算できます。第1引数は単語リスト、第2引数はNがいくつのときのVを計算するか指定します。

```R
> koRpus:::hdd.calc(words, 42)
$HDD
[1] 31.50715

$ATTR
[1] 0.7501702

$type.probs
(中略)

$summary
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.04200 0.04200 0.08228 0.13880 0.12090 0.84830 

$sd
[1] 0.1816875
```

私の誤解でなければ、HD-Dはvocdの超幾何分布バージョンであり、Dという指標の値を計算するものです。しかし、koRpusのhddはDの計算は行っておらず、```.$HDD```が異なり語数Vの期待値、```.$ATTR```がTTRの期待値($=v/n$)のようです。```.$type.probs```は語数Nの時に各語が1語以上生起する確率を示しており、その総和が```.$HDD```になっています。

## MTLD / MTLDMA

MSTTR、MATTR、HD-Dが語数NのときのTTRを計算するものだったのに対して、MTLDはTTRが一定の値になる時の語数Nを計算します。MTLDは、テキストの先頭から1語ずつ単語を拾っていき、TTRが一定値に達した時のNを記録します。それをテキストの末尾まで繰り返し、さらにテキストの後方から前方に向かって同様の処理を行って、Nの平均値を計算します。koRpusでは、以下の内部関数で計算できます。第2引数でTTRの値を指定します。

```R
> koRpus:::MTLD.calc(words, 0.65)
$MTLD
[1] 42.83116

$all.forw
[1] NA

$all.back
[1] NA

$factors
    forw     mean     back 
23.00000 23.34749 23.69498 

$lengths
$lengths$forw
 [1] 53 53 71 39 57 30 34 17  2 37 42 47 71 44 36 47 25 61 33 81 59 25 34  1

$lengths$forw.compl
 [1] 53 53 71 39 57 30 34 17  2 37 42 47 71 44 36 47 25 61 33 81 59 25 34

$lengths$mean
[1] 41.64583

$lengths$mean.compl
[1] 42.63043

$lengths$sd
[1] 18.95963

$lengths$sd.compl
[1] 18.36465

$lengths$back
 [1] 14 37 21 62 71 33 16 65 48 17 45 50 54 39 44 31 17 34 31 77 67 53 37 37

$lengths$back.compl
 [1] 14 37 21 62 71 33 16 65 48 17 45 50 54 39 44 31 17 34 31 77 67 53 37
```

MTLDMAはMTLDの移動平均バージョンです。```min.tokens```を指定すると、Nが指定した値に達するまでは、TTRが一定値に達しても無視するようになります(デフォルトは9)。```steps```は移動量を指定します(デフォルトは1)。

```R
> koRpus:::MTLDMA.calc(words, 0.65, min.tokens = 9, steps = 1)
$MTLDMA
[1] 44.98375

(以下略)
```

## Yule's K

Yule's KはTTRとは違った考え方で語彙多様性を評価するもので、大雑把にいうと「テキストからランダムに2語を抽出した時に同一の語である確率」を$10^4$倍したものに相当するようです。確率を用いる点ではHD-Dと似ていますが、HD-DがN語をランダム抽出した時のVの期待値を計算するのに対して、Kは2語をランダム抽出した時にv=1である確率を計算している、と考えることができます。koRpusでは、次の内部関数で計算できます。

```R
> koRpus:::k.calc(words)
[1] 172.04
```

# おわりに

koRpusパッケージを使って、各種の語彙多様性指標を計算する方法をまとめました。TTRなど数式にVとNを代入するだけで計算できるものはともかく、MSTTR、MATTR、MTLDなど複雑な計算工程が必要な指標を手軽に計算できる点は、なかなか便利ではないかと思います。

ところで、語彙多様性指標は非常に多くの種類ものが提案されていますが、それぞれ特徴があり、異なり語数と延べ語数の関係を定式化するのはなかなか難しいようです。また、ここで取り上げた指標は基本的に単語の数しか使用しておらず、個々の語の難易度などは問題としていないため、指標値が同程度のテキストであっても実際に見てみると使用している語彙の難易度にかなりの差があるケースもしばしばあります。この記事で紹介した指標を使うときには、そうした点にも十分に注意することをお勧めします。