JP2003228571A - 文字列の出現頻度の計数方法およびその方法を利用可能な装置 - Google Patents

文字列の出現頻度の計数方法およびその方法を利用可能な装置

Info

Publication number
JP2003228571A
JP2003228571A JP2002026458A JP2002026458A JP2003228571A JP 2003228571 A JP2003228571 A JP 2003228571A JP 2002026458 A JP2002026458 A JP 2002026458A JP 2002026458 A JP2002026458 A JP 2002026458A JP 2003228571 A JP2003228571 A JP 2003228571A
Authority
JP
Japan
Prior art keywords
class
character string
suffix
document
frequency
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
JP2002026458A
Other languages
English (en)
Inventor
Kyoji Umemura
恭司 梅村
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Individual
Original Assignee
Individual
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Individual filed Critical Individual
Priority to JP2002026458A priority Critical patent/JP2003228571A/ja
Publication of JP2003228571A publication Critical patent/JP2003228571A/ja
Pending legal-status Critical Current

Links

Landscapes

  • Complex Calculations (AREA)
  • Machine Translation (AREA)
  • Document Processing Apparatus (AREA)
  • Information Retrieval, Db Structures And Fs Structures Therefor (AREA)

Abstract

(57)【要約】 【課題】 文字列を2回以上含む文書の数を計数する効
率的な方法がなかった。 【解決手段】 Suffix Array生成部12は、文書データ
ベース24に格納された複数の文書ファイル26につい
てsuffixを求め、すべてのsuffixの集合を辞書順に並べ
たSuffix Arrayを生成し、Suffix Arrayファイル28と
して文書データベース24に格納する。文字列頻度計数
部14は、Suffix Arrayファイル28を参照して、suff
ixのクラス分けのクラス検出と、各クラスについての文
字列の重複度判定とを行い、重複度つき文字列頻度を計
数する。文書頻度算出部16は、文字列頻度計数部14
により計測された重複度つき文字列頻度の差分により文
字列がk回以上出現するドキュメントの頻度を求める。

Description

