レベル: 中級 Geert Josten, Consultant/Content Engineer, Daidalos BV
2009年 9月 29日 データの変換とは、適切ではないソースやフォーマットの情報を適切な形の情報に移行させるプロセスであり、大抵は精密科学に属するものではありません。このような変換に関する正確さを測定する手段がデータ・スコアリングです。この記事では、小規模なテキストから XML への変換結果に適用できる、XQuery での単純な採点 (スコアリング) 手法を紹介します。
 |
よく使われる頭字語
- HTML: Hypertext Markup Language
- W3C: World Wide Web Consortium
- URL: Uniform Resource Locator
- XML: Extensible Markup Language
- XSLT: Extensible Stylesheet Transformations
|
|
変換後のデータを採点するということは、要は変換の品質を分析することです。品質という言葉は何通りにも解釈することができます。さらに、データベースのデータを変換する場合には、自然言語で作成された文書のデータを変換する場合に比べ、さまざまな問題が伴いがちです。このヒントで説明する手法には何の前提条件もないので、対象とする任意の XML コードに適用することができます。この手法を実際に確かめるために、これからプレーン・テキストを変換します。つまり、カンマ区切りのファイルではなく、インターネットから入手したニュース項目のプレーン・テキストです。
プレーン・テキストの入力
ソース用のテキストは、URL http://news.google.com/news/section?pz=1&topic=w&ict=ln で Google ニュース Web サイトにアクセスし、そこから取得しました。その時点で表示されたページを図 1 に示します。
図 1. Google ニュースに表示されたニュース項目のサンプル
これらのニュース項目には基本構造があります。つまり、先頭に見出しがあり、それに続いて発信ソースの詳細、ニュースのメッセージ本文、そして別の発信ソースからの追加情報が記載されるという構造です。このヒントでは、ヘッドライン (headline)、発信地 (location)、本文 (text)、関連ヘッドライン (related headline)、関連ヘッドラインの発信ソース (source) を抽出します。図 2 に、これらの要素を示します。
図 2. サンプル Google ニュース項目のテキストの分析
このヒントの例のために、その時点でトップに掲載されていた 3 つのニュース項目を選択し、テキストをコピーしました。そしてこのヒントで取り上げない行については、スペースを節約するために削除しました。また、作業に取り掛かりやすいように、テキストはすでに個々のニュース項目ごとに分けてあります。
 | 行末
