本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはhide_o_55さんで、テーマは「自然言語処理」です。
自然言語処理とは
自然言語処理とは、人間が日常のコミュニケーションで使用する自然言語をコンピュータで扱うこと全般を指します。今回は自然言語処理の中でも自然言語で書かれたテキストをコンピュータで解析する手法を中心に、Perlによる自然言語処理について紹介します。
自然言語処理の手法には、大きく分けてルールベースと統計学習ベースの2種類の手法があります。
ルールベースの自然言語処理
ルールベースの自然言語処理は、対象となる言語の文法ルールを人手で定義して、そのルールに基づいて処理を行う方式です。人手でルールを定義するため内部の処理がわかりやすく、調整も可能という長所があります。一方、ルールの定義には高度な専門知識が必要、ルールのメンテナンスコストが大きい、新しい分野への適応が苦手といった短所があります。
統計学習ベースの自然言語処理
統計学習ベースの自然言語処理は、機械学習によりルールを導出して処理を行う方式です。コンピュータの高速化と低価格化により、大量の計算資源が必要となる機械学習による処理が実用的となってきました。学習のための訓練データの作成には専門知識が必要となりますが、ルールの定義よりは容易であり、訓練データを新たに用意して追加学習することによって新しいドメインへの適用を行うことができるという長所があります。一方、ルールベースと比較して処理結果の調整が難しいといった短所があります。今回は主に統計学習ベースの手法を紹介します。
自然言語処理と文字コード
コンピュータで自然言語のテキストを処理するためには、文字コードについて理解しておく必要があります。
文字コードとは
文字コードとは、コンピュータ上で文字を扱うために各文字に割り当てられたビット表現、またはそれらを対応付ける規則のことです。たとえばA、B、C、D、E、Fの6文字を符号化した場合は表1 のようになります。
表1 文字の符号化
文字 ビット表現 バイト表現
A 0001 0x1
B 0010 0x2
C 0011 0x3
D 0100 0x4
E 0101 0x5
F 0110 0x6
符号化文字集合
文字を重複なく集めた集合を文字集合と呼びます。たとえばアルファベットの大文字、小文字を集めたものが文字集合となります。ある文字集合の各文字に対応するビット表現の組み合わせを一意に定めたものを符号化文字集合(coded character set 、CCS)と呼びます。実用されている符号化文字集合としては、ASCII(American Standard Code for Information Interchange ) 、JIS X 0208、Unicodeなどがあります。
文字符号化方式
文字符号化方式(character encoding scheme 、CES)は符号化文字集合で文字に対応付けられたビット表現を、コンピュータで利用できるバイト列に変換する方式のことです。符号化文字集合JIS X 0208に対する文字符号化方式として、ISO-2022-JP、Shift_JIS、EUC-JPなど複数があります。
また、Unicodeでは文字符号化方式と文字符号化形式(character encoding form 、CEF)の2つに分けて標準化されています(表2 ) 。Unicodeの文字符号化形式とは、Unicode符号化文字集合の符号位置に対応付けられた整数値を符号単位列に変換した形式のことです。符号単位はUTF-8が8ビット整数、UTF-16が16ビット整数、UTF-32が32ビット整数となります。
表2 UnicodeのCESとCEF
符号化文字集合 CEF CES
Unicode UTF-8 UTF-8
UTF-16 UTF-16BE
UTF-16LE
UTF-16
UTF-32 UTF-32BE
UTF-32LE
UTF-32
自然言語処理とUnicode
自然言語処理においてはさまざまな言語を扱う可能性があるため、基本的には世界の主要な言語のほとんどの文字を扱えるUnicode(UTF-8)を使用します。Unicodeの符号化方式の中でもUTF-8を使う理由は、ASCIIコードと互換性があるため解析処理で誤動作が発生しないこと、文字コードのエンディアン(バイト列の並び順)を意識する必要がないこと、多くのプラットフォームのデフォルトの文字コードであることなどが挙げられます。
Unicodeの正規化
自然言語を処理する場合には、文字の全角、半角のように表現は違っても意味的に同一であるならば区別せずに処理したいということがあります。このようなときにUnicodeの正規化(Normalize )という処理を行います。
Unicodeの正規化形式としては、NFC、NFD、NFKC、NFKDの4種類が定義されています(表3 ) 。正規化形式は文字の等価性の評価方法と、結合文字を分解するか合成するかの組み合わせです。等価性の評価方法として正準等価と互換等価があります。正準等価は基底文字と結合文字の列と合成済文字とを同一視する方式で、互換等価は正準等価性に加えて全角、半角、上付き、書体の違いを無視して等価性を評価する方式です。日本語の全角、半角を無視した処理を行う場合はNFKCを採用することが多いですが、互換等価性に基づく分解により、もとの情報の一部が失われるので注意が必要です。
表3 Unicodeの正規化形式
名称 説明
NFC(Normalization Form Canonical Composition) 正準等価性に基づいて文字を分解し、再合成を行う。文字の並びが変換前と変わることもあり得る
NFD(Normalization Form Canonical Decomposition) 正準等価性に基づいて文字の分解を行う
NFKC(Normalization Form Compatibility Composition) 互換等価性に基づいて文字を分解し、正準等価性に基づいて再合成を行う
NFKD(Normalization Form Compatibility Decomposition) 互換等価性に基づいて文字の分解を行う
PerlでのUnicodeの扱い方
PerlでUnicodeを扱う場合、UTF-8であればutf8プラグマの指定と、I/Oの際のエンコーディング指定を行います。
use strict;
use warnings;
use utf8;
open my $fh, '<:utf8', 'corpus_ja.txt') or die $!;
...
Unicode の正規化を行いたい場合は、Unicode::Normalizeモジュールを利用します。以下は半角カタカナを全角カタカナに正規化する例です。
use strict;use warnings;
use utf8;
use Unicode::Normalize;
use Encode;
my $src = ' パール';
my $dst = Unicode::Normalize::NFKC($src);
print Encode::encode('utf8', "${src} : ${dst}\n");
# パール : パール
<続きの(2)はこちら 。>