【発明の詳細な説明】
【0001】
【発明の属する技術分野】この発明は記号列の出現頻度
を計数する技術、とくに文書中に含まれる文字列の出現
頻度を計数する方法、およびその方法を利用可能な装置
に関する。
【0002】
【従来の技術】インターネットの普及に伴い、各種デー
タベースのネットワーク環境での利用が進んでおり、文
献データベースをもとにした電子図書館など実用的なア
プリケーションも広がっている。このような電子化され
た文書を多数蓄積したデータベースを効率よく利用する
ためには、蓄積された文書から適切なキーワードを抽出
して、検索しやすいようにインデックスをつけたり、キ
ーワードにもとづいて文書を分類することが必要であ
る。
【0003】日本語のような膠着言語ではキーワードを
抽出する際、文書をまず単語列に分解することが行われ
る。単語の切れ目を判定するために、形態素解析が用い
られることがあるが、単語を正しく切り出すためには単
語辞書を充実させたり、複雑な文法規則を適用するな
ど、形態素解析の精度を向上させる必要がある。またイ
ンデックスとなる適切なキーワードを抽出するには、単
語の出現パターンを統計的に解析して、文書を特徴づけ
る有用な単語を選択する必要がある。
【0004】このような統計的な解析にあたって、文書
中に含まれる文字列の出現頻度等の統計量が利用され
る。たとえば文書の集合が与えられたとき、ある文字列
の総出現回数cfやある文字列を1回以上含むドキュメ
ントの数dfが統計量として用いられる。文献 Mikio Y
amamoto and Kenneth W. Church, Using Suffix Arrays
to Compute Term Frequency and Document Frequency f
or All Substrings ina Corpus, Computational Lingui
stics, Vol.27:1, pp.1-30, MIT Press.には、ある文字
列を1回以上含むドキュメントの数dfを求める方法が
開示されている。
【0005】
【発明が解決しようとする課題】このような文字列に関
する統計量を計測する場合、計算量が問題となる。扱う
文書の集合(以下コーパスという)の総文字数Nは非常
に大きなものとなり、その部分文字列はN(N−1)/
2個になるため、単純な計数方法を用いると通常の計算
機では処理できない計算量となってしまう。
【0006】上記のMikio Yamamoto and Kenneth W. Ch
urchによる文献では、文字列の出現パターンにもとづい
て、部分文字列を最大2N−1個のクラスに分類して、
ドキュメント頻度を計数する方法が提案されている。し
かしこの方法はある文字列が1回以上出現するドキュメ
ントの数を計測するものであり、ある文字列が2回以上
出現するドキュメントの数の計測には適用することがで
きない。文字列に関してより意味のある統計量は、その
文字列が2回以上出現するドキュメントの数から得られ
ることがあるが、これを効率的に計数する方法は知られ
ていない。
【0007】本発明はこうした状況に鑑みてなされたも
のであり、その目的は、文字列の出現頻度を効率よく計
測するための計数方法、およびその方法を利用可能な計
数装置を提供することにある。
【0008】
【課題を解決するための手段】本発明のある態様は文字
列の出現頻度の計数方法に関する。この方法は、文書の
集合に対して、文字列がk(kは2以上の自然数)回以
上出現する回数と前記文字列がk+1回以上出現する回
数とを計数してそれらの回数の差を求めることにより、
前記文字列がk回以上含まれる文書の数を取得する。
【0009】ここでいう「文書」は言語を問わない。
「文書」は、古文書や暗号文書のようにかならずしも文
字や文法が解読されていない文書や、遺伝子配列など任
意の記号列のシーケンスも含み、任意の記号列が記録さ
れたファイル全般を意味する広い概念である。したがっ
て文書中に含まれる「文字列」という場合、言語のアル
ファベット等に限らず、一つの記号体系をなす任意の記
号列を含む趣旨である。
【0010】前記文書内に含まれる部分文字列の集合
を、同一クラスに属する部分文字列についてはその部分
文字列が同一文書に出現する回数が同じになるようなク
ラスに分類しながら、前記出現回数を前記クラス単位で
計数してもよい。前記クラスの階層構造を利用して、下
位クラスにおいて計数された出現回数を上位クラスにお
いて計数される出現回数に加算することにより前記出現
回数の計数を行ってもよい。
【0011】本発明の別の態様も文字列の出現頻度の計
数方法に関する。この方法は、複数の文書を含むコーパ
スに対して、前記文書のある位置の文字から前記文書の
終了までの範囲の文字列、すなわち接尾辞(サフィック
ス)の集合であって、その集合が辞書順に並べられたサ
フィックスアレイ(Suffix Array)を生成する工程と、
与えられた文字列xの出現のうち、重複度がk(kは2
以上の自然数)以上の文字列の出現頻度cf(x)を
計数する工程と、前記文字列xがk回以上出現する文書
の数df(x)をcf(x)とcfk+1(x)の
差により求める工程とを含む。
【0012】サフィックスアレイはサフィックスのコー
パス中の出現場所を格納した配列である。重複度は、文
字列xの出現場所ごとに定義される値であり、ある文字
列xの出現場所の重複度がkであるとは、サフィックス
アレイ内の配列の番号順でその出現場所以下の場所で、
かつ同一のドキュメントに属する文字列xの出現場所が
k個あることをいう。
【0013】前記サフィックスアレイのクラス分けであ
って、同一クラスに属する文字列についてはその文字列
が同一文書に出現する回数が同じになるようなクラス分
けを生成する工程をさらに含み、前記クラス分けによる
各クラスについて前記出現頻度cf(x)を計数して
もよい。前記クラス分けを生成する工程により、階層構
造をなすクラス分けが生成され、前記出現頻度cf
(x)を計数する工程において、下位クラスにおいて
計数された出現頻度cf(x)が上位クラスにおいて
計数される出現頻度に加算されてもよい。
【0014】前記出現頻度cf(x)を計数する工程
における重複度の判定と、前記クラス分けを生成する工
程におけるクラスの検出とが同時になされてもよい。ク
ラスがサフィックスアレイの添え字の区間で定められる
とき、新しいクラスの区間の始まりと終わりを検出する
過程で、検出されたクラスごとに重複度を判定して出現
頻度cf(x)の計数を行ってもよい。
【0015】本発明のさらに別の態様は計数装置に関す
る。この装置は、文書の集合に対して文字列の出現頻度
を計数する計数処理部と、前記文字列の出現頻度に関す
るデータを記録する記録部とを含む。前記計数処理部
は、前記文書のある位置の文字から前記文書の終了まで
の範囲の文字列の集合であって、その集合が辞書順に並
べられたサフィックスアレイを生成するサフィックスア
レイ生成部と、前記サフィックスアレイのクラス分けの
クラスの検出と同時に、前記文字列の出現の重複度の判
定を行うことにより、前記クラス単位で前記文字列が重
複して出現する頻度を計数する文字列頻度計数部と、前
記文字列の出現頻度にもとづいて前記文字列が出現する
文書の頻度を算出する文書頻度算出部とを含む。
【0016】前記サフィックスアレイの各サフィックス
は、当該サフィックスと同一文書に属し、かつ前記サフ
ィックスアレイの配列順で当該サフィックスの直前にあ
るサフィックスへのポインタをもち、前記文字列頻度計
数部は、このポインタを前記重複度の回数だけ順次たど
ることができるか否かにより前記重複度の判定を行って
もよい。
【0017】前記文字列頻度計数部は、前記サフィック
スアレイを階層的なクラス構造にクラス分けし、下位ク
ラスにおいて計数された前記文字列の前記出現頻度を上
位クラスにおいて計数される前記出現頻度に加算しても
よい。
【0018】前記文書頻度算出部は、前記文字列がk
(kは自然数)回以上出現する文書の頻度を、前記文字
列についての前記重複度がk以上の出現頻度と前記重複
度がk+1以上の出現頻度との差により求めてもよい。
【0019】前記文字列がk(kは自然数)回以上出現
する文書の頻度を用いて前記文書からキーワードを抽出
するキーワード抽出部をさらに含んでもよい。とくに文
字列が2回以上出現する文書の頻度が用いられてもよ
い。
【0020】本発明のさらに別の態様はコンピュータプ
ログラムに関する。このプログラムは、複数の文書を含
むコーパスに対して、前記文書のある位置の文字から前
記文書の終了までの範囲の文字列の集合であって、その
集合が辞書順に並べられたサフィックスアレイを生成す
る工程と、前記サフィックスアレイの階層的なクラス構
造に係るクラスを検出するとともに、そのクラス単位
で、与えられた文字列xの出現のうち、重複度がk(k
は2以上の自然数)以上の文字列の出現頻度cf
(x)を計数する工程と、下位クラスにおいて計数さ
れた出現頻度cf(x)を上位クラスにおいて計数さ
れる出現頻度に加算する工程と、前記文字列xがk回以
上出現する文書の数df(x)を、前記文字列につい
ての前記重複度がk以上の前記出現頻度cf(x)と
前記重複度がk+1以上の前記出現頻度cf
k+1(x)との差により求める工程とをコンピュータ
に実行させる。
【0021】本発明のさらに別の態様は記号列の出現頻
度の計数方法に関する。この方法は、記号のシーケンス
が複数含まれる集合に対して、前記シーケンス内に含ま
れる部分記号列の集合を、同一クラスに属する部分記号
列についてはその部分記号列が同一シーケンスに出現す
る回数が同じになるような階層的なクラスに分類しなが
ら、任意の記号列がk(kは2以上の自然数)回以上出
現する回数を前記クラス単位で計数し、前記任意の記号
列がk回以上含まれる前記シーケンスの数を求める。
【0022】なお、以上の構成要素の任意の組合せ、本
発明の表現を方法、装置、サーバ、システム、コンピュ
ータプログラム、記録媒体などの間で変換したものもま
た、本発明の態様として有効である。
【0023】
【発明の実施の形態】実施の形態に係る計数方法と計数
装置を説明する前に、記号の定義と概念の説明を行う。
【0024】1. 記号の定義 tf(d,x)を、ドキュメントdに含まれる文字列x
の個数と定義する。以下の二つの統計量は、tf(d,
x)から計算できるものであり、情報検索に通常用いら
れる統計量である。 cf(x):コーパスに文字列xが出現する数 cf(x)=Σtf(d,x) df(x):文字列xが1回以上出現するドキュメント
の数 df(x)=|{d|tf(d,x)≧1}|
【0025】本発明において利用する以下の統計量もt
f(d,x)から求められる。 df(x):文字列xが2回以上出現するドキュメン
トの数 df(x)=|{d|tf(d,x)≧2}| df(x):文字列xが3回以上出現するドキュメン
トの数 df(x)=|{d|tf(d,x)≧3}| 一般に、df(x):文字列xがk回以上出現するド
キュメントの数 df(x)=|{d|tf(d,x)≧k}|
【0026】ここで、df(x)の主要な利用法は、
「ドキュメントの分布において、ある文字列をドキュメ
ントが1回以上含むことを条件としたとき、その文字列
が2回以上含まれる条件付き確率の推定値」としてdf
(x)/df(x)の計算に用いることである。文献
[6]に示されているように、この条件付き確率は、単
語に適用した場合、語の性質を表すものとして使うこと
ができる。dfおよびdfは、dfの拡張であ
り、同様の条件付き確率の推定に使用でき、推定値のク
ロスチェックに使用することができる。
【0027】2. Suffix Array Suffix Arrayは文献[1]によって示されたデータ構造
である。図1の例に示すように、このデータ構造はある
テキストが与えられたときに、そのテキストのある位置
の文字からコーパスの終了までの範囲の文字列(これを
接尾辞(suffix)とよぶ)の集合を考え、その集合を辞
書順に並べたものである。どのsuffixも開始場所により
一意に定まるため、テキストの本体がメモリにあるとす
ると、一つのを格納するのに、文字列の開始場所を示す
一つの整数を格納すればよい。同図の例においてテキス
ト「abcabedcabcde」に対して、suffix
[6]は「cabcde」であり、開始場所はテキストの
配列の第7列であるから、suffix[6]の値は7である。
このように、Suffix Arrayを用いれば、任意の部分文字
列の場所を知ることができるにもかかわらず、必要な記
憶容量はテキストのサイズをNとするとO(N)(Nの
オーダー)で済む。
【0028】Suffix Arrayは以下のルーチンで生成でき
る。 /* size:コーパスの文字数, text:コーパスの先頭を指すポインタ*/ int suffix_compare(struct suffix_struct * x, struct suffix_struct * y) { return strcmp(text + x->position, text + y->position); /* x->position,y->positionはそれぞれx,yに対応する場所を指すポインタ*/ } for(i=0;i<size;i++) { suffix[i].position = i; } qsort(suffix, size, sizeof(struct suffix_struct),suffix_compare);
【0029】ドキュメント頻度を計算する場合は、ドキ
ュメントの長さに上限があればコーパス中の文字列はド
キュメント毎に区切られていると見なすことができる。
この条件では上記のアルゴリズムを使ってデータ構造を
作成するためには、O(NlogN)の時間が必要であ
る。
【0030】一般にコーパスがドキュメントの構造をも
たないとき、単純な方法では、文字列の比較計算の上限
を見積もることが難しいが、Suffix Arrayを生成する効
率の良いアルゴリズムが知られており(文献[2])、
この方法によると、Suffix Arrayの作成の計算量はO
(NlogN)である。
【0031】このデータ構造により、任意の文字列を与
え、その文字列が出現する場所を特定するために2分探
索ができ、O(logN)の時間で出現場所のリストが
求められる。ここでいう出現場所とは、コーパス内のあ
る部分と一対一で対応する整数値であり、Suffix Array
の性質から、これはある一つのsuffixにも対応する。
【0032】3. 文字列のクラス分け 実施の形態に係る計数アルゴリズムでは、文献[3]の
文字列のクラス分けの方法を使用する。同一クラスに属
する文字列xについて、tf(d,x)の値が同じにな
るようにクラス分けする。このクラス分けはsuffixを用
いて定義する。Suffix Arrayのsuffixは辞書順に並んで
いるので、文字列の先頭部分が次のsuffixと共通である
ことが多い。そこで、common[i]をsuffix[i]とsuffix[i
+1]の文字列の先頭からの共通部分の長さとする。クラ
スの定義を下に示す。
【0033】ここで、定義の記述を簡単にするためj−
1<iの場合mink=i j−1=∞とする。そしてco
mmon[-1]=-1、common[N]=-1とする。区間[i,j]の境
界でのcommonの値の大きい方をoutgoing(i,j)=max(comm
on[i-1],common[j])と定義し、区間[i,j]の内部で
のcommonの値のうち最小のものをinner(i,j)=mink=
j−1(common[k])と定義する。
【0034】[定義]区間[i,j]がクラスを形成す
るとは、inner(i,j)>outgoing(i,j)であることをいう。
inner(i,j)は区間全体で共通部分となる文字列の長さで
あり、inner(i,j)>outgoing(i,j)であるとは区間を広げ
ると全体で共通となる文字列が短くなることを意味す
る。
【0035】図2のSuffix Arrayの例において、各suff
ixに対するcommonの値が示されている。この例で区間
[i,j]=[2,2]、[i,j]=[1,4]、お
よび[i,j]=[1,3]がそれぞれクラスを形成す
るかどうかを考える。
【0036】 outgoing(2,2)=max(common[1],common[2])=max(6,3)=6 inner(2,2)=mink=2 (common[k])=∞ outgoing(1,4)=max(common[0],common[4])=max(2,0)=2 inner(1, 4)=mink=1 (common[k])=3 outgoing(1,3)=max(common[0],common[3])=max(2,6)=6 inner(1,3)=mink=1 (common[k])=3 となり、区間[2,2]はinner(2,2)>outgoing(2,2)、
区間[1,4]はinner(1,4)>outgoing(1,4)となるので
クラスを形成するが、区間[1,3]はinner(1,3)<out
going(1,3)となるのでクラスを形成しない。図3に区間
[1,4]の場合を図示した。このようにして区間ごと
にクラスが形成するかどうかを判定すると、図4に示す
区間においてクラスが形成される。同図に示した区間
[0,0]、[1,1]、[2,2]、[1,2]など
はすべてクラスを形成しており、後述のようにクラスを
形成する区間は階層構造をなす。
【0037】区間[i,j]がクラスを形成するとき、
区間[i,j]に共通する長さoutgoing(i,j)+1からinn
er(i,j)までの部分文字列の集合を、その区間に対応す
る文字列のクラスと定義する。図4の例における区間
[1,4]、[1,2]、[1,1]のクラスに属する
文字列を図5に示す。区間[1,4]ではoutgoingの値
は2で、innerの値は3であるから、文字列「aab」
がクラスの要素である。区間[1,2]ではoutgoingの
値は3で、innerの値は6であるから、文字列「aab
b」、「aabbc」、「aabbcc」がクラスの要
素である。区間[1,1]ではoutgoingの値は6で、in
nerの値は無限大であるから、文字列「aabbcc
d」、「aabbccdd」、・・・(以下続く)がク
ラスの要素である。
【0038】以下、文字列の出現パターンというとき、
文字列xとドキュメントdが与えられたとき、tf
(d,x)の関数形のことをいう。一般に、長さNのテ
キストの部分文字列はN(N−1)/2個あり、そのす
べてを表にすることは実際的ではないが、同じ出現パタ
ーンを持つものに分類すると、その数は減る。文献
[3]によると、クラスの数は最大でも2N−1個であ
り、これは分類表を実際に作成し記憶することができる
実際的な大きさである。
【0039】[Occurence(C)の定義]クラスCで定まる
区間[i,j]について、集合suffix[i], ・・・, suf
fix[j]をOccurence(C)とする。
【0040】[性質1]クラスCがあったとき、Cの任
意の2要素x、yについて、任意のドキュメントをdと
すると、tf(d,x)=tf(d,y)である。証
明:tf(d,x)を計算するときに、xの属するCに
ついて、xの出現する位置の集合Occurrence(C)を求め
て、それからtf(d,x)を決定できる。yがxと同
じクラスの属していれば、それはOccurence(C)が同じで
あるため、tf(d,x)=tf(d,y)となる。
【0041】この性質により、図5に示した各クラスに
ついて、各クラスの任意の要素が同一ドキュメントに含
まれる個数tfが図示したように求められる。たとえば
区間[1,2]について、そのクラスの要素「aab
b」、「aabbc」、「aabbcc」が同一ドキュ
メントに含まれる個数tfはこの区間の長さ2に等しく
なる。
【0042】[性質2]クラスCがあったとき、Cの任
意の2要素x、yについて、 df(x)=df(y) df(x)=df(y) df(x)=df(y)(n≧3) cf(x)=cf(y) が成立する。
【0043】証明:性質1より、tf(d,x)=tf
(d,y)なので、 df(x)={d|tf(d,x)≧1}={d|tf
(d,y)≧1}=df(y) df(x)={d|tf(d,x)≧2}={d|t
f(d,y)≧2}=df(y) df(x)={d|tf(d,x)≧n}={d|t
f(d,y)≧n}=df(y) cf(x)=Σtf(d,x)=Σtf(d,y)
=cf(y)
【0044】[性質3]すべての部分文字列は、高々2
N−1のクラスに分類できる。証明は文献[3]にある
が、その概略は、一度しか出現しない文字列のクラスが
N個あり、どんなに重複しても高々N−1しか重複した
クラスを構成できないことを示して、この性質を証明す
る。
【0045】4. クラスの階層関係 区間[i1,j1]がクラスC1を形成し、区間[i
2,j2]がクラスC2を形成していて、区間[i1,
j1]が区間[i2,j2]に含まれているとき、C1
はC2の下位のクラスと定義する。また、C2はC1の
上位のクラスと定義する。
【0046】[性質4]二つのクラスC1、C2に交わ
りがあったときには、C1はC2の上位のクラスである
かC1はC2の下位のクラスであるかのどちらかであ
る。
【0047】証明 C1とC2に交わりがあるということは、 i1≦i2≦j1≦j2 (1) i2≦i1≦j2≦j1 (2) i1≦i2≦j2≦j1 (3) i2≦i1≦j1≦j2 (4)のいずれかである。
【0048】(1)の場合、i1<i2であると仮定す
る。区間[i1,j1]では max(common[i1-1],common[j1]) < mink1=i1
j1−1(common[k1]) となるので、common[j1]<common[k1](i1≦k1≦j
1−1)である。一方、区間[i2,j2]では、k1
=i2−1、k2=j1(i2≦k2≦j2−1)とな
るk1、k2が存在する。従って、 common[k1]=common[i2-1]>common[k2]=common[j1] となり、区間[i2,j2]は max(common[i2−1],common[j2]) < mink2=i2
j2−1(common[k2]) を満たさず、i1<i2の場合クラスC2を形成しない
のでC1とC2に交わりはない。
【0049】i1=i2≦j1≦j2の場合はクラスの
階層の定義より、C2がC1の上位クラスである、また
は、等しいクラスである。
【0050】(2)の場合も(1)と同様に証明でき
る。また、(3)の場合はクラスの階層の定義より、C
1がC2の上位クラスであるか等しいクラスであり、
(4)の場合は、C2がC1の上位クラスである、また
は、等しいクラスである。
【0051】以上より、2つのクラスに交わりがある場
合は、一方がもう一方の上位クラス、または、下位クラ
スとなる。
【0052】[性質5]Suffix Arrayにおいて、すべて
のsuffixはクラスによって階層構造を形成する。 証明 common[−1] = common[N]= −1より、最上位クラスは、
すべてのsuffixを含むクラスである。また、性質4より
あるクラスが他のクラスの部分クラスでない限り交わる
ことはない。このとき、部分クラスでは上位クラスより
その区間が短くなる。
【0053】以上のことから、すべての文字列の出現場
所は文字列クラスによって階層構造を形成する。
【0054】[性質6]任意の区間[i,j]につい
て、[i,j]を含む区間でクラスを形成する区間があ
る。区間[i,i]においてoutgoing(i, i)<∞、inner
(i, i)=∞なので、inner(i,i) > outgoing(i,i)とな
り、区間[i,i]は1つのsuffixからなる最下位クラ
スを形成する。 証明 性質5より、Suffix Arrayのすべてのsuffixはクラスに
よって階層構造を形成する。
【0055】[記号]任意の区間[i,j]について、
それを含むクラスを形成する区間のうち、もっとも下位
のものを[i,j]から定まるクラスとし、Class*([i,
j])と記述する。
【0056】任意の区間について、それを含むもっとも
下位のクラスが一意に定まることは、後述のように計算
量を抑えた計数アルゴリズムを構成するときに必要な性
質である。
【0057】5. ドキュメント頻度の計測における問
題点 すべてのクラスについて、それに属する文字列のドキュ
メント頻度を単純な方法で求めるとすると、通常の計算
機では実用上問題がある。クラスの大きさが高々2Nで
あったとしても、df(x)、df(x)、df
(x)を計測するときのように、それぞれの統計量の
定義に則した条件を満たす集合を作って、その大きさを
計測すると、各xの処理にO(N)の時間がかかり、x
がN個あれば、全体ではO(N)の時間が必要とな
る。これは、コーパスの大きさから考えて、通常の計算
機では実行できない処理となる。
【0058】Suffix Arrayを用いると、文字列の出現場
所が特定でき、その特定できた場所についてのドキュメ
ントの数を数えれば、任意の文字列に対するドキュメン
ト頻度を計算できる。これを使えば、単純な方法に比べ
て高速化ができる。しかし、これでも頻度が大きな文字
列を多く含むケースでは実用的ではない。文字列の出現
場所が特定できても、その文字列を含むドキュメントの
数を求めるには、ある出現場所が同じドキュメント内に
存在しないかどうか、重複を調べる必要がある。重複を
調べる処理は、出現場所の多い文字列に対しては時間が
かかる。すべての文字列のドキュメント頻度を計算する
には、一文字のように高頻度の文字列についての計算も
含まれ、そのような文字列が計算のボトルネックとな
る。
【0059】単純な出現頻度であれば、クラス階層に従
って頻度の合計を求めることができるが、その文字列が
出現するドキュメントの数は、直接寄せ集めることがで
きない。たとえば、図6(a)のようなコーパスについ
て考える。文字列「abc」はコーパス全体で6回出現
し、それが出現するドキュメントの数は4個である。ま
た、文字列「abx」はコーパス全体で7回出現し、そ
れが出現するドキュメントの数は5個である。このとき
文字列「ab」に続く文字のパターンが「abc」と
「abx」の二つだけであったとすると、図6(b)に
示すように、「ab」の出現回数cf(ab)は、cf
(abc)+cf(abx)により計算され、13回で
ある。しかし、「ab」が出現するドキュメントの数d
f(ab)は、df(abc)+df(abx)により
計算すると、9となり間違いである。これは「abc」
と「abx」の両方が出現するドキュメントを重複して
数えているからであり、正しくは6である。もし、ドキ
ュメントを計測する条件が、2回以上出現するドキュメ
ント数であった場合、クラスの上下によるドキュメント
頻度の変化はさらに複雑になり、重複を避けて数えるこ
とは困難になる。
【0060】6. 出現場所の重複度 ドキュメント頻度の計数を行う準備として、文字列の出
現場所ごとの重複度を定義する。重複度を導入する目的
は、ドキュメント頻度の計測のために、クラスの階層を
たどる過程で加算することのできる新たな統計量を定義
し、その統計量の関数としてドキュメント頻度を求める
ことを可能にするためである。
【0061】すべての文字列の出現場所は、Suffix Arr
ay内の配列の番号で順序づけることができる。この順序
をsuffix順と定義し、これを利用して文字列の出現場所
の重複度を定義する。
【0062】[定義]ある文字列xの出現場所の重複度
がkであるとは、suffix順でその出現場所以下の場所
で、かつ同一のドキュメントに属する文字列xの出現場
所がk個あることとする。
【0063】図7(a)、(b)に重複度の例を示す。
図7(b)に示されたSuffix Arrayのsuffix順でabx
(suffix[3])以下の場所にあるのは、abc(suffix
[0])、abd(suffix[1])、abe(suffix[2])、および
abx(suffix[3])である。ここで、suffix[3]につい
て、図7(a)に示されたドキュメント#1での文字列
「ab」の重複度kを求めると、ドキュメント#1中に
文字列「abc」、「abd」、「abx」が出現する
ので、k=3である。同様にして他のsuffixについても
重複度kを求めた結果が図7(b)に示されている。
【0064】[性質7]文字列xがドキュメントiにt
個出現するとき、t個の出現場所について、すべて重複
度を求め、それをsuffix順に並べると1,・・・,tと
なる。
【0065】7. 重複条件つき文字列頻度 [記号]xを文字列としたとき、重複度つき文字列頻度
をcf(x)、重複度つきドキュメント文字列頻度を
tf(d,x)と書く。 [定義]cf(x)はコーパスの中で、文字列xの出
現のうち、重複度がk以上の文字列の出現頻度とする。 [定義]tf(d,x)はドキュメントdの中での文
字列xの出現のうち、重複度がk以上の文字列の出現頻
度とする。
【0066】[性質8] ∀x,y∈C,∀k;∀d;tf(d,x)=tf
(d,y) 性質8は、両辺ともCの出現Occurence(C)のうちdに含
まれかつ、重複度がkであるものの個数であることから
明らかである。
【0067】8. 重複条件つき文字列頻度とドキュメ
ント頻度の関係 ドキュメント頻度と重複条件つき文字列頻度には下の単
純な関係がある。 [定理「文字列頻度とドキュメント頻度の関係」] df(x)=cf(x)−cfk+1(x)
【0068】証明 tf(d,x)=tのとき、k≦tについて、 tf(d,x)−tfk+1(d,x)=1 tf(d,x)=tのときtf(d,x)=1,tf
t+1(d,x)=0,・・・であるから、k>tにつ
いて、 tf(d,x)−tfk+1(d,x)=0 cf(x)=Σtf(d,x)であるので、 cf(x)−cfk+1(x) =Σ(tf(d,x)−tfk+1(d,x)) =|{d|tf(d,x)≧k}| =df(x)
【0069】あるコーパスにおいて、cfとdf
実際に求めた例を図8(a)、(b)に示す。コーパス
は図8(a)のように3つのドキュメント#1、#2、
#3を含み、各ドキュメントについて文字列「ab」、
「abc」の出現頻度は、tf(1,ab)=7、tf
(1,abc)=3、tf(2,ab)=8、tf
(2,abc)=5、tf(3,ab)=6、tf
(3,abc)=3である。
【0070】このコーパスについて文字列「ab」、
「abc」の重複度つき文字列頻度cfをもとめ、そ
の値からドキュメント頻度を求めた結果が図8(b)に
示されている。cf(ab)=1、cf(ab)=
3、cf(ab)=6より、df(ab)=cf
(ab)−cf(ab)=3−1=2、df(a
b)=cf(ab)−cf(ab)=6−3=3と
なる。またcf(abc)=1、cf(abc)=
2、cf(abc)=5より、df(abc)=c
(abc)−cf(abc)=2−1=1、df
(abc)=cf (abc)−cf(abc)=
5−2=3となる。
【0071】[性質9]あるクラスCがあったとき、そ
の要素x,yについては任意のkについて、 cf(x)=cf(y) が成り立つ。 証明 cf(x)=Σtf(d,x)、tf(d,
x)=tf(d,y)より、cf(x)=Σtf
(d,x)=Σtf(d,y)=cf(y)
【0072】9. 重複度判定のためのデータ構造 それぞれのsuffixについて、同じドキュメントに属し、
かつsuffix順で前にある最も近いsuffixの順位をprevio
usリンクとして記録しておく。もしそのような場所がな
ければ、−1をpreviousリンクとする。このpreviousリ
ンクのデータ構造はコーパスの大きさに比例した大きさ
のメモリ領域である。
【0073】文字列xの出現場所の重複度がk以上であ
ることの判定は、その出現場所からpreviousリンクをk
回たどれるかどうかと、たどれる場合、k回たどった先
の場所においてその文字列がまだ出現しているかを計測
することで判定することができる。
【0074】図9(a)、(b)、(c)はpreviousリ
ンクの説明図である。図9(a)、(b)はコーパスに
含まれる2つのドキュメント#234、#235であ
る。図9(c)はコーパスのSuffix Arrayを示す。図9
(a)、(c)にはドキュメント#234内でsuffix[1
2405]のpreviousリンクをたどった様子が矢印で示され
ている。また同様に図9(b)、(c)にはドキュメン
ト#235内でsuffix[12494]のpreviousリンクをたど
った様子が矢印で示されている。
【0075】このようなpreviousリンクのデータ構造を
作るには、ドキュメント数と同数の整数配列を用意し
て、それぞれの文字列の出現ごとに、ドキュメントの番
号を求め、その配列からpreviousリンクの情報を求める
と同時に、その表を現在の場所に更新すればよい。
【0076】previousリンクのデータ構造を作成するに
は、ドキュメント数と同じメモリ領域を用意し、コーパ
ス全体を一度スキャンすることになる。これは以下のプ
ログラムで生成できる /* id_max:ドキュメント数、size:コーパスの文字数*/ for(i=0;i<id_max;i++) { last_suffixes[i] = -1; } for(i=0;i<size;i++) { suffix[i].previous_suffix = last_suffixes[suffix[i].id]; last_suffixes[suffix[i].id] = i; }
【0077】重複判定は、このpreviousリンクをk回た
どることができ、かつその文字列が同じドキュメントに
あるかどうかで判定することができる。実施の形態に係
る計数プログラムでは、計算量を押さえるため、単純に
重複度を判定するのではなく、後述のように重複度の判
定とクラスの検出の処理を同時に行う。
【0078】10. クラス検出のアルゴリズム クラスを検出するアルゴリズムの概略を以下に示す。 (1)Suffix Arrayはsuffix順が小さいものから順に調
べる。 (2)クラスの開始場所を見つける。 (3)クラスの終了場所を探す。 (3−a)クラスは入れ子になっているため、そのクラ
スの終了場所が見つかる前に、他のクラスの開始場所が
見つかることがある。この場合は、スタックにその開始
場所をプッシュする。 (3−b)クラスの終了場所が見つかれば、報告しスタ
ックを回復する。
【0079】上記のアルゴリズムでクラスを求めていく
とき、求めるクラスの先頭が発見できていて、まだその
終わりが発見できないクラスを「計算中のクラス」と呼
ぶことにする。アルゴリズム上は、スタック中のクラス
が現在の「計算中のクラス」に相当する。
【0080】common[i]はコーパスの文字列と同じ大き
さの配列で、Suffix Arrayで次のsuffixと文字列が一致
している長さである。この配列の計算時間は、一致して
いる長さが長いときには多いが、文献[2]の方法では
Suffix Arrayを計算すると同時に、common[i]が求めら
れる。したがって、計算量のオーダーを増やすことはな
い。
【0081】文字列のクラスは、common[i]の増減にし
たがう。common[i]が増加したときは、現在計算中のク
ラスを計算終了していないクラスとして登録し、新しい
クラスが開始したものとして処理する。
【0082】一方、common[i]が減少しているときは次
の2つのケースがある。 (1)現在のクラスは終了するが、実は現在のクラスと
同じsuffixの場所から始まったクラスが、現在のクラス
以外にもある場合、(2)現在のクラスを終了し、スタ
ックトップのクラスの処理を継続しなければならない場
合。
【0083】2番目のケースで、スタックトップの計算
途中のクラスの処理を継続するときには、このクラスが
すぐに終了するかどうかの検査から処理を継続する。
【0084】クラスの発見をするにはcommon[i]ごと
に、クラスの終了判定の操作を行うことになる。2番目
のケースでは、計算途中のクラスの数だけ繰り返しが起
きるが、その繰り返しの数を合計してもクラスの最大数
を越えることはない。したがって、クラスの最大数とco
mmon[i]の個数からこの操作はO(N)の計算量で完了
する。
【0085】現在計算中のクラスについて、以下の性質
が成り立つ。 [性質10]現在計算中のsuffixから始まり、ドキュメ
ントの区切りまでの文字列を属するクラス毎に分類する
と、そのクラスは現在計算中のクラスとなる。
【0086】11. 単純な重複条件つき文字列頻度の
計数 重複度kが与えられていたとき、すべての文字列xに対
して重複度がk以上であるcf(x)を求めることを
考える。重複度は文字列と場所の関数であるが、同一ク
ラスに属する文字列の重複度が異なることはない。ま
た、同一クラスに属する文字列について、cf(x)
は等しい。そこでクラスの数だけのカウンタを用意し、
各suffixについて処理を行うことでも計数できる。これ
を「単純な方法」と呼ぶ。この方法に要するメモリ領域
はO(N)であるが、計算時間が問題となる。
【0087】計数の方法は、ある場所について、そこか
ら始まるクラスの集合を求め、すべてのクラスに対して
カウンタを用意し、クラス毎に重複度がk以上であるか
を判定して、カウンタに1を加えるというものである。
この方法を単純に行うと、一つのsuffixに関連するクラ
スが多数になり得るため、O(Nlog(N))以下の
計算量では収まらない場合がある。具体的には同じ文字
が長く連続するようなデータに対してはこのようなこと
が起こる。
【0088】12. 重複条件つき文字列頻度の計数 重複度つき文字列頻度の計数を単純な方法で行うと、一
つのsuffixに対し、それが構成するクラスをすべて求
め、そのクラスのすべてに対してカウンタの更新を行わ
なければならない。しかし、以下の性質を利用すること
ですべてのクラスに対しカウンタを更新することを避け
ることができる。
【0089】[性質11]ある場所が与えられたとき、
そのsuffixの先頭の文字列に対応するクラスの集合が求
められるが、そのクラスには一意の階層関係がある。 [性質12]ある場所が与えられたとき、その場所のsu
ffixの先頭の文字列に対応するクラスのうち、あるクラ
スの文字列について重複度がkであったとすると、その
クラスより上位のクラスの重複度はk以上である。
【0090】この2つの性質のため、カウンタの加算を
一つのsuffixと一つの重複度kに対して一つにすること
ができる。つまり、あるsuffixで重複度k以上となるク
ラスのうち、最下位のクラスのカウンタだけを加算して
おき、下位クラスの計数が終了したときに、上位のクラ
スのカウンタにその計数値を加算していくことにより、
すべてのクラスの計数値を得ることができる。この性質
を利用してクラスの検出と重複度の判定とを融合した計
数アルゴリズムを以下に説明する。
【0091】13. クラスの発見と頻度計算 13.1 クラスの始まりを発見したときの処理 あるクラスの始まりはcommon[i]が増加したことで発見
できる。このとき、現在計測している重複度つき文字列
頻度の情報はほかのクラスの情報と同様にスタックに待
避させ、重複度つき文字列頻度は0に初期化して新たに
計数する。
【0092】13.2 重複度判定とクラス選択の融合 ある場所で、重複度がkより大きいクラスのなかで最も
下位のクラスを特定する操作は、重複度判定と融合する
ことができる。重複度の判定はpreviousリンクをk回た
どった場所iと、現在の場所jの区間が一つのドキュメ
ントに含まれるかどうかにより行うので、逆にその区間
を含むクラスの集合を求めておき、その中で前述のClas
s*([i,j])を求めることができる。
【0093】この操作は、さらにクラスの検出と同時に
行うことができる。これは、「ある場所で、重複度がk
より大きいClass*([i,j])」を定める区間[i,j]が、現在
の場所jを終わりに持つため、検出の途中では計算未終
了のクラスとなっていることを利用する。
【0094】具体的には、まず、previousリンクをk回
たどったところにある文字列の出現を求める。次に、そ
の出現場所と最初の出現場所を含む文字列から、共通か
つ計算中のClass*([i,j])を特定し、そのクラスの重複
度つき文字列頻度を加算する。
【0095】13.3 クラスの終了を発見したときの
処理 あるクラスの終了はcommon[i]が減少することで発見で
きる。このとき、上位クラスへ計数の値を伝える処理を
する。下位クラスの計数が終了したときに上位クラスの
カウンタに、その計数値を加算することで、結果的にす
べてのクラスに加算するのと同じ値を得ることができ
る。
【0096】14. 実施例 次に上述の計数アルゴリズムを実行するための装置の実
施例を説明する。図10は、実施の形態に係る計数装置
100の構成図である。この構成は、ハードウエア的に
は、任意のコンピュータのCPU、メモリ、その他のL
SIで実現でき、ソフトウエア的にはメモリにロードさ
れた計数処理機能のあるプログラムなどによって実現さ
れるが、ここではそれらの連携によって実現される機能
ブロックを描いている。したがって、これらの機能ブロ
ックがハードウエアのみ、ソフトウエアのみ、またはそ
れらの組合せによっていろいろな形で実現できること
は、当業者には理解されるところである。
【0097】計数処理部10は、文書データベース24
に格納された複数の文書ファイル26を読み込んで文書
ファイル26中の文字列の出現頻度に関する統計量を計
数する。複数の文書ファイル26はコーパスを形成す
る。計数処理部10は、SuffixArray生成部12と、文
字列頻度計数部14と、文書頻度算出部16とをもつ。
Suffix Array生成部12は、各々の文書ファイル26に
ついてsuffixを求め、すべてのsuffixの集合を辞書順に
並べたSuffix Arrayを生成する。またSuffix Array生成
部12はそれぞれのsuffixについて前述のcommonとprev
iousリンクを作成し、各suffixに対応づけて格納する。
このようにして生成されたSuffix Arrayに関するデータ
はSuffix Arrayファイル28として文書データベース2
4に格納される。
【0098】文字列頻度計数部14は、Suffix Arrayフ
ァイル28を参照して、suffixのクラス分けのクラス検
出と、各クラスについての文字列の重複度判定とを行
い、重複度つき文字列頻度を計数する。文書頻度算出部
16は、文字列頻度計数部14により計測された重複度
つき文字列頻度の差分により文字列がk回以上出現する
ドキュメントの頻度を求める。文字列頻度計数部14お
よび文書頻度算出部16により計測された統計量は、文
字列出現頻度データ30として文書データベース24に
格納される。
【0099】問い合わせ部18は、ユーザが指定する任
意の文字列を受けつける。文書頻度算出部16は、問い
合わせ部18からの要求に応じて文字列出現頻度データ
30に含まれる各クラスの統計量の表を2分探索して、
問い合わせのあった文字列に対する出現頻度やドキュメ
ント頻度に関するデータを出力する。問い合わせ部18
は文書頻度算出部16が出力する統計データをユーザに
提供する。
【0100】キーワード抽出部22は、文字列出現頻度
データ30を参照して、各文書ファイル26を特徴づけ
るキーワードを抽出する。キーワードの抽出は後述のよ
うにドキュメント頻度dfを用いた単語の切れ目の検
出と単語の出現のパターンにもとづいて行い、単語辞書
を必要としない。抽出されたキーワードは各文書ファイ
ル26の検索用のインデックスとしてキーワードインデ
ックスファイル32に格納される。検索部20は、ユー
ザが指定する文字列をキーワードとして受けつけ、キー
ワードインデックスファイル32を参照して、指定され
たキーワードを含む文書ファイル26を検索し、ユーザ
に提供する。
【0101】図11は、以上の構成による計数装置10
0が行う計数処理のフローチャートである。このフロー
チャートを用いて計数アルゴリズムの主要部の大まかな
流れを説明する。このフローチャートは、Suffix Array
生成部12によりpreviousリンクを含むSuffix Arrayの
データ構造が生成された後、文字列頻度計数部14が行
うクラス検出と重複度つき文字列頻度の計数処理の流れ
を示したものである。
【0102】Suffix Arrayの添え字を示す変数iを0に
初期化する(S10)。現在の変数iの値が新しいクラ
スの開始場所すなわち新しいクラスを定める区間の始ま
りであるかどうかを調べる(S12)。新しいクラスの
開始場所であるなら(S12のY)、その新しいクラス
の重複度つき文字列頻度cfのカウンタを0に初期化
する(S14)。新しいクラスの開始場所でないなら
(S12のN)、ステップS14は行わない。
【0103】次に計数処理として、各重複度について重
複度に応じた適切なクラスを選んで文字列頻度cf
カウンタをインクリメントする(S16)。ここでいう
適切なクラスとは、現在の場所iと、previousリンクを
k回たどったところにある文字列の出現場所jで定まる
区間を含むもっとも下位のクラスのことである。
【0104】次に後処理として、クラスの終了検出を行
う。現在の変数iがクラスの終了場所すなわちクラスを
定める区間の終わりであるかどうかを調べる(S1
8)。クラスの終了であれば(S18のY)、終了した
クラスの重複度つき文字列頻度cfを記録する(S2
0)。さらに終了したクラスの文字列頻度cfを上位
のクラスの文字列頻度のカウンタに加算する(S2
2)。クラスの終了でなければ(S18のN)、ステッ
プS20およびS22は行わない。
【0105】次のsuffixを調べるために、suffixの添え
字の変数iを1だけインクリメントする(S24)。変
数のiがSuffix Arrayの配列のサイズに等しいなら(S
26のY)、計数処理を終了するが、そうでないなら
(S26のN)、ステップS12にもどって計数処理を
繰り返す。
【0106】このようにして文字列頻度計数部14は、
suffixを順次調べて、クラスの検出と重複度の判定を同
時に行い、重複度つきの文字列頻度を計測する。各ステ
ップの処理の詳細については既に述べた通りである。
【0107】15. 実行例 以上説明した計数アルゴリズムは後述のプログラムによ
り実行される。ここではこのプログラムの実行結果を説
明する。サンプルとして処理するデータは以下のファイ
ルである。一行が一つのドキュメントに相当する。 abcabcabc abcd abcde bcde
【0108】15.1 第1段階 第1段階では、Suffix Arrayを作成し、commonをもと
め、previousリンクを作成する。前述の例に対しては以
下のようなデータが作成される。データは先頭から、su
ffixの番号、suffixが属するドキュメントの番号、同じ
ドキュメントに属しているsuffixで、直前に現れたもの
の番号、直後のsuffixと「先頭から一致している文字
列」の長さ、そのsuffixの文字の順に示されている。 0 0 -1 0: 1 1 -1 0: 2 2 -1 0: 3 3 -1 0: 4 0 0 3:abc 5 0 4 6:abcabc 6 0 5 3:abcabcabc 7 1 1 4:abcd 8 2 2 0:abcde 9 0 6 2:bc 10 0 9 5:bcabc 11 0 10 2:bcabcabc 12 1 7 3:bcd 13 2 8 4:bcde 14 3 3 0:bcde 15 0 11 1:c 16 0 15 4:cabc 17 0 16 1:cabcabc 18 1 12 2:cd 19 2 13 3:cde 20 3 14 0:cde 21 1 18 1:d 22 2 19 2:de 23 3 20 0:de 24 2 22 1:e 25 3 23 0:e
【0109】15.2 第2段階 第2段階では、クラスの検出と頻度の計数を行う。実行
結果を表1に示す。実行結果に示された<start length
c0 c1 c2 c3 c4>は計算途中のクラスの状態を示す。sta
rtはクラスに対応する区間が始まったsuffixの番号、le
ngthはそのクラスに属する最長の文字列の長さである。
c0, c1,c2, c3,c4は、それぞれそのクラスに属する重複
度1,2,3,4,5の文字列の頻度のカウンタであ
る。
【0110】文字列のクラスは、最短の文字列の長さと
最長の文字列の長さで定まるが、計算途中のクラスで
は、最短の長さの文字列はない。クラスに属する最短の
文字列の長さは、最終的にはクラスの階層関係から求め
る。また、最短の文字列の長さは、先頭から順に見てい
った場合、途中ではわからないので、含めることはでき
ない。
【0111】suffixを調べる前にはその都度、計算途中
のクラスをすべて一行で出力する。これは表1の実行結
果のなかで、"<"で始まっている部分である。その次
に、suffixが出力されている。suffixのそれぞれの数字
は、第1段階の例と同様である。
【0112】suffixをひとつ見るごとに、以下の二つの
処理をする。 (1)それぞれの多重度について、多重度に応じた「適
切なクラス」を選んで出現数を加算する。この処理は実
行結果の中では"Incrementing"で始まる部分である。 (2)区間が2以上のクラスを発見したら、記録し、そ
の出現数を上位のクラスに足し込む。この処理は実行結
果の中で"---> Class"で始まる部分である。
【0113】ここで「適切なクラス」とは、現在の場所
(a)とprevious linkを多重度の回数だけたどった場
所(b)で定まる区間を含み、一番短い区間のクラスで
ある。もし、previous linkが多重度の分だけたどれな
かった場合には、加算するべきクラスは存在しないこと
を意味する。
【0114】区間の始まりの場所と終わりの場所が同じ
であるクラスは特別に記録することをしない。記録にな
ければ、それは1回あらわれているか0回かのどちらか
であり、それはO(log(N))で判定できるため、
記録は不要である。
【0115】表1の実行結果において、計算途中のクラ
スの多重度の計数が変化しているが、その場所は、加算
の対象になったクラスと上位のクラスが終了した結果か
らの引き継ぎの二つのケースであり、それらのケースに
限られる。
【表1】 <S0 L0 0 0 0 0 0> 0 0 -1 0: -> Incrementing c[0] of Class*[0,0] : (S0,L0) S="" <S0 L0 1 0 0 0 0> 1 1 -1 0: -> Incrementing c[0] of Class*[1,1] : (S0,L0) S="" <S0 L0 2 0 0 0 0> 2 2 -1 0: -> Incrementing c[0] of Class*[2,2] : (S0,L0) S="" <S0 L0 3 0 0 0 0> 3 3 -1 0: -> Incrementing c[0] of Class*[3,3] : (S0,L0) S="" <S0 L0 4 0 0 0 0> 4 0 0 3:abc -> Incrementing c[0] of Class*[4,4] : (S4,L3) S="abc" -> Incrementing c[1] of Class*[0,4] : (S0,L0) S="" <S0 L0 4 1 0 0 0><S4 L3 1 0 0 0 0> 5 0 4 6:abcabc -> Incrementing c[0] of Class*[5,5] : (S5,L6) S="abcabc" -> Incrementing c[1] of Class*[4,5] : (S4,L3) S="abc" -> Incrementing c[2] of Class*[0,5] : (S0,L0) S="" <S0 L0 4 1 1 0 0><S4 L3 1 1 0 0 0><S5 L6 1 0 0 0 0> 6 0 5 3:abcabcabc -> Incrementing c[0] of Class*[6,6] : (S5,L6) S="abcabc" -> Incrementing c[1] of Class*[5,6] : (S5,L6) S="abcabc" -> Incrementing c[2] of Class*[4,6] : (S4,L3) S="abc" -> Incrementing c[3] of Class*[0,6] : (S0,L0) S="" ---> Class[5, 6] L=6 c[0]=2 c[1]=1 c[2]=0 c[3]=0 c[4]=0 S="abcabc" <S0 L0 4 1 1 1 0><S4 L3 3 2 1 0 0> 7 1 1 4:abcd -> Incrementing c[0] of Class*[7,7] : (S7,L4) S="abcd" -> Incrementing c[1] of Class*[1,7] : (S0,L0) S="" <S0 L0 4 2 1 1 0><S4 L3 3 2 1 0 0><S7 L4 1 0 0 0 0> 8 2 2 0:abcde -> Incrementing c[0] of Class*[8,8] : (S7,L4) S="abcd" -> Incrementing c[1] of Class*[2,8] : (S0,L0) S="" ---> Class[7, 8] L=4 c[0]=2 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="abcd" ---> Class[4, 8] L=3 c[0]=5 c[1]=2 c[2]=1 c[3]=0 c[4]=0 S="abc" <S0 L0 9 5 2 1 0> 9 0 6 2:bc -> Incrementing c[0] of Class*[9,9] : (S9,L2) S="bc" -> Incrementing c[1] of Class*[6,9] : (S0,L0) S="" -> Incrementing c[2] of Class*[5,9] : (S0,L0) S="" -> Incrementing c[3] of Class*[4,9] : (S0,L0) S="" -> Incrementing c[4] of Class*[0,9] : (S0,L0) S="" <S0 L0 9 6 3 2 1><S9 L2 1 0 0 0 0> 10 0 9 5:bcabc -> Incrementing c[0] of Class*[10,10] : (S10,L5) S="bcabc" -> Incrementing c[1] of Class*[9,10] : (S9,L2) S="bc" -> Incrementing c[2] of Class*[6,10] : (S0,L0) S="" -> Incrementing c[3] of Class*[5,10] : (S0,L0) S="" -> Incrementing c[4] of Class*[4,10] : (S0,L0) S="" <S0 L0 9 6 4 3 2><S9 L2 1 1 0 0 0><S10 L5 1 0 0 0 0> 11 0 10 2:bcabcabc -> Incrementing c[0] of Class*[11,11] : (S10,L5) S="bcabc" -> Incrementing c[1] of Class*[10,11] : (S10,L5) S="bcabc" -> Incrementing c[2] of Class*[9,11] : (S9,L2) S="bc" -> Incrementing c[3] of Class*[6,11] : (S0,L0) S="" -> Incrementing c[4] of Class*[5,11] : (S0,L0) S="" ---> Class[10, 11] L=5 c[0]=2 c[1]=1 c[2]=0 c[3]=0 c[4]=0 S="bcabc " <S0 L0 9 6 4 4 3><S9 L2 3 2 1 0 0> 12 1 7 3:bcd -> Incrementing c[0] of Class*[12,12] : (S12,L3) S="bcd" -> Incrementing c[1] of Class*[7,12] : (S0,L0) S="" -> Incrementing c[2] of Class*[1,12] : (S0,L0) S="" <S0 L0 9 7 5 4 3><S9 L2 3 2 1 0 0><S12 L3 1 0 0 0 0> 13 2 8 4:bcde -> Incrementing c[0] of Class*[13,13] : (S13,L4) S="bcde" -> Incrementing c[1] of Class*[8,13] : (S0,L0) S="" -> Incrementing c[2] of Class*[2,13] : (S0,L0) S="" <S0 L0 9 8 6 4 3><S9 L2 3 2 1 0 0><S12 L3 1 0 0 0 0><S13 L4 1 0 0 0 0> 14 3 3 0:bcde -> Incrementing c[0] of Class*[14,14] : (S13,L4) S="bcde" -> Incrementing c[1] of Class*[3,14] : (S0,L0) S="" ---> Class[13, 14] L=4 c[0]=2 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="bcde" ---> Class[12, 14] L=3 c[0]=3 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="bcd" ---> Class[9, 14] L=2 c[0]=6 c[1]=2 c[2]=1 c[3]=0 c[4]=0 S="bc" <S0 L0 15 11 7 4 3> 15 0 11 1:c -> Incrementing c[0] of Class*[15,15] : (S15,L1) S="c" -> Incrementing c[1] of Class*[11,15] : (S0,L0) S="" -> Incrementing c[2] of Class*[10,15] : (S0,L0) S="" -> Incrementing c[3] of Class*[9,15] : (S0,L0) S="" -> Incrementing c[4] of Class*[6,15] : (S0,L0) S="" <S0 L0 15 12 8 5 4><S15 L1 1 0 0 0 0> 16 0 15 4:cabc -> Incrementing c[0] of Class*[16,16] : (S16,L4) S="cabc" -> Incrementing c[1] of Class*[15,16] : (S15,L1) S="c" -> Incrementing c[2] of Class*[11,16] : (S0,L0) S="" -> Incrementing c[3] of Class*[10,16] : (S0,L0) S="" -> Incrementing c[4] of Class*[9,16] : (S0,L0) S="" <S0 L0 15 12 9 6 5><S15 L1 1 1 0 0 0><S16 L4 1 0 0 0 0> 17 0 16 1:cabcabc -> Incrementing c[0] of Class*[17,17] : (S16,L4) S="cabc" -> Incrementing c[1] of Class*[16,17] : (S16,L4) S="cabc" -> Incrementing c[2] of Class*[15,17] : (S15,L1) S="c" -> Incrementing c[3] of Class*[11,17] : (S0,L0) S="" -> Incrementing c[4] of Class*[10,17] : (S0,L0) S="" ---> Class[16, 17] L=4 c[0]=2 c[1]=1 c[2]=0 c[3]=0 c[4]=0 S="cabc" <S0 L0 15 12 9 7 6><S15 L1 3 2 1 0 0> 18 1 12 2:cd -> Incrementing c[0] of Class*[18,18] : (S18,L2) S="cd" -> Incrementing c[1] of Class*[12,18] : (S0,L0) S="" -> Incrementing c[2] of Class*[7,18] : (S0,L0) S="" -> Incrementing c[3] of Class*[1,18] : (S0,L0) S="" <S0 L0 15 13 10 8 6><S15 L1 3 2 1 0 0><S18 L2 1 0 0 0 0> 19 2 13 3:cde -> Incrementing c[0] of Class*[19,19] : (S19,L3) S="cde" -> Incrementing c[1] of Class*[13,19] : (S0,L0) S="" -> Incrementing c[2] of Class*[8,19] : (S0,L0) S="" -> Incrementing c[3] of Class*[2,19] : (S0,L0) S="" <S0 L0 15 14 11 9 6><S15 L1 3 2 1 0 0><S18 L2 1 0 0 0 0><S19 L3 1 0 0 0 0> 20 3 14 0:cde -> Incrementing c[0] of Class*[20,20] : (S19,L3) S="cde" -> Incrementing c[1] of Class*[14,20] : (S0,L0) S="" -> Incrementing c[2] of Class*[3,20] : (S0,L0) S="" ---> Class[19, 20] L=3 c[0]=2 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="cde" ---> Class[18, 20] L=2 c[0]=3 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="cd" ---> Class[15, 20] L=1 c[0]=6 c[1]=2 c[2]=1 c[3]=0 c[4]=0 S="c" <S0 L0 21 17 13 9 6> 21 1 18 1:d -> Incrementing c[0] of Class*[21,21] : (S21,L1) S="d" -> Incrementing c[1] of Class*[18,21] : (S0,L0) S="" -> Incrementing c[2] of Class*[12,21] : (S0,L0) S="" -> Incrementing c[3] of Class*[7,21] : (S0,L0) S="" -> Incrementing c[4] of Class*[1,21] : (S0,L0) S="" <S0 L0 21 18 14 10 7><S21 L1 1 0 0 0 0> 22 2 19 2:de -> Incrementing c[0] of Class*[22,22] : (S22,L2) S="de" -> Incrementing c[1] of Class*[19,22] : (S0,L0) S="" -> Incrementing c[2] of Class*[13,22] : (S0,L0) S="" -> Incrementing c[3] of Class*[8,22] : (S0,L0) S="" -> Incrementing c[4] of Class*[2,22] : (S0,L0) S="" <S0 L0 21 19 15 11 8><S21 L1 1 0 0 0 0><S22 L2 1 0 0 0 0> 23 3 20 0:de -> Incrementing c[0] of Class*[23,23] : (S22,L2) S="de" -> Incrementing c[1] of Class*[20,23] : (S0,L0) S="" -> Incrementing c[2] of Class*[14,23] : (S0,L0) S="" -> Incrementing c[3] of Class*[3,23] : (S0,L0) S="" ---> Class[22, 23] L=2 c[0]=2 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="de" ---> Class[21, 23] L=1 c[0]=3 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="d" <S0 L0 24 20 16 12 8> 24 2 22 1:e -> Incrementing c[0] of Class*[24,24] : (S24,L1) S="e" -> Incrementing c[1] of Class*[22,24] : (S0,L0) S="" -> Incrementing c[2] of Class*[19,24] : (S0,L0) S="" -> Incrementing c[3] of Class*[13,24] : (S0,L0) S="" -> Incrementing c[4] of Class*[8,24] : (S0,L0) S="" <S0 L0 24 21 17 13 9><S24 L1 1 0 0 0 0> 25 3 23 0:e -> Incrementing c[0] of Class*[25,25] : (S24,L1) S="e" -> Incrementing c[1] of Class*[23,25] : (S0,L0) S="" -> Incrementing c[2] of Class*[20,25] : (S0,L0) S="" -> Incrementing c[3] of Class*[14,25] : (S0,L0) S="" -> Incrementing c[4] of Class*[3,25] : (S0,L0) S="" ---> Class[24, 25] L=1 c[0]=2 c[1]=0 c[2]=0 c[3]=0 c[4]=0 S="e" <S0 L0 26 22 18 14 10>
【0116】15.3 第3段階 この実行結果より、tfの値が2より大きいクラスが求
まるので、クラスの先頭の場所を第1のキー、長さを第
2のキーとしてクラスをソートする。同時に、重複度つ
き文字列頻度cfの差分からドキュメント頻度df
を求める。その結果を表2に示す。この例では、tfの
値が2より大きなクラスは全部で14個ある。クラスご
とに、対応する区間、長さ、それぞれのクラスに対する
tf、dfの統計値、およびクラスの中の最長の文字
列が順に示されている。
【0117】このクラスのリストの中には、区間が1の
クラスは含まれていない。また、クラスの中で最短長さ
は含まれていないが、これはあとに述べるように、クラ
スの代表する文字列と先頭から一致する文字列を検索し
た場合には、そのなかで短い最長の長さをもつクラスの
情報を取り出すことで対処している。
【0118】クラスのソートで、区間の先頭を第一のキ
ーにすることでおよそアルファベットの順番にならぶ。
区間の先頭が同じ場合には、長さが短いほうが優先され
ることで、結果としてクラスの代表する文字列は辞書順
にならぶ。
【表2】 total=14 Class[ 4, 8] L=3 tf=5 df1=3 df2=1 df3=1 df4=0 S="abc" Class[ 5, 6] L=6 tf=2 df1=1 df2=1 df3=0 df4=0 S="abcabc" Class[ 7, 8] L=4 tf=2 df1=2 df2=0 df3=0 df4=0 S="abcd" Class[ 9, 14] L=2 tf=6 df1=4 df2=1 df3=1 df4=0 S="bc" Class[ 10, 11] L=5 tf=2 df1=1 df2=1 df3=0 df4=0 S="bcabc" Class[ 12, 14] L=3 tf=3 df1=3 df2=0 df3=0 df4=0 S="bcd" Class[ 13, 14] L=4 tf=2 df1=2 df2=0 df3=0 df4=0 S="bcde" Class[ 15, 20] L=1 tf=6 df1=4 df2=1 df3=1 df4=0 S="c" Class[ 16, 17] L=4 tf=2 df1=1 df2=1 df3=0 df4=0 S="cabc" Class[ 18, 20] L=2 tf=3 df1=3 df2=0 df3=0 df4=0 S="cd" Class[ 19, 20] L=3 tf=2 df1=2 df2=0 df3=0 df4=0 S="cde" Class[ 21, 23] L=1 tf=3 df1=3 df2=0 df3=0 df4=0 S="d" Class[ 22, 23] L=2 tf=2 df1=2 df2=0 df3=0 df4=0 S="de" Class[ 24, 25] L=1 tf=2 df1=2 df2=0 df3=0 df4=0 S="e"
【0119】15.4 文字列に対する処理 与えられた任意の文字列に対して、上記の表2を2分探
索することでtf,df,df,df,df
値を求めることができる。2分探索であり、表の大きさ
はO(N)であるので、この処理はO(log(N))
の計算量で終了する。以下に文字列を与えたときの出力
結果を示す。 abc -- Class[4,8]に該当(代表文字列) 5 3 1 1 0 abc abcabc -- Class[5,6]に該当(代表文字列) 2 1 1 0 0 abcabc abcd -- Class[7,8]に該当(代表文字列) 2 2 0 0 0 abcd abca -- Class[5,6]に該当(代表文字列でない) 2 1 1 0 0 abca abcab -- Class[5,6]に該当(代表文字列でない) 2 1 1 0 0 abcab abcabc -- Class[5,6]に該当(代表文字列) 2 1 1 0 0 abcabc abcabca -- 表になく、コーパスに存在する 1 1 0 0 0 abcabca abcabcab -- 表になく、コーパスに存在する 1 1 0 0 0 abcabcab abcabcabc -- 表になく、コーパスに存在する 1 1 0 0 0 abcabcabc abcabcabca -- 表になく、コーパスに存在しない 0 0 0 0 0 abcabcabca
【0120】16. 計算量とメモリ使用量 クラス分けを行わないですべての部分文字列に対してd
を求める方法や、クラス分けをしても、クラスの階
層構造を利用せずに、それぞれのクラスを独立して調べ
てdfを求める方法に比べると、本アルゴリズムによ
る実行時間は大規模なコーパスに対しても実際的に処理
可能な計算時間となる。本アルゴリズムでは、全体の処
理は、テキストの文字数をN、求める最大のkをkMA
Xとしたときに、O(NlogN+kMAX×N)の前
処理のあとに、O(logN)で、「任意の文字列につ
いて、k回以上出現するドキュメントの数」を求めるこ
とができる。またメモリ使用量については、前処理にお
いても、その後に任意の文字列に対して値を求める際に
も、O(N)の容量である。この計数アルゴリズムを実
装した後述のプログラムを用いて実験を行い、実行時間
を計測した結果、実用的に計数が行えることが確認され
ている。
【0121】17. キーワード抽出への応用 df/dfは、ドキュメントの確率空間において、ド
キュメントにある文字列が出現するということを条件と
したとき、そのドキュメントに2回その文字列が出現す
る確率の推定値として用いることができる。文献[6]
は英語において、その確率が統計的に単語の性質を識別
できることを示している。
【0122】任意文字列をIDF(Inverse Document F
requency)をポテンシャルとして、そのポテンシャルの
最良の分割点として求めるというアイデアは文献[4]
に示されている。さらに、dfも利用するとキーワー
ドの抽出精度を上げることができる。これらのキーワー
ド抽出作業を行うには、任意の部分文字列について、d
f、dfを計算する必要があり、本アルゴリズムを使
うことでシステムの動作速度を向上できる。
【0123】dfの計測はこのようにいくつか応用が
あるが、そのなかで辞書を使わないキーワードの抽出へ
の応用を示す。
【0124】以下のような文書ファイルをいくつか含む
コーパスが与えられたとする。gakkai-0000000001 電気
回路演習用CAIとその改良 大学等での基礎的な電気
回路演習を支援するCAIソフトウェアとその改良につ
いて述べている。本CAIはコンピュータが出題される
回路を学習者各人のレベルに応じて自動的に作成するこ
と、解答を数式で入力することが大きな特長である。ま
た、誤った解答に対しては、原因の検討を容易にするメ
ッセージが表示されるなど、効果的な個別学習が限られ
た設備・要員で実施可能であるよう配慮した。昨年度の
学生による本CAIの使用結果のアンケート、および発
表の場における質疑等を参考に、操作を容易とし、効果
を上げるための改良を行った。 電気回路 演習
【0125】コーパスの部分文字列に関して、tf,
N,df,df,df,df,dfを求めた結
果の一部を表3に示す。
【表3】 27511 40000 40000 40000 40000 40000 40000 1 20 21 回 14384 40000 5224 3132 2094 1431 938 1 20 22 回路 6 40000 3 2 1 0 0 1 20 23 回路演 6 40000 3 2 1 0 0 1 20 24 回路演習 23604 40000 40000 40000 40000 40000 40000 1 21 22 路 7 40000 4 2 1 0 0 1 21 23 路演 7 40000 4 2 1 0 0 1 21 24 路演習 3325 40000 1555 702 408 245 162 1 22 23 演 192 40000 75 41 25 18 12 1 22 24 演習 7 40000 6 1 0 0 0 1 22 25 演習用 4 40000 4 0 0 0 0 1 22 26 演習用C 4 40000 4 0 0 0 0 1 22 27 演習用C A 4 40000 4 0 0 0 0 1 22 28 演習用C AI 4245 40000 1308 860 640 462 333 1 23 24 習 29 40000 23 5 1 0 0 1 23 25 習用 5 40000 5 0 0 0 0 1 23 26 習用C 5 40000 5 0 0 0 0 1 23 27 習用CA 5 40000 5 0 0 0 0 1 23 28 習用CA I 72462 40000 40000 40000 40000 40000 40000 1 24 25 用 139 40000 121 16 2 0 0 1 24 26 用C 51 40000 40 10 1 0 0 1 24 27 用CA 27 40000 21 6 0 0 0 1 24 28 用CAI 38995 40000 40000 40000 40000 40000 40000 1 25 26 C 3749 40000 1852 837 499 275 142 1 25 27 CA 790 40000 288 186 148 86 43 1 25 28 CAI 9 40000 9 0 0 0 0 1 25 29 CAIと 44832 40000 40000 40000 40000 40000 40000 1 26 27 A 1899 40000 877 445 276 157 76 1 26 28 AI 10 40000 10 0 0 0 0 1 26 29 AIと 44675 40000 40000 40000 40000 40000 40000 1 27 28 I 180 40000 158 16 6 0 0 1 27 29 Iと 6 40000 6 0 0 0 0 1 27 30 Iとそ 5 40000 5 0 0 0 0 1 27 31 Iとその 158324 40000 40000 40000 40000 40000 40000 1 28 29 と 2093 40000 1939 141 13 0 0 1 28 30 とそ 1789 40000 1669 112 8 0 0 1 28 31 とその 14 40000 13 1 0 0 0 1 28 32 とその改 6 40000 5 1 0 0 0 1 28 33 とその改 良
【0126】この表3において、たとえば文字列「CA
I」については、dfは288、dfは186、df
は148であるが、文字列「CAIと」については、
dfが9であるのに対して、df、dfは0であ
る。このように単語の切れ目を含む文字列はdfに比べ
df以降が急激に減ることがわかる。このdf以降
が急激に減る性質を利用して単語の切れ目を検出して文
書ファイルの文字列を分割すると以下のようになる。
【0127】gakkai-000000/0001/電気回路/演習/用/C
AI/と/その/改良//大学/等/で/の基礎/的/な/電気回
路/演習/を/支援/する/CAI/ソフトウエア/と/その/
改良/について述べ/ている。/本/CAI/は/コンピュー
タ/が/出/題/され/る/回路/を/学習者/各/人の/レベル/
に応じて/自動/的/に/作成/する/こと、/解答/を/数式/
で/入力/する/ことが/大き/な/特/長/である。/ま/た
/、/誤/った/解答/に対しては、/原因/の/検討/を容易
に/する/メッセージ/が/表示/され/る/など/、/効果/的
/な/個別/学習/が/限/ら/れ/た/設備/・/要員/で/実施/
可能/である/よ/う/配/慮/した。/昨年度/の/学生/によ
る/本/CAI/の/使用/結/果/の/アンケート/、/および
/発/表/の/場における/質/疑/等/を/参/考/に/、/操作/
を/容易/とし、/効果/を上げる/ため/の改良/を行っ
た。/電気回路//演習/
【0128】このように、文字分割された文書ファイル
からキーワードとなりそうな文字列の分布をもつものを
選ぶことにより、以下のようなキーワードが抽出され
る。 演習 CAI 演習 支援 CAI ソフトウエア C
AI 学習者 自動 メッセージ 表示 学習 学生
CAI 演習
【0129】結果として、単語の辞書がまったくない状
態で、日本語の文章からキーワードが抽出できる。この
方法は言語独立であり、古文書のように辞書の整備がな
されていない文書や、暗号文書など未解読の文書にも適
用できる。また遺伝子情報に適用して、DNAの配列の
解析に応用することもできる。
【0130】その他の応用をいくつか述べる。df
計測は情報検索への応用が考えられる。バイグラムの情
報検索システムにおいては、単語による情報検索におい
て行われているストップリストによる単語の選別方法が
明らかではない。そこで、バイグラムをdf/dfで
切り分けて、df/dfが高いバイグラムだけを選び
出すという応用が考えられる。文献[8]によれば、d
/dfにはキーワードを選別する傾向がみられるの
で、選別に使うことによって情報検索の性能の向上が見
て取れた。
【0131】ソフトウェアツールへの応用も考えられ
る。Suffix Arrayのクラス分けの応用として、文献
[7]にはプログラムにクラスシステムの分析を行い、
他の場所にはあらわれない特異な場所を計測して、プロ
グラム中の特異な場所を自動検出するシステムの報告が
ある。このシステムでは統計量としてtfだけを使って
いるがdf、dfを利用することで、プログラムの計
測ツールとして、さらに性能の向上が期待できる。
【0132】以上述べたように、本アルゴリズムに示さ
れたドキュメント頻度の計数技術では、既存のSuffix A
rrayのデータ構造を用いて、Suffix Arrayをクラス分け
し、そのクラスを利用してdfを計数する。クラス分
けをして文字列が1回以上出現するドキュメントの数d
fを計数する方法は文献[3]で知られているが、本ア
ルゴリズムでは、文字列がk回(kは2以上の自然数)
以上出現するドキュメントの数dfの効率的な計測を
可能にするため、重複度つきの文字列頻度を新たに定義
し、文字列がk回以上出現するドキュメントの数を求め
るとき、重複度つき文字列頻度の差分を用いて計算し
た。また、クラスの検出と重複度の判定の処理を同時に
行うことにより、計算量を抑えた。さらには入れ子にな
ったクラス階層の構造を利用して、下位のクラスで求め
た重複度つき文字列頻度を、上位のクラスで求める重複
度つき文字列頻度に加算することにより、文字列の出現
頻度の累積計測を可能にし、計算量を抑えた。これらの
技術により、コーパスの大きさに対して実用的な計算時
間でドキュメント頻度の計数が可能となった。
【0133】以上、本発明を実施の形態をもとに説明し
た。これらの実施の形態は例示であり、それらの各構成
要素や各処理プロセスの組合せにいろいろな変形例が可
能なこと、またそうした変形例も本発明の範囲にあるこ
とは当業者に理解されるところである。以下そのような
変形例を説明する。
【0134】上記の実施の形態では、計数アルゴリズム
の実行例として、日本語を対象としたが、アルゴリズム
は言語独立である。また実施の形態では、文書を例にあ
げて文字列の出現頻度を計測したが、計数アルゴリズム
は、計測の対象を文書に限らず、たとえば遺伝子情報に
おける遺伝子の配列の出現頻度を計測するために用いる
ことも可能である。とくに本発明では辞書を用いずに出
現頻度の情報から意味のある単語を切り出すことができ
るため、遺伝子情報の解読に用いた場合、特定の機能を
もつ遺伝子配列の抽出が可能となる。
【0135】本明細書で参照した参考文献のリストを以
下に示す。 [1] Manber, Udi and Gene Myer. 1990., Suffix arrays: A new method for on-line string sea
rches,In the first Annual ACM-SIAM Symposium on Di
screte Algorithms, pages 319-327. [2] 伊藤秀夫, Suffix Arrayの効率的な構築法, 情報処理学会論文誌、Vol.41, No.SIG1(TOD5), pp.31-3
9(2000). [3] Mikio Yamamoto and Kenneth W. Church,Using Suf
fix Arrays to Compute Term Frequency and Document
Frequency forAll Substrings in a Corpus,Computatio
nal Linguistics, Vol.27:1, pp.1-30, MIT Press. [4] Tomohiro Ozawa, Mikio Yamamoto, Kyoji Umemura
and Kennth W. Church,Japanese word segmentation us
ing similarity measure for IR,In proceedings of th
e first NTCIR workshop on Research in Japanese tex
tretrieval and term recognition. Tokyo Japan, Augu
st 1999, pp.89-96. [5] 小澤智裕、山本幹雄、山本英子、梅村恭司, 情報検索の類似尺度を用いた検索要求文の単語分割, 言語処理学会第回年次大会発表論文集, March, 1999, p
p.305-308. [6] Kenneth W. Church, Empirical Estimates of Adaptation: The chance of T
wo Noriega’s is closeto p/2 than p 2,Coling2000,
pp.173-179. [7] 吉川裕之、貴島寿郎、梅村恭司, n-gram解析手法を応用したプログラム中の欠損の検出, 情報処理学会論文誌、Vol.9, No.12, pp.3294-3303. [8] Kyoji Umemura and Kenneth W. Church,Empirical
Term Weighting and Expansion Frequency,Empirical M
ethods in Natural Language Processing and Very Lar
ge Corpora,pp.117-123. [9] 武田善行、梅村恭司, キーワード抽出を実現する文書頻度分析 計量国語学, Vol.23, No.2, pp.65-90
【0136】上述の実施の形態に係る計数アルゴリズム
を実装したプログラムのリストを表4に示す。
【表4】 1 /* もとめるdf_kのkの最大値+1, 2 */ 3 #define MAX_C 5 4 5 /* ドキュメントの区切り文字 */ 6 #define SEPARATOR '\n' 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <stdlib.h> 11 /* qsortの引数に与えるべき関数の型*/ 12 typedef int (*sortfn)(const void *, const void*); 13 14 #define MESSAGE_FILE stdout 15 16 static char * text; /* テキストのもとデータ*/ 17 18 static int size; /* テキストのバイト数*/ 19 20 static int id; /* 読み込み中のドキュメントの番号 */ 21 22 static int id_max; /* ドキュメントの総数 */ 23 24 static int common_max; /* 隣り合うsuffixで共通である文字数の最 大値 */ 25 26 27 struct suffix_struct 28 { int position; /* textのスタートindex */ 29 int common; /* 次のsuffixとの共通部分の長さ */ 30 int id; /* 対応するドキュメントの番号 */ 31 int previous_suffix; /* 同一のドキュメントであるsuffixのもっとも 近いもの */ 32 }; 33 34 static struct suffix_struct * suffix; /* suffix array */ 35 36 static int * last_suffixes; /* previous suffixを作成するための配列 */ 37 38 static FILE * text_file; /* データのファイル */ 39 40 struct pending_struct 41 { int start_suffix; 42 int length; 43 int c[MAX_C]; 44 }; 45 46 47 static struct pending_struct * pendings; 48 static int level; 49 50 static int pending_level(int suffix) 51 { 52 int min, max, mid; 53 min = 0; max = level; 54 while(min + 1 < max) { 55 mid = (min + max) / 2; 56 if(pendings[mid].start_suffix <= suffix){ 57 min = mid; 58 } else { 59 max = mid; 60 } 61 } 62 if(pendings[max].start_suffix <= suffix) return max; 63 if(pendings[min].start_suffix <= suffix) return min; 64 fprintf(stderr, "internal error(pending_level)\n"); 65 exit(2); 66 return -1; 67 } 68 69 70 #ifdef DEBUG 71 /* 指定されたsuffixの状態を表示 */ 72 static void debug_suffix(int i) 73 { 74 int j; 75 fprintf(MESSAGE_FILE, 76 "%5d %3d %5d %2d:", 77 i, 78 suffix[i].id, 79 suffix[i].previous_suffix, 80 suffix[i].common); 81 for(j=0;text[suffix[i].position+j]!='\n';j++) { 82 fputc(text[suffix[i].position+j], MESSAGE_FILE); 83 } 84 fputc('\n', MESSAGE_FILE); 85 fflush(MESSAGE_FILE); 86 } 87 88 /* suffix arrayの状態を表示 */ 89 static void debug_output() 90 { int i; 91 fprintf(MESSAGE_FILE, "size = %d\n", size); 92 fprintf(MESSAGE_FILE, "id_max = %d\n", id_max); 93 fprintf(MESSAGE_FILE, "common_max = %d\n", common_max); 94 for(i=0;i<size;i++) { 95 debug_suffix(i); 96 } 97 } 98 99 /* pending classの状態を表示 */ 100 static void debug_pending() 101 { 102 int i; int j; 103 for(i = 0; i<=level; i++) { 104 fprintf(MESSAGE_FILE, "<S%d L%d", 105 pendings[i].start_suffix, 106 pendings[i].length); 107 for(j=0;j<MAX_C;j++) { 108 fprintf(MESSAGE_FILE, " %d", pendings[i].c[j]); 109 } 110 fprintf(MESSAGE_FILE, ">"); 111 } 112 fprintf(MESSAGE_FILE, "\n"); 113 } 114 #endif 115 116 static void error_alloc(void) 117 { 118 fprintf(MESSAGE_FILE, 119 "text %x, suffix %x, last_suffixes %x, classes %x \n", 120 (int)text, 121 (int)suffix, 122 (int)last_suffixes, 123 (int)pendings); 124 exit(1); 125 } 126 127 /* suffixの順序の決定関数, 128 ドキュメントの区切りで中断するが 129 文字列の辞書順の比較である。 130 131 */ 132 static int my_strcmp(char *x1, char *y1) 133 { 134 register unsigned char * x; 135 register unsigned char * y; 136 x = (unsigned char *) x1; y= (unsigned char *)y1; 137 while(*x && *y) { 138 if(*x < *y) return -1; 139 if(*x > *y) return 1; 140 if(*x == '\n') break; 141 if(*y == '\n') break; 142 x++; y++; 143 } 144 return 0; 145 } 146 147 static int string_sub(char *s1, char *s2) 148 { 149 while(*s2) { 150 if(*s1 != *s2) { return 0; } 151 s1++; 152 s2++; 153 } 154 return *s1; 155 } 156 157 /* suffixが示す文字列の順序を定める関数 158 先頭からある部分が同じなら, 次の文字で順序が決定する 159 という性質であれば,これに限らない。 160 */ 161 static int suffix_order(struct suffix_struct * x, struct suffix_st ruct * y) 162 { 163 return my_strcmp(text + x->position, text + y->position); 164 } 165 166 /* 先頭から共通の文字数を求める。関数 */ 167 168 static int common_length(char * x, char * y) 169 {int i; 170 i = 0; 171 while((*x == *y) && (*x) && (*x !='\n')) { i++; x++; y++;}; 172 return i; 173 } 174 175 struct class_struct 176 { struct class_struct * next; 177 int first; 178 int last; 179 int length; 180 int c[MAX_C]; 181 }; 182 183 static struct class_struct * class_list = 0; 184 static int class_count = 0; 185 186 static struct class_struct * class_table; 187 188 static void register_class(int first, int last, int length, int c[ ]) 189 { int i; 190 struct class_struct * p; 191 #ifdef DEBUG 192 printf(" ---> Class[%d, %d] L=%d", first, last, length); 193 for(i=0;i<MAX_C;i++) { 194 printf(" c[%d]=%d", i, c[i]); 195 } 196 printf(" S=\""); 197 for(i=0;i<length;i++) { putchar(text[suffix[first].position + i] ); } 198 printf("\"\n"); 199 #endif 200 p = (struct class_struct *) malloc(sizeof(struct class_struct)); 201 if(p == 0) { 202 fprintf(stderr, "register_class\n"); 203 exit(2); 204 } 205 p->first = first; 206 p->last = last; 207 p->length = length; 208 for(i=0;i<MAX_C;i++) { 209 p->c[i] = c[i]; 210 } 211 p->next = class_list; 212 class_list = p; 213 class_count++; 214 } 215 216 int class_order(struct class_struct * x, struct class_struct * y) 217 { 218 if(x->first < y->first) return -1; 219 if(x->first > y->first) return 1; 220 if(x->length < y->length) return -1; 221 if(x->length > y->length) return 1; 222 return 0; 223 } 224 225 /* クラスについて, 場所, 長さ, 文字, 計数値を表示する */ 226 #ifdef DEBUG 227 static void output_class(int first, int last, int length, int c[] ) 228 { 229 int i; int j; 230 printf("Class[%4d,%4d] L=%d tf=%d", 231 first, 232 last, 233 length, 234 c[0]); 235 for(j=1;j<MAX_C;j++) { 236 printf(" df%d=%d", j, c[j-1]-c[j]); 237 } 238 printf(" S=\""); 239 for(i=0;i<length;i++) { putchar(text[suffix[first].position + i] ); } 240 printf("\"\n"); 241 } 242 #endif 243 244 245 static void make_class_table(void) 246 { struct class_struct * p; 247 int i; 248 class_table = (struct class_struct *) 249 malloc (sizeof(struct class_struct) * class_count) ; 250 if(class_table == 0) { 251 fprintf(stderr, "make_class_table\n"); 252 exit(1); 253 } 254 p = class_list; 255 for(i=0;i<class_count;i++) { 256 class_table[i] = *p; 257 p = p->next; 258 }; 259 qsort(class_table, class_count, sizeof(struct class_struct), (so rtfn)class_order); 260 } 261 262 static void clear_class_list(void) 263 { int i; 264 struct class_struct * p; 265 struct class_struct * q; 266 p = class_list; 267 for(i=0;i<class_count;i++) { 268 q = p; 269 p = q->next; 270 q->next = 0; 271 free(q); 272 } 273 class_list = 0; 274 } 275 276 277 void df_setup(char * file) 278 { char * p; int i; int j; int ch; int previous; 279 #ifdef DEBUG 280 int ii; 281 #endif 282 text_file = fopen(file, "r"); 283 if(text_file == 0) { 284 fprintf(stderr, "File %s not found\n", file); 285 exit(1); 286 } 287 288 /* データの総文字数を求める*/ 289 size = 0; 290 while(EOF != (ch = fgetc(text_file))) { 291 size++; 292 }; 293 294 /* 総文字数から, 必要なデータ領域を生成する*/ 295 text = (char *) malloc (sizeof(char) * (size + 1)); 296 if(text == 0) error_alloc(); 297 suffix = (struct suffix_struct *) 298 malloc( sizeof(struct suffix_struct) * (size + 1)); 299 if(suffix == 0) error_alloc(); 300 fseek(text_file, 0, SEEK_SET); 301 p = text; 302 id = 0; 303 304 /* メモリに読み込むと同時に, ドキュメントの区切りを 305 つけていく */ 306 id_max = 0; 307 for(i=0;i<size;i++) { 308 ch = fgetc(text_file); 309 text[i] = ch; 310 suffix[i].position = i; 311 suffix[i].id = id; 312 id_max = id + 1; 313 if(ch == '\n') { id ++; } 314 }; 315 text[size]=0; 316 317 318 /* Suffixをつくるルーチン*/ 319 /* 以下は例である。*/ 320 common_max = 0; 321 for(i=0;i<size;i++) { suffix[i].position = i; } 322 /* sortの処理が, 計算時間の大半を占めると予想される */ 323 qsort(suffix, size, sizeof(struct suffix_struct), (sortfn) suffi x_order); 324 suffix[size].position = size; 325 for(i=0;i<size;i++) { 326 int c; 327 c = common_length(text+suffix[i].position, text+suffix[i+1].po sition); 328 suffix[i].common = c; 329 if(c > common_max) common_max = c; 330 } 331 suffix[size].common = 0; 332 333 334 /* 重複計算のためのデータ構造の生成 */ 335 last_suffixes = (int *) malloc( id_max * sizeof(int)); 336 if(last_suffixes == 0) error_alloc(); 337 for(i=0;i<id_max;i++) { last_suffixes[i] = -1; } 338 for(i=0;i<size;i++) { 339 suffix[i].previous_suffix = last_suffixes[suffix[i].id]; 340 last_suffixes[suffix[i].id] = i; 341 } 342 343 #ifdef DEBUG 344 debug_output(); 345 #endif 346 347 /* クラス構造の取出し */ 348 349 pendings = (struct pending_struct *) 350 malloc(sizeof(struct pending_struct) * (common_max+1)); 351 if(pendings == 0) error_alloc(); 352 level = 0; 353 pendings[level].length = 0; 354 pendings[level].start_suffix = 0; 355 for(j=0;j<MAX_C;j++) { 356 pendings[level].c[j] = 0; 357 } 358 for(i=0;i<size;i++) { 359 #ifdef DEBUG 360 debug_pending(); 361 debug_suffix(i); 362 #endif 363 /* 前処理, 新しいクラスの始まりかどうかのチェック */ 364 if(suffix[i].common > pendings[level].length) { 365 /* 現在の場所から新しいクラスを生成する。*/ 366 /* 新しいクラスは, カウント0から始める */ 367 level++; 368 pendings[level].start_suffix = i; 369 pendings[level].length = suffix[i].common; 370 for(j=0;j<MAX_C;j++) { pendings[level].c[j] = 0; } 371 } 372 373 /* 計数処理, 文字列の出現に関して適切なクラスを検索して計数す る */ 374 375 previous = suffix[i].previous_suffix; 376 pendings[level].c[0]++; 377 #ifdef DEBUG 378 printf(" -> Incrementing c[%d] of Class*[%d,%d] : (S%d,L%d) S= \"", 379 0, 380 i, 381 i, 382 pendings[level].start_suffix, 383 pendings[level].length 384 ); 385 for(ii=0;ii<pendings[level].length;ii++) { 386 putchar(text[suffix[pendings[level].start_suffix].position + ii]) ; 387 } 388 printf("\"\n"); 389 #endif 390 for(j=1;j<MAX_C;j++) { 391 int plev; 392 if(previous < 0) break; 393 plev = pending_level(previous); 394 pendings[plev].c[j]++; 395 #ifdef DEBUG 396 printf(" -> Incrementing c[%d] of Class*[%d,%d] : (S%d,L%d) S=\"", 397 j, 398 previous, 399 i, 400 pendings[plev].start_suffix, 401 pendings[plev].length 402 ); 403 for(ii=0;ii<pendings[plev].length;ii++) { 404 putchar(text[suffix[pendings[plev].start_suffix].position + ii]); 405 } 406 printf("\"\n"); 407 #endif 408 previous = suffix[previous].previous_suffix; 409 } 410 411 /* 後処理: classの終了の検出 */ 412 while(suffix[i].common < pendings[level].length) { 413 int common = suffix[i].common; 414 /* classの終了が発見されたとき */ 415 register_class( 416 pendings[level].start_suffix,/*start suffix */ 417 i, /*final suffix */ 418 pendings[level].length, /*maximum class length */ 419 pendings[level].c); 420 if(level <= 0) { fprintf(stderr, "internal level\n"); exit(2 ); } 421 if( common > pendings[level-1].length) { 422 /* 計算中として登録されていなかったクラスが存在した。 423 計算が終了したクラスと同じ場所からスタートする上位の 424 クラスの処理を開始 */ 425 pendings[level].length = common; 426 /* 上位のクラスにカウントを引き継ぐ, ただし 427 上位のクラスは現在, 計算中のクラスと同じ場所にあるので 428 実際の操作は不要である。 */ 429 430 } 431 if( common <= pendings[level-1].length) { 432 /* 上位のクラスのスタート場所は, 今よりも前でpendingになっている もの */ 433 for(j=0;j<MAX_C;j++) { 434 pendings[level-1].c[j] += pendings[level].c[j]; 435 } 436 level --; 437 } 438 /* 終了処理をしたあと, 再度終了しているかどうか調べる. */ 439 } 440 } 441 #ifdef DEBUG 442 debug_pending(); 443 #endif 444 make_class_table(); 445 clear_class_list(); 446 } 447 448 449 static int df_class_string_length(char *s) 450 { int i; 451 i = 0; 452 while(*s++) i++; 453 return i; 454 } 455 456 457 static int df_class_compare_string(char *x, char *s) 458 { 459 if(string_sub(x, s) != 0) return 0; 460 return( my_strcmp(x, s) ); 461 } 462 463 static int df_class_compare(int m, char *s) 464 { 465 char *x; int r; 466 x = text + suffix[class_table[m].first].position; 467 r = df_class_compare_string(x, s); 468 if(r != 0) return r; 469 if (class_table[m].length > df_class_string_length(s)) return 1; 470 if (class_table[m].length < df_class_string_length(s)) return -1 ; 471 return 0; 472 } 473 474 475 476 static int df_class_binary(char * s) 477 { 478 int min; int max; int mid; int cmp; 479 /* cf>=2のclass にあるかどうか検索する */ 480 min = 0; 481 max = class_count-1; 482 while(min+1<max) { 483 mid = (max + min) / 2; 484 cmp = df_class_compare(mid, s); 485 if(cmp < 0) { min = mid; } else {max =mid; } 486 }; 487 if((string_sub(text+suffix[class_table[min].first].position, s) != 0) && 488 (string_sub(text+suffix[class_table[min].last].position, s) ! = 0) 489 ) return min; 490 if((string_sub(text+suffix[class_table[max].first].position, s) != 0) && 491 (string_sub(text+suffix[class_table[max].last].position, s) ! = 0) 492 ) return max; 493 /* cf=1であるかどうかどうか検索する */ 494 min = 0; 495 max = size-1; 496 while(min+1<max) { 497 mid = (max + min) / 2; 498 cmp = df_class_compare_string(text+suffix[mid].position, s); 499 if(cmp < 0) { min = mid; } else { max = mid; } 500 } 501 if(string_sub(text+suffix[min].position, s) != 0) return -1; 502 if(string_sub(text+suffix[max].position, s) != 0) return -1; 503 return -2; 504 } 505 506 static int df_class(char * s) 507 { 508 int c; 509 c = df_class_binary(s); 510 #ifdef DOCUMENTATION 511 if(c != df_class_simple(s)) { 512 fprintf(stderr, "%d %d %s\n", c, df_class_simple(s), s); 513 } 514 #endif 515 return c; 516 } 517 518 519 int cf(char *s) 520 { 521 int c; 522 c = df_class(s); 523 if(c < -1) return 0; 524 if(c < 0) return 1; 525 return class_table[c].c[0]; 526 } 527 528 529 static int df1(char *s) 530 { 531 int c; 532 c = df_class(s); 533 if(c < -1) return 0; 534 if(c < 0) return 1; 535 return class_table[c].c[0] - class_table[c].c[1]; 536 } 537 538 int dfn(int k, char *s) 539 { int c; 540 if(k>= MAX_C) { 541 fprintf(stderr, "%d: dfn K too large\n", k); 542 } 543 if(k==1) return df1(s); 544 c = df_class(s); 545 if(c< 0) return 0; 546 return class_table[c].c[k-1] - class_table[c].c[k]; 547 } 548 549 char line[1024]; 550 551 int main(int argc, char ** argv) 552 { int i; 553 if(argc != 2) { 554 fprintf(stderr, "Usage %s filename > output\n", argv[0]); 555 exit(1); 556 } 557 df_setup(argv[1]); 558 #ifdef DEBUG 559 fprintf(stdout, "total=%d\n", class_count); 560 for(i=0;i<class_count;i++) { 561 output_class( class_table[i].first, 562 class_table[i].last, 563 class_table[i].length, 564 class_table[i].c 565 ); 566 } 567 #endif 568 while(fgets(line, sizeof(line), stdin)) { 569 i = strlen(line); 570 line[i-1] = 0; 571 fprintf(stdout, "%d ", cf(line)); 572 for(i=1;i<MAX_C;i++) { 573 fprintf(stdout, "%d ", dfn(i, line)); 574 } 575 fprintf(stdout, "%s\n", line); 576 } 577 return 0; 578 }
【0137】
【発明の効果】本発明によれば、文字列の出現頻度を効
率よく計数することができる。
【図面の簡単な説明】
【図1】 実施の形態に係る計数方法に用いられるSuff
ix Arrayのデータ構造を説明する図である。
【図2】 Suffix Arrayの各suffixに対するcommonの値
を示す図である。
【図3】 クラスを形成するSuffix Arrayの区間を例示
する図である。
【図4】 Suffix Arrayのクラスの階層構造を示す図で
ある。
【図5】 図4のSuffix Arrayのクラスに属する部分文
字列を説明する図である。
【図6】 図6(a)は6つのドキュメントを含むコー
パスの例を示す図であり、図6(b)は図6(a)のコ
ーパスに含まれる文字列に関する文字列頻度とドキュメ
ント頻度の計算例を示す図である。
【図7】 図7(a)はコーパスに含まれるドキュメン
トの一つを示す図であり、図7(b)はSuffix Arrayの
各suffixの重複度を示す図である。
【図8】 図8(a)は3つのドキュメントを含むコー
パスを示す図であり、図8(b)は図8(a)のコーパ
スに含まれる文字列に関する重複度つきの文字列頻度と
ドキュメント頻度の計算例を示す図である。
【図9】 図9(a)、(b)、(c)はpreviousリン
クの説明図である。
【図10】 実施の形態に係る計数装置の構成図であ
る。
【図11】 実施の形態に係る計数処理手順のフローチ
ャートである。
【符号の説明】
10 計数処理部、 12 Suffix Array生成部、 1
4 文字列頻度計数部、 16 文書頻度算出部、 1
8 問い合わせ部、 20 検索部、 22キーワード
抽出部、 24 文書データベース、 26 文書ファ
イル、 28Suffix Arrayファイル、 30 文字列出
現頻度データ、 32 キーワードインデックスファイ
ル、 100 計数装置。