XQuery を扱うときには、オペレーティング・システムが何であろうと関係なく、メモリー内で行末は常に数字の 10 で表されます。
|
|
リスト 1 に、使用する入力データを記載します (行末を視覚的に表すために、段落記号 (¶) を追加してあります)。文字参照 " は、二重引用符を表します。
リスト 1. プレーン・テキスト
let $news-items := (
"Afghans go to polls under threat of Taliban violence¶
KABUL, Afghanistan (CNN) - Under the menacing threat of violence from the
Taliban, Afghans headed to the polls on Thursday in the war-ravaged nation's
second-ever national election.¶
Afghan people cast votes in hope of better future RT",
"Security stepped up after Baghdad bombings¶
BAGHDAD, Iraq (CNN) - The Iraqi government implemented new security measures a
day after a string of bombings in Baghdad killed at least 100 people and wounded
hundreds more, an interior ministry official told CNN on Thursday.¶
Questioning security in Baghdad's Green Zone - 19 Aug 09 Al Jazeera",
"Will Democrats Go At It Alone on the Health Care Bill?¶
This is a rush transcript from "On the Record," August 19, 2009. This copy may not
be in its final form and may be updated.¶
New Health Care Strategy CBS"
)
|
実際の採点手法を確認するために、これからパターンを定義して情報を抽出し、その情報を XML に変換し、そして変換結果にこの採点手法を適用してみます。ここで大きな問題となるのは、パターンを見つけることではなく、このようなパターンを信頼できる抽出ルールに変換することです。この手法は、独自のルールの信頼性を分析する上で有益なツールとなります。
パターンを適用するには、まずは各ニュース項目の構造を分解しなければなりません。それぞれのニュース項目には、以下の 3 つのデータ行があります。
- ヘッドライン
- 本文
- 関連ニュース項目のヘッドライン
すべてのニュース項目を繰り返し処理し、以下のように行末でトークン化することによって行を区別します。
let $result :=
for $news-item in $news-items
let $lines := tokenize($news-item, ' ')
|
result 変数が、XML の結果を取り込みます。
パターンの適用
変換品質の分析に関心が向けられるのは、情報が欠落している場合、あるいは情報が結合されているために分離しなければならない場合のみです。このヒントでは、この 2 つの場合について取り上げます。まず、それぞれの行を調べて、結合された情報を分離するためのパターンを見つけます。
最初の行
最初の行にはヘッドラインしかないので、normalize-space を適用して余分なスペースを削除します。
let $headline := normalize-space($lines[1])
|
2 番目の行
2 番目の行 (本文が含まれる行) には、明らかに最も多くの情報が含まれますが、この行で信頼できるパターンはニュースの発信地だけです。ニュースの発信地は行の先頭にあり、その後にダッシュが続きます。そこで、このダッシュを利用して、発信地を本文から分離します。
let $location := normalize-space(substring-before($lines[2], '-'))
let $text := normalize-space(substring-after($lines[2], '-'))
|
3 番目の行
3 番目の行は、3 つの行のなかで最も厄介です。この行には関連ヘッドラインとその発信ソースの名前が含まれていますが、この 2 つを視覚的に分離するマーカーは使用されていません。すべての発信ソースの名前を把握することはできないので、名前を突き合わせるのは文字通り不可能ですが、発信ソースの名前は通常大文字で始まるので、正規表現によって対応することはできます。
let $related-headline :=
normalize-space(replace($lines[3], '^(.*?) [A-Z].*$', '$1'))
let $related-headline-source :=
normalize-space(replace($lines[3], '^.*? ([A-Z].*)$', '$1'))
|
基本的に上記の正規表現で突き合わせているのは、行の先頭 (^) から末尾 ($) までのストリングです。.*? は、スペースに続く大文字が最初に出てくるところまで、突き合わせをすることで、ヘッドラインの本文の部分を取得します。そのヘッドラインの発信ソースを取得するのは、[A-Z].* の部分です。対象とする部分を開始括弧と終了括弧 (「(」、および「)」) で囲み、その部分の置換として $1 を使用することにより、括弧で囲んだ部分に応じてヘッドラインまたは発信ソースのいずれかを取得することができます。
変換結果
抽出した情報には、リスト 2 の行を追加してタグを付けます。
リスト 2. 抽出した情報を XML に変換する
return
<news-item>{
if ($headline) then
<headline>{$headline}</headline>
else (),
if ($location) then
<location>{$location}</location>
else (),
if ($text) then
<text>{$text}</text>
else (),
if ($related-headline) then
<related-headline>{$related-headline}</related-headline>
else (),
if ($related-headline-source) then
<related-headline-source>{
$related-headline-source
}</related-headline-source>
else ()
}</news-item>
|
各タグを囲む if 文は、空ではない値が含まれるタグのみが書き込まれるようにするためのものです。これまでの式をすべて 1 つにまとめて以下の行を追加すれば、最初のニュース項目を出力することができます。
リスト 3 に、期待される出力を記載します。
リスト 3. 最初のニュース項目の XML 出力
<news-item>
<headline>Afghans go to polls under threat of Taliban violence</headline>
<location>KABUL, Afghanistan (CNN)</location>
<message>Under the menacing threat of violence from the
Taliban, Afghans headed to the polls on Thursday in the war-ravaged nation's
second-ever national election.</message>
<related-headline>Afghan people cast votes in hope of better future</related-headline>
<related-headline-source>RT</related-headline-source>
</news-item>
|
このようにしてすべてのニュース項目を変換した後、いよいよ変換の品質を採点します。
変換結果の要素に対する採点
変換結果の品質を分析するには、いくつかの手法のなかから必要に応じた手法を選択することができます。ここで紹介する手法は基本的なものなので、さまざまな方法で使用することができます。この手法では、以下の 2 つの詳細レベルで統計を表示します。
- 対象要素ごとの採点
- 特定の対象要素に関する個別要素値の採点
この変換結果で対象とする要素は、テキストを構成する以下の要素すべてです。
headline
location
text
related-headline
related-headline-source
対象要素ごとの採点では、当該要素のなかで変換された要素の数をカウントし、ニュース項目の合計数に対して比率を計算するだけにすぎません。合計数は、XQuery を使用して計算することができます (ニュース項目の XML 出力は、$result という変数に取り込まれていることに注意してください)。
let $element-name = 'headline'
let $element-score := count($result//*[local-name() = $element-name])
let $element-ratio := round(100 * $element-score div count($news-items))
|
要素を突き合わせる際に、要素のローカル名を基準に行うという方法は速度の点では遅いものの、コードが簡潔になり、スクリプトがより動的になります。リスト 4 では、計算結果を小さな HTML レポート内にラップしています。
リスト 4. 要素の採点レポートを作成する
let $total-number-of-items := count($news-items)
let $elements-of-interest :=
('headline', 'location', 'text', 'related-headline',
'related-headline-source')
return
<html>
<body>
<p><b>Total number of items: </b>{$total-number-of-items}</p>
<table border="1">
<tr>
<th>element name</th>
<th>score</th>
<th>ratio</th>
</tr>
{
for $element-name in $elements-of-interest
let $elements :=
$result//*[local-name() = $element-name]
let $element-score :=
count($elements)
let $element-ratio :=
round(100 * $element-score div $total-number-of-items)
return
<tr>
<td>{ $element-name }</td>
<td>{ $element-score }</td>
<td>{ concat($element-ratio,'%') }</td>
</tr>
}</table>
</body>
</html>
|
リスト 4 のコードでは、まず始めに、比率 (ratio) が意味のある値になるように、分析対象とするニュース項目の数をカウントしています。次に、すべての対象要素をループ処理してスコア (score) および比率を計算し、それぞれに対応する表内の行に書き込みます。変換結果のレポートは、図 3 のように示されます (ここをクリックすると、図 3 のテキストのみのバージョンが表示されます)。
図 3. 変換結果の要素に対する採点
スコアは高いように見えますが、発信地 (location) と本文 (text) はいくつか欠落しています。続いて、要素の値を採点して変換結果を調べます。
変換結果の値に対する採点
 | 大規模なデータ・セットで値を採点する場合
この採点手法を大規模なデータ・セットで適用すると、レポートを生成する際の計算にかなりの時間がかかることになります。そのため、このコードをまず小さなセットでテストして、計算時間が 1 秒を超えるようであれば XQuery プロセッサーの機能を十分に利用するようにコードを最適化するという方法を検討してください。XQuery 対応の XML データベースを使用すれば、索引を利用してさらに処理時間を短縮することができます。
|
|
要素の値を採点するのは、要素を採点する場合と同じく、難しいことではありません。各要素の個別の値を判定し、値ごとにスコアと比率を計算するだけの話です。
欠落している要素のスコアと比率を計算することで、詳しい情報を取得することができます。リスト 4 のコードの代わりにリスト 5 のコードを使用してください。
リスト 5. 要素と値の採点レポートを作成する
<html>
<body>
<p><b>Total number of items: </b>{$total-number-of-items}</p>
<table border="1" width="50%">
<tr>
<th colspan="2">element name</th>
<th colspan="2">score</th>
<th colspan="2">ratio</th>
</tr>
{
for $element-name in $elements-of-interest
let $elements :=
$result//*[local-name() = $element-name]
let $element-score :=
count($elements)
let $element-ratio :=
round(100 * $element-score div $total-number-of-items)
return (
<tr>
<td colspan="2">{ $element-name }</td>
<td colspan="2">{ $element-score }</td>
<td colspan="2">{ concat($element-ratio,'%') }</td>
</tr>,
let $distinct-values :=
distinct-values($elements)
for $distinct-value in $distinct-values
let $value-score :=
count($elements[. = $distinct-value])
let $value-ratio :=
round(100 * $value-score div $total-number-of-items)
return
<tr>
<td> </td>
<td><i>{ $distinct-value }</i></td>
<td> </td>
<td><i>{ $value-score }</i></td>
<td> </td>
<td><i>{ concat($value-ratio,'%') }</i></td>
</tr>,
let $missing-score :=
$total-number-of-items - $element-score
let $missing-ratio :=
round(100 * $missing-score div $total-number-of-items)
where $missing-score > 0
return
<tr>
<td> </td>
<td><i><b>(not found)</b></i></td>
<td> </td>
<td><i>{ $missing-score }</i></td>
<td> </td>
<td><i>{ concat($missing-ratio,'%') }</i></td>
</tr>
)}
</table>
</body>
</html>
|
このバージョンのレポートでは、HTML の表に 6 つの列がありますが、それ以外については前のコードと変わりありません。リスト 5 はリスト 4 のコードを、各ニュース項目にサブループを実行するように拡張しているだけです。このサブループによって、ニュース項目の各要素の値をすべて処理し、処理した個々の値とそのスコアおよび比率を、表に行を追加して出力します。また、該当する要素が結果から欠落している場合にも、欠落していることを示す行を表に追加します。
スコアの分析
この採点レポートは、少なくとも以下の 3 つの使用ケースで役立ちます。
欠落
要素のスコア・レポート (図 3 または 図 3 のテキスト・バージョン) では、発信地 (location) と本文 (text) のスコアが低いことが示されました。図 4 に、値の採点レポートで、この 2 つの要素に対応する部分を示します (ここをクリックすると、図 4 のテキストのみのバージョンが表示されます)。
図 4. 発信地 (location) と本文 (text) の値に対する採点
このレポートには、発信地を抽出できなかったニュース項目が 1 つ、そして本文を抽出できなかったニュース項目が 1 つあったことが示されています。これらの欠落は、同じニュース項目に関連している可能性が考えられます。残念ながらこのレポートからは、これらの項目の変換が失敗した理由を判断する上で必要な情報は得られませんが、このレポートは少なくとも変換が失敗したことは示しています。そこで、コンテンツを調べて、どのようなパターンがこの 2 つの要素に隠れているのか、もう一度検討してみましょう。
前述したように、発信地 (location) と本文 (text) はダッシュによって互いに分離されています。リスト 1 をもう一度見てみると、ニュース項目のうちの 1 つでは、2 番目の行が発信地で始まっていません。ダッシュがないために、発信地と本文を分離するパターンが適用されなかったというわけです。
値の分布
これらのレポートは、欠落を特定するだけでなく、値の分布を分析するためにも使用できます。今回変換したのは 3 つのアイテムだけなので、スクリプト全体を実行してレポートを調べてみるとわかるように、それぞれの値は一度しか出現しません。これよりも大きなデータ・セットのレポートを使用して、この使用ケースを試してみてください。
異常
3 つ目の使用ケースは、要素の値を検査して異常を見つけ出すことです。図 5 に抜粋した値の採点レポートの部分は、related-headline 要素と related-headline-source 要素について明らかにしています (ここをクリックすると、図 5 のテキストのみのバージョンが表示されます)。
図 5. 関連ヘッドラインおよび発信ソースの値に対する採点
抽出ルールは成功しているにも関わらず、誤った値を生成していることに注目してください。related-headline-source の値は、本来ならば以下の値になるはずです。
正しい値を生成するのは難しいとは言え、このレポートがこのような誤りを見つけ出すのに役立つことは確かです。有効な発信ソースの目録がある場合には、取得した値の妥当性を検査する際にその目録を利用することで、誤っている値については通知するか、または誤検出として除外するという方法をとることができます。
まとめ
この記事では、小さなテキストを XML に変換した結果に対して、単純な計算を使って要素と値を採点した簡単な HTML レポートを生成しました。そして生成したレポートを利用して、この変換の品質分析、欠落の特定、値の分布の分析、異常の検出を行うことができました。この採点手法は、変換結果の品質を分析する上で役立つツールとなるはずです。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Source file for this tip | data-scoring.xqy.zip | 2KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Geert Josten は、Daidalos のコンテンツ・エンジニアとして 10 年近く、XSLT と XQuery、そしてその他の独自仕様の変換言語に関する知識を応用してきました。また Daidalos では Web および Java 開発者としても、これまでさまざまな分野で何十ものカスタマーの顧問を務めてきました。 |
記事の評価
|