自然言語処理(ソフトウェアアプリケーションが人間の言語を処理できるようにするテクノロジー)は、ここ数年でかなり普及しています。
Google検索はますます自然な質問に答えることができるようになり、AppleのSiriはさまざまな質問を理解できるようになり、ますます多くの企業が(合理的に)インテリジェントなチャットボットや電話ボットを使用して顧客と通信しています。しかし、この一見「スマート」なソフトウェアは実際にどのように機能するのでしょうか。
この記事では、これらのアプリケーションを機能させるテクノロジーについて学び、独自の自然言語処理ソフトウェアを開発する方法を学びます。
この記事では、ニュース関連性アナライザーを構築するプロセスの例について説明します。株式ポートフォリオがあり、人気のあるニュースWebサイトを自動的にクロールして、ポートフォリオに関連する記事を特定するアプリが必要だとします。たとえば、株式ポートフォリオにMicrosoft、BlackStone、Luxotticaなどの企業が含まれている場合、これら3つの企業について言及している記事を表示する必要があります。
自然言語処理アプリは、他の機械学習アプリと同様に、連携して動作する比較的小さく、シンプルで直感的なアルゴリズムに基づいて構築されています。多くの場合、これらのアルゴリズムがすべてすでに実装および統合されている外部ライブラリを使用することは理にかなっています。
この例では、 スタンフォードNLPライブラリ 、多くの言語をサポートする強力なJavaベースの自然言語処理ライブラリ。
私たちが関心を持っているこのライブラリの特定のアルゴリズムの1つは、品詞(POS)タガーです。 POSタガーは、テキスト内のすべての単語に品詞を自動的に割り当てるために使用されます。このPOSタガーは、語彙の特徴に基づいてテキスト内の単語を分類し、周囲の他の単語との関連で分析します。
POSタガーアルゴリズムの正確な仕組みはこの記事の範囲を超えていますが、それについてもっと学ぶことができます ここに 。
まず、新しいJavaプロジェクトを作成し(お気に入りのIDEを使用できます)、依存関係のリストにStanfordNLPライブラリを追加します。 Mavenを使用している場合は、pom.xml
に追加するだけです。ファイル:
adobexdはいくらですか
edu.stanford.nlp stanford-corenlp 3.6.0 edu.stanford.nlp stanford-corenlp 3.6.0 models
アプリはWebページから記事のコンテンツを自動的に抽出する必要があるため、次の2つの依存関係も指定する必要があります。
de.l3s.boilerpipe boilerpipe 1.1.0
net.sourceforge.nekohtml nekohtml 1.9.22
これらの依存関係を追加すると、先に進む準備が整います。
アナライザーの最初の部分では、記事を取得し、Webページからコンテンツを抽出します。
c ++ <>
ニュースソースから記事を取得する場合、ページには通常、記事自体に関係のない無関係な情報(埋め込みビデオ、アウトバウンドリンク、ビデオ、広告など)がたくさんあります。ここが ボイルパイプ 登場します。
Boilerpipeは、平均的な文の長さ、コンテンツブロックで使用されるタグの種類、リンクの密度などの機能を使用してさまざまなコンテンツブロックを分析することにより、ニュース記事のメインコンテンツを識別する「クラッター」を削除するための非常に堅牢で効率的なアルゴリズムです。ボイラーパイプアルゴリズムは、マシンビジョンに基づくアルゴリズムなど、他のはるかに計算コストの高いアルゴリズムと競合することが証明されています。あなたはそのでもっと学ぶことができます プロジェクトサイト 。
Boilerpipeライブラリには、Webページのスクレイピングのサポートが組み込まれています。 WebからHTMLをフェッチし、HTMLからテキストを抽出し、抽出されたテキストをクリーンアップできます。 URLを受け取り、Boilerpipeを使用して、extractFromURL
を使用して最も関連性の高いテキストを文字列として返す関数、ArticleExtractor
を定義できます。このタスクの場合:
import java.net.URL; import de.l3s.boilerpipe.document.TextDocument; import de.l3s.boilerpipe.extractors.CommonExtractors; import de.l3s.boilerpipe.sax.BoilerpipeSAXInput; import de.l3s.boilerpipe.sax.HTMLDocument; import de.l3s.boilerpipe.sax.HTMLFetcher; public class BoilerPipeExtractor { public static String extractFromUrl(String userUrl) throws java.io.IOException, org.xml.sax.SAXException, de.l3s.boilerpipe.BoilerpipeProcessingException { final HTMLDocument htmlDoc = HTMLFetcher.fetch(new URL(userUrl)); final TextDocument doc = new BoilerpipeSAXInput(htmlDoc.toInputSource()).getTextDocument(); return CommonExtractors.ARTICLE_EXTRACTOR.getText(doc); } }
Boilerpipeライブラリは、ボイラーパイプアルゴリズムに基づいて、ArticleExtractor
を使用してさまざまなエクストラクタを提供します。 HTML形式のニュース記事用に特別に最適化されています。 ArticleExtractor
特に、各コンテンツブロックで使用されるHTMLタグとアウトバウンドリンク密度に焦点を当てています。これは、高速ですが単純なDefaultExtractor
よりも私たちのタスクに適しています。
組み込み関数がすべてを処理してくれます。
HTMLFetcher.fetch
HTMLドキュメントを取得しますgetTextDocument
テキストドキュメントを抽出しますCommonExtractors.ARTICLE_EXTRACTOR.getText
ボイラーパイプアルゴリズムを使用して、記事から関連するテキストを抽出します今、あなたはあなたが見つけることができる光学巨人エシロールとルックスオティカの合併に関するサンプル記事でそれを試すことができます ここに 。このURLを関数にフィードして、何が出力されるかを確認できます。
次のコードをメイン関数に追加します。
public class App { public static void main( String[] args ) throws java.io.IOException, org.xml.sax.SAXException, de.l3s.boilerpipe.BoilerpipeProcessingException { String urlString = 'http://www.reuters.com/article/us-essilor-m-a-luxottica-group-idUSKBN14Z110'; String text = BoilerPipeExtractor.extractFromUrl(urlString); System.out.println(text); } }
広告、HTMLタグ、アウトバウンドリンクなしで、記事の本文の出力に表示されます。これを実行したときに得たものの最初のスニペットは次のとおりです。
MILAN/PARIS Italy's Luxottica (LUX.MI) and France's Essilor (ESSI.PA) have agreed a 46 billion euro ( billion) merger to create a global eyewear powerhouse with annual revenue of more than 15 billion euros. The all-share deal is one of Europe's largest cross-border tie-ups and brings together Luxottica, the world's top spectacles maker with brands such as Ray-Ban and Oakley, with leading lens manufacturer Essilor. 'Finally ... two products which are naturally complementary -- namely frames and lenses -- will be designed, manufactured and distributed under the same roof,' Luxottica's 81-year-old founder Leonardo Del Vecchio said in a statement on Monday. Shares in Luxottica were up by 8.6 percent at 53.80 euros by 1405 GMT (9:05 a.m. ET), with Essilor up 12.2 percent at 114.60 euros. The merger between the top players in the 95 billion eyewear market is aimed at helping the businesses to take full advantage of expected strong demand for prescription spectacles and sunglasses due to an aging global population and increasing awareness about eye care. Jefferies analysts estimate that the market is growing at between...
そして、それは確かに記事の主要な記事の本文です。これがはるかに簡単に実装できるとは想像しがたいです。
記事の本文を正常に抽出したので、記事がユーザーに関心のある会社に言及しているかどうかを判断する作業を行うことができます。
文字列または正規表現の検索を単純に実行したくなるかもしれませんが、このアプローチにはいくつかの欠点があります。
まず第一に、文字列検索は誤検知を起こしやすい可能性があります。たとえば、Microsoft Excelに言及している記事には、Microsoftに言及しているというタグが付けられている場合があります。
第二に、正規表現の構成によっては、正規表現の検索によって偽陰性が発生する可能性があります。たとえば、「Luxotticaの四半期収益が予想を上回った」というフレーズを含む記事は、空白で囲まれた「Luxottica」を検索する正規表現検索では見逃される可能性があります。
最後に、多数の企業に関心があり、多数の記事を処理している場合、ユーザーのポートフォリオ内のすべての企業のテキスト全体を検索すると、非常に時間がかかり、許容できないパフォーマンスが得られる可能性があります。
アジャイルプロジェクト管理の概要
スタンフォードのCoreNLPライブラリ 多くの強力な機能があり、これら3つの問題すべてを解決する方法を提供します。
アナライザーには、品詞(POS)タガーを使用します。特に、POSタガーを使用して、記事内のすべての固有名詞を見つけ、それらを興味深い株式のポートフォリオと比較することができます。
NLPテクノロジーを組み込むことにより、タガーの精度を向上させ、上記の誤検知と誤検知を最小限に抑えるだけでなく、固有名詞は小さなサブセットしか含まないため、株式ポートフォリオと比較するために必要なテキストの量を大幅に最小限に抑えます。記事の全文の。
ポートフォリオを前処理して、 低い会員照会コスト 、記事の分析に必要な時間を劇的に短縮できます。
スタンフォードCoreNLPは、と呼ばれる非常に便利なタガーを提供します MaxentTagger ほんの数行のコードでPOSタグ付けを提供できます。
ビジネスにおけるCFOとは
簡単な実装は次のとおりです。
public class PortfolioNewsAnalyzer { private HashSet portfolio; private static final String modelPath = 'edu\stanford\nlp\models\pos-tagger\english-left3words\english-left3words-distsim.tagger'; private MaxentTagger tagger; public PortfolioNewsAnalyzer() { tagger = new MaxentTagger(modelPath); } public String tagPos(String input) { return tagger.tagString(input); }
タガー関数tagPos
は、文字列を入力として受け取り、元の文字列の単語と対応する品詞を含む文字列を出力します。メイン関数で、PortfolioNewsAnalyzer
をインスタンス化しますスクレーパーの出力をタガー関数にフィードすると、次のように表示されます。
MILAN/PARIS_NN Italy_NNP 's_POS Luxottica_NNP -LRB-_-LRB- LUX.MI_NNP -RRB-_-RRB- and_CC France_NNP 's_POS Essilor_NNP -LRB-_-LRB- ESSI.PA_NNP -RRB-_-RRB- have_VBP agreed_VBN a_DT 46_CD billion_CD euro_NN -LRB-_-LRB- $_$ 49_CD billion_CD -RRB-_-RRB- merger_NN to_TO create_VB a_DT global_JJ eyewear_NN powerhouse_NN with_IN annual_JJ revenue_NN of_IN more_JJR than_IN 15_CD billion_CD euros_NNS ._. The_DT all-share_JJ deal_NN is_VBZ one_CD of_IN Europe_NNP 's_POS largest_JJS cross-border_JJ tie-ups_NNS and_CC brings_VBZ together_RB Luxottica_NNP ,_, the_DT world_NN 's_POS top_JJ spectacles_NNS maker_NN with_IN brands_NNS such_JJ as_IN Ray-Ban_NNP and_CC Oakley_NNP ,_, with_IN leading_VBG lens_NN manufacturer_NN Essilor_NNP ._. ``_`` Finally_RB ..._: two_CD products_NNS which_WDT are_VBP naturally_RB complementary_JJ --_: namely_RB frames_NNS and_CC lenses_NNS --_: will_MD be_VB designed_VBN ,_, manufactured_VBN and_CC distributed_VBN under_IN the_DT same_JJ roof_NN ,_, ''_'' Luxottica_NNP 's_POS 81-year-old_JJ founder_NN Leonardo_NNP Del_NNP Vecchio_NNP said_VBD in_IN a_DT statement_NN on_IN Monday_NNP ._. Shares_NNS in_IN Luxottica_NNP were_VBD up_RB by_IN 8.6_CD percent_NN at_IN 53.80_CD euros_NNS by_IN 1405_CD GMT_NNP -LRB-_-LRB- 9:05_CD a.m._NN ET_NNP -RRB-_-RRB- ,_, with_IN Essilor_NNP up_IN 12.2_CD percent_NN at_IN 114.60_CD euros_NNS ._. The_DT merger_NN between_IN the_DT top_JJ players_NNS in_IN the_DT 95_CD billion_CD eyewear_NN market_NN is_VBZ aimed_VBN at_IN helping_VBG the_DT businesses_NNS to_TO take_VB full_JJ advantage_NN of_IN expected_VBN strong_JJ demand_NN for_IN prescription_NN spectacles_NNS and_CC sunglasses_NNS due_JJ to_TO an_DT aging_NN global_JJ population_NN and_CC increasing_VBG awareness_NN about_IN...
これまで、ニュース記事をダウンロード、クリーンアップ、タグ付けする機能を構築してきました。ただし、記事にユーザーが関心のある企業のいずれかが記載されているかどうかを判断する必要があります。
これを行うには、すべての固有名詞を収集し、ポートフォリオの株式がそれらの固有名詞に含まれているかどうかを確認する必要があります。
すべての固有名詞を見つけるには、最初にタグ付き文字列出力をトークンに分割し(スペースを区切り文字として使用)、次に各トークンをアンダースコア(_
)で分割し、品詞があるかどうかを確認します。固有名詞です。
固有名詞がすべて揃ったら、目的に合わせて最適化されたデータ構造にそれらを格納します。この例では、HashSet
を使用します。重複するエントリを禁止し、エントリの順序を追跡しないことと引き換えに、HashSet
非常に高速なメンバーシップクエリを可能にします。メンバーシップのクエリにのみ関心があるため、HashSet
私たちの目的に最適です。
以下は、固有名詞の分割と保存を実装する関数です。この関数をPortfolioNewsAnalyzer
に配置しますクラス:
public static HashSet extractProperNouns(String taggedOutput) { HashSet propNounSet = new HashSet(); String[] split = taggedOutput.split(' '); for (String token: split ){ String[] splitTokens = token.split('_'); if(splitTokesn[1].equals('NNP')){ propNounSet.add(splitTokens[0]); } } return propNounSet; }
ただし、この実装には問題があります。会社の名前が複数の単語で構成されている場合(たとえば、Luxotticaの例のCarl Zeiss)、この実装ではそれをキャッチできません。 Carl Zeissの例では、「Carl」と「Zeiss」が別々にセットに挿入されるため、「CarlZeiss」という単一の文字列が含まれることはありません。
この問題を解決するために、私たちはすべてを集めることができます 連続 固有名詞とそれらをスペースで結合します。これを実現する更新された実装は次のとおりです。
public static HashSet extractProperNouns(String taggedOutput) { HashSet propNounSet = new HashSet(); String[] split = taggedOutput.split(' '); List propNounList = new ArrayList(); for (String token: split ){ String[] splitTokens = token.split('_'); if(splitTokens[1].equals('NNP')){ propNounList.add(splitTokens[0]); } else { if (!propNounList.isEmpty()) { propNounSet.add(StringUtils.join(propNounList, ' ')); propNounList.clear(); } } } if (!propNounList.isEmpty()) { propNounSet.add(StringUtils.join(propNounList, ' ')); propNounList.clear(); } return propNounSet; }
これで、関数は個々の固有名詞のセットを返す必要があります そして 連続する固有名詞(つまり、スペースで結合されている)。 propNounSet
を印刷すると、次のように表示されます。
[... Monday, Gianluca Semeraro, David Goodman, Delfin, North America, Luxottica, Latin America, Rossi/File Photo, Rome, Safilo Group, SFLG.MI, Friday, Valentina Za, Del Vecchio, CEO Hubert Sagnieres, Oakley, Sagnieres, Jefferies, Ray Ban, ...]
ほぼ完了です!
前のセクションでは、記事の本文をダウンロードして抽出できるスクレーパー、記事の本文を解析して固有名詞を識別することができるタガー、およびタグ付けされた出力を取得して固有名詞を| _に収集するプロセッサーを構築しました。 + _ |。あとはHashSet
を取るだけです興味のある企業のリストと比較してください。
実装は非常に簡単です。 HashSet
に次のコードを追加しますクラス:
PortfolioNewsAnalyzer
これで、スクレイピング、クリーニング、タグ付け、収集、比較など、アプリケーション全体を実行できます。これは、アプリケーション全体で実行される関数です。この関数をprivate HashSet portfolio; public PortfolioNewsAnalyzer() { portfolio = new HashSet(); } public void addPortfolioCompany(String company) { portfolio.add(company); } public boolean arePortfolioCompaniesMentioned(HashSet articleProperNouns){ return !Collections.disjoint(articleProperNouns, portfolio); }
に追加しますクラス:
PortfolioNewsAnalyzer
最後に、アプリを使用できます!
ビジネスインテリジェンスと人工知能
上記と同じ記事を使用し、ポートフォリオ会社としてLuxotticaを使用した例を次に示します。
public boolean analyzeArticle(String urlString) throws IOException, SAXException, BoilerpipeProcessingException { String articleText = extractFromUrl(urlString); String tagged = tagPos(articleText); HashSet properNounsSet = extractProperNouns(tagged); return arePortfolioCompaniesMentioned(properNounsSet); }
これを実行すると、アプリは「記事がポートフォリオ企業に言及している」と出力するはずです。
ポートフォリオ会社をLuxotticaから記事に記載されていない会社(「Microsoft」など)に変更すると、アプリは「記事にはポートフォリオ会社が記載されていません」と表示されます。
この記事では、URLから記事をダウンロードし、Boilerpipeを使用して記事をクリーンアップし、Stanford NLPを使用して処理し、記事が特定の関心のある参照を行っているかどうかを確認するアプリケーションを構築するプロセスを順を追って説明しました(この場合、ポートフォリオ)。示されているように、この一連のテクノロジーを活用することで、他の方法では困難な作業が比較的簡単な作業になります。
この記事で、自然言語処理の有用な概念と手法が紹介され、独自の自然言語アプリケーションを作成するきっかけになったと思います。
[注:この記事で参照されているコードのコピーを見つけることができます ここに 。]