Claims (14)

    【特許請求の範囲】
  1. 【請求項1】 文書の集合に対して、文字列がk(kは
    2以上の自然数)回以上出現する回数と前記文字列がk
    +1回以上出現する回数とを計数してそれらの回数の差
    を求めることにより、前記文字列がk回以上含まれる文
    書の数を取得する計数処理部を含むことを特徴とする計
    数装置。
  2. 【請求項2】 前記計数処理部は、前記文書内に含まれ
    る部分文字列の集合を、同一クラスに属する部分文字列
    についてはその部分文字列が同一文書に出現する回数が
    同じになるようなクラスに分類しながら、前記出現回数
    を前記クラス単位で計数することを特徴とする請求項1
    に記載の計数装置。
  3. 【請求項3】 前記計数処理部は、前記クラスの階層構
    造を利用して、下位クラスにおいて計数された出現回数
    を上位クラスにおいて計数される出現回数に加算するこ
    とにより前記出現回数の計数を行うことを特徴とする請
    求項2に記載の計数装置。
  4. 【請求項4】 複数の文書を含むコーパスに対して、前
    記文書のある位置の文字から前記文書の終了までの範囲
    の文字列の集合であって、その集合が辞書順に並べられ
    たサフィックスアレイを生成する工程と、 与えられた文字列xの出現のうち、重複度がk(kは2
    以上の自然数)以上の文字列の出現頻度cf(x)を
    計数する工程と、 前記文字列xがk回以上出現する文書の数df(x)
    をcf(x)とcf k+1(x)の差により求める工
    程とを含むことを特徴とする文字列の出現頻度の計数方
    法。
  5. 【請求項5】 前記サフィックスアレイのクラス分けで
    あって、同一クラスに属する文字列についてはその文字
    列が同一文書に出現する回数が同じになるようなクラス
    分けを生成する工程をさらに含み、 前記クラス分けによる各クラスについて前記出現頻度c
    (x)を計数することを特徴とする請求項4に記載
    の計数方法。
  6. 【請求項6】 前記クラス分けを生成する工程により、
    階層構造をなすクラス分けが生成され、前記出現頻度c
    (x)を計数する工程において、下位クラスにおい
    て計数された出現頻度cf(x)が上位クラスにおい
    て計数される出現頻度に加算されることを特徴とする請
    求項5に記載の計数方法。
  7. 【請求項7】 前記出現頻度cf(x)を計数する工
    程における重複度の判定と、前記クラス分けを生成する
    工程におけるクラスの検出とが同時になされることを特
    徴とする請求項5または6に記載の計数方法。
  8. 【請求項8】 文書の集合に対して文字列の出現頻度を
    計数する計数処理部と、 前記文字列の前記出現頻度に関するデータを記録する記
    録部とを含み、 前記計数処理部は、 前記文書のある位置の文字から前記文書の終了までの範
    囲の文字列の集合であって、その集合が辞書順に並べら
    れたサフィックスアレイを生成するサフィックスアレイ
    生成部と、 前記サフィックスアレイのクラス分けのクラスの検出と
    同時に、前記文字列の出現の重複度の判定を行うことに
    より、前記クラス単位で前記文字列が重複して出現する
    頻度を計数する文字列頻度計数部と、 前記文字列の出現頻度にもとづいて前記文字列が出現す
    る文書の頻度を算出する文書頻度算出部とを含むことを
    特徴とする計数装置。
  9. 【請求項9】 前記サフィックスアレイの各サフィック
    スは、当該サフィックスと同一文書に属し、かつ前記サ
    フィックスアレイの配列順で当該サフィックスの直前に
    あるサフィックスへのポインタをもち、前記文字列頻度
    計数部は、このポインタを前記重複度の回数だけ順次た
    どることができるか否かにより前記重複度の判定を行う
    ことを特徴とする請求項8に記載の計数装置。
  10. 【請求項10】 前記文字列頻度計数部は、前記サフィ
    ックスアレイを階層的なクラス構造にクラス分けし、下
    位クラスにおいて計数された前記文字列の前記出現頻度
    を上位クラスにおいて計数される前記出現頻度に加算す
    ることを特徴とする請求項8または9に記載の計数装
    置。
  11. 【請求項11】 前記文書頻度算出部は、前記文字列が
    k(kは自然数)回以上出現する文書の頻度を、前記文
    字列についての前記重複度がk以上の出現頻度と前記重
    複度がk+1以上の出現頻度との差により求めることを
    特徴とする請求項8から10のいずれかに記載の計数装
    置。
  12. 【請求項12】 前記文字列が2回以上出現する文書の
    頻度を用いて前記文書からキーワードを抽出するキーワ
    ード抽出部をさらに含むことを特徴とする請求項8から
    11のいずれかに記載の計数装置。
  13. 【請求項13】 複数の文書を含むコーパスに対して、
    前記文書のある位置の文字から前記文書の終了までの範
    囲の文字列の集合であって、その集合が辞書順に並べら
    れたサフィックスアレイを生成する工程と、 前記サフィックスアレイの階層的なクラス構造に係るク
    ラスを検出するとともに、そのクラス単位で、与えられ
    た文字列xの出現のうち、重複度がk(kは2以上の自
    然数)以上の文字列の出現頻度cf(x)を計数する
    工程と、 下位クラスにおいて計数された出現頻度cf(x)を
    上位クラスにおいて計数される出現頻度に加算する工程
    と、 前記文字列xがk回以上出現する文書の数df(x)
    を、前記文字列についての前記重複度がk以上の前記出
    現頻度cf(x)と前記重複度がk+1以上の前記出
    現頻度cfk+1(x)との差により求める工程とをコ
    ンピュータに実行させることを特徴とするコンピュータ
    プログラム。
  14. 【請求項14】 記号のシーケンスが複数含まれる集合
    に対して、前記シーケンス内に含まれる部分記号列の集
    合を、同一クラスに属する部分記号列についてはその部
    分記号列が同一シーケンスに出現する回数が同じになる
    ような階層的なクラスに分類しながら、任意の記号列が
    k(kは2以上の自然数)回以上出現する回数を前記ク
    ラス単位で計数し、前記任意の記号列がk回以上含まれ
    る前記シーケンスの数を求めることを特徴とする記号列
    の出現頻度の計数方法。
JP2002026458A 2001-11-28 2002-02-04 文字列の出現頻度の計数方法およびその方法を利用可能な装置 Pending JP2003228571A (ja)

Priority Applications (1)

Application Number Priority Date Filing Date Title
JP2002026458A JP2003228571A (ja) 2001-11-28 2002-02-04 文字列の出現頻度の計数方法およびその方法を利用可能な装置

Applications Claiming Priority (3)

Application Number Priority Date Filing Date Title
JP2001363378 2001-11-28
JP2001-363378 2001-11-28
JP2002026458A JP2003228571A (ja) 2001-11-28 2002-02-04 文字列の出現頻度の計数方法およびその方法を利用可能な装置

Publications (1)

Publication Number Publication Date
JP2003228571A true JP2003228571A (ja) 2003-08-15

Family

ID=27759427

Family Applications (1)

Application Number Title Priority Date Filing Date
JP2002026458A Pending JP2003228571A (ja) 2001-11-28 2002-02-04 文字列の出現頻度の計数方法およびその方法を利用可能な装置

Country Status (1)

Country Link
JP (1) JP2003228571A (ja)

Cited By (6)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
WO2008014702A1 (fr) * 2006-07-25 2008-02-07 Beijing Sogou Technology Development Co., Ltd. Procédé et système d'extraction de mots nouveaux
JP2009116559A (ja) * 2007-11-06 2009-05-28 Hitachi Ltd 大量配列の一括検索方法及び検索システム
JP2009244996A (ja) * 2008-03-28 2009-10-22 Hitachi High-Technologies Corp 文字列検索システム及び方法
CN103186618A (zh) * 2011-12-30 2013-07-03 北京新媒传信科技有限公司 正确数据的获取方法和装置
WO2015025751A1 (ja) * 2013-08-23 2015-02-26 日本電気株式会社 頻出系列の列挙装置、方法および記録媒体
WO2015143708A1 (zh) * 2014-03-28 2015-10-01 华为技术有限公司 后缀数组的构造方法及装置

Cited By (6)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
WO2008014702A1 (fr) * 2006-07-25 2008-02-07 Beijing Sogou Technology Development Co., Ltd. Procédé et système d'extraction de mots nouveaux
JP2009116559A (ja) * 2007-11-06 2009-05-28 Hitachi Ltd 大量配列の一括検索方法及び検索システム
JP2009244996A (ja) * 2008-03-28 2009-10-22 Hitachi High-Technologies Corp 文字列検索システム及び方法
CN103186618A (zh) * 2011-12-30 2013-07-03 北京新媒传信科技有限公司 正确数据的获取方法和装置
WO2015025751A1 (ja) * 2013-08-23 2015-02-26 日本電気株式会社 頻出系列の列挙装置、方法および記録媒体
WO2015143708A1 (zh) * 2014-03-28 2015-10-01 华为技术有限公司 后缀数组的构造方法及装置

Similar Documents

Publication Publication Date Title
CN106649260B (zh) 基于评论文本挖掘的产品特征结构树构建方法
CN109886294B (zh) 知识融合方法、装置、计算机设备和存储介质
US7689588B2 (en) Method of syntactic pattern recognition of sequences
US8533203B2 (en) Identifying synonyms of entities using a document collection
US8478737B2 (en) Segmentation of search topics in query logs
US20060206306A1 (en) Text mining apparatus and associated methods
CN110807102B (zh) 知识融合方法、装置、计算机设备和存储介质
US20100211588A1 (en) Context-Aware Query Suggestion By Mining Log Data
CN107844533A (zh) 一种智能问答***及分析方法
Verma et al. A novel approach for text summarization using optimal combination of sentence scoring methods
CN110851584A (zh) 一种法律条文精准推荐***和方法
CN111325018A (zh) 一种基于web检索和新词发现的领域词典构建方法
Eichinger et al. Sequence mining for customer behaviour predictions in telecommunications
JP6108212B2 (ja) 同義語抽出システム、方法およびプログラム
CN114816962A (zh) 基于attention-lstm的网络故障预测方法
JPH11328317A (ja) 日本語文字認識誤り訂正方法及び装置、並びに、誤り訂正プログラムを記録した記録媒体
Brodal et al. Finding maximal quasiperiodicities in strings
Minkov et al. Learning graph walk based similarity measures for parsed text
JP2003228571A (ja) 文字列の出現頻度の計数方法およびその方法を利用可能な装置
KR20230025102A (ko) 기계학습 기반의 지능형 법률 판례 검색 및 통합형 법률 서비스 방법 및 장치
CN116628628B (zh) 基于检索信息的用户信息素养分析方法、***及存储介质
Ajitha et al. EFFECTIVE FEATURE EXTRACTION FOR DOCUMENT CLUSTERING TO ENHANCE SEARCH ENGINE USING XML.
Min et al. A Longest Matching Resource Mapping Algorithm with State Compression Dynamic Programming Optimization.
CN116126893B (zh) 一种数据关联检索方法、装置及相关设备
CN113656574B (zh) 用于搜索结果排序的方法、计算设备和存储介质

Legal Events

Date Code Title Description
A621 Written request for application examination

Free format text: JAPANESE INTERMEDIATE CODE: A621

Effective date: 20050107

A131 Notification of reasons for refusal

Free format text: JAPANESE INTERMEDIATE CODE: A131

Effective date: 20071218

A02 Decision of refusal

Free format text: JAPANESE INTERMEDIATE CODE: A02

Effective date: 20080408