モチベーション
DX化が進む昨今、業務効率化において活躍しているのはテキスト処理の自動化だったりします。まずはコピー&ペーストをしなくて済むようになるだけで実際かなり単純作業に費やす手間がカットされます。次にオンライン上にある膨大なテキストデータを自分の頭で読み込むのではなくコンピューターに読み込ませてほしい情報を取り出してもらう、これがあるとかなり仕事が楽になります。人間は基本的にとても高性能なのですが情報の処理だけにリソースを使用できるわけではなく、体のバランスを取ったり動かしたり、ものを見たり音を聞いたりとにかく様々なことにリソースを使っているので、目の前の仕事のテキストを読み込むことにすごくたくさんのリソースを割くことができるかというと実はそうでもない、というのが現実です。実際僕もスプレッドシートにある情報にマッチする不動産物件をページ上から探し出すとか、顧客の注文情報から取引先へと発注する文面を生成する自動処理機能などを業務で開発することがあって、大した機能ではないのですが会社のいろんな人にかなり重宝されます。それだけでなくChat GPTをはじめとするテキスト生成AIが登場しさらに文字を扱う仕事の生産性が大幅にアップしています。そして挙げたテキスト情報の処理においてテキストマイニングという技術が使われています。そこで、今回の記事ではテキストマイニングについて実例を交えて紹介していこうと思います。
テキストマイニングとは
テキストマイニングというのは、大量のテキストデータを解析しそこから有益な情報を抽出するための技術や手法の総称を言います。テキストマイニングの手法には、テキストデータを構造化する自然言語処理をはじめ文書のクラスタリングやテキストの感情分析、テキストデータから特徴を抽出する固有表現抽出や関係抽出などがあります。大量のテキストデータから洞察を得ることで、ビジネスや研究など様々分野で活用されます。今回フォーカスするのは自然言語処理とテキストからの特徴抽出となるので、その2点について少し詳しく紹介していこうと思います。
自然言語処理とはを話す前に自然言語とは?と思ってしまうのは自然なことだと思うので、まずはそこから触れていこうと思います。自然言語というのは所謂コンピュータ言語と対比されて、英語や日本語をはじめ人間が日常的に使用している言語のことを指します。解析することを前提に設計されたコンピューター言語と違い自然言語はその名の通り、自然発生的に生まれ紆余曲折を経て現在の言語体系を成しており、表記や文法に揺れがあったりするためコンピューター言語よりも解析するのが難しいのが特徴です。そして自然言語処理はその自然言語をコンピューターが処理し解析するための技術や手法の総称で、テキストや音声で表現される自然言語の理解や生成に関わります。自然言語の情報をコンピューターが処理可能な形式に解析することが重要で、トークン化・品詞のタグ付け、構文解析、意味解析など様々なタスクが存在します。
また今回はテキストの特徴を抽出するために統計的な手法を使うことにします。単語の出現頻度や単語の共起(どれくらい一緒に出現するか)性、語彙の豊かさ、文章の長さや構造などを、そのテキストデータの特徴として抽出し、統計的な手法で検定していくことでどんなことがビジネス上の要素と関連するか膨大なテキストデータから有益な情報を抽出していきます。
分析対象のデータと期待されるアウトプット
僕はインテリア関連の会社で働いているのですが、全国にあるショールームでは来たお客さんごとに接客した内容を記した日報のテキストデータを分析して、将来の良顧客となりうる人の特徴を抽出しそこからスタッフに対する教育資料を作成したい、という依頼を受けました。僕は以前働いていた化粧品のレビューサイトで働いていた時のことを思い出し、そういえば様々な化粧品メーカーの人たちが血眼になってレビューテキストを読み込んでたことが脳裏に甦りました。レビューサイトではテキストマイニングのサービスを提供しており、テキストデータのような定性的なデータを統計的に捉えられるように商品の評価ごとの単語の出現頻度、フレーズの出現頻度、それらをその評価特有のものであるかをスコアリングしランキング化することでその商品のどこが評価されどこが評価のネックとなっているかを浮き彫りにします。そのテキストマイニングサービスの処理を再現してみることにしました。
実装方針
まずは日報のデータがノーコード型のSaaSに蓄積されており、そのSaaSにはAPIがあるので外部からAPI経由でデータを取得することができます。取得したデータはCSV形式なのでパースしたデータをGoogle BigQueryにとりあえず突っ込みます。そして突っ込んだデータを取り出して加工していきます。また、該当するユーザーのメールアドレスをキーとしてSaaSにある注文データを取り出して見積もりの有無や購入の有無、購入金額などを同じくBigQueryに突っ込んでおきます。購入データはそのテキスト(もっと言うとそのテキストで表現された顧客)を評価するパラメータとして使用します。とりあえずテキストデータと購入データのデータストアがBigQuery上に出来上がっていれば元データは完成です。
次に解析に使う中間のデータを生成してBigQueryに保存します。テキストをまずは句点や改行で区切り、一文ごとの配列を作ります。そして、それぞれの文ごとに単語を抽出しその品詞などのメタ情報を添えて配列にします。これは形態素解析という処理になってくるのですが、英語と違い日本語はスペースで区切られたりしないため処理が複雑になります。スペース問題に加え品詞も判別が難しいケースが多々あるからです。形態素解析は現在は確率統計モデルを用いて実装されるものが多く、辞書などを用いた学習済みの教師データを用いてスコアリングしていくことで最も確率の高い品詞のラベリングがなされていくような処理を行うイメージです。ただし、形態素解析に関しては頭のいい人たちが日々日々研究を進めている領域ですし、オープンソースのライブラリが提供されているので、ライブラリを用いた解析が一般的です。単語だけではなくその単語がどのように使われているか、つまりフレーズも抽出したいので係り受け解析も行います。係り受け解析をするためには形態素解析におけるトークン化、品詞のタグ付けに加え、句構造解析や係り受けの特定が必要です。句構造解析をどのように実装するかはコンピュータ言語のコンパイラなどでも使われているCFG (文脈自由法)やニューラルネットワークなどの手法がありますが、今回使うCabochでどれが採用されているかは開発ドキュメントやソースを読んでみないとわからないですね。係り受けの特定にはShift-Reduce法のようなスタックとキューのような基本的なデータ構造を使用するケースや、単語をノード・係り受けをエッジと捉えて表現するGraph-Based法、メモ化をフル活用した動的プログラミング法、サポートベクターマシンなどを使う機械学習法などがあり、多分これらのうちの複数を組み合わせて係り受けを特定していると思います。
そして、テキストの特徴として抽出した単語やフレーズなどの特徴を、購入の有無や金額などでカテゴライズされたグループと掛け合わせて分析に使えるデータを作ります。ただ単にカテゴリごとに出現する特徴をランキングするだけでは、多分似たようなものになりカテゴリごとの違いが明確にならないということが多々あります。だから、各カテゴリ特有の出現ワード、出現フレーズのランキングを作る必要があり、そのランキングを作るためのスコアリングを単語やフレーズに対して付与する処理をしなければなりません。そのスコアリングの手法として今回はカイ2乗検定を使います。カイ2乗検定などの確率統計的なアプローチ以外にもクラスタリングなど他の方法もありますし、統計的なアプローチとしてもベイズ検定やエントロピーを比較する方法など別の選択肢はたくさんあります。今回カイ2乗検定を選択した理由としては、まず第1に今回の主題がスコアリング良し悪しを比較するということではないことと、次に実際にカイ2乗検定でスコアリングをしている事例を知っていてまずは使えるアウトプット一旦出すということを考えた時に、カイ2乗検定でスコアリングしてみるのが良いのではないかという結論になりました。
元となるデータストアの構築について
まずは日報が記載されているノーコード型のSaaSからデータを取ってくる来る必要がありますが、その方法はとても簡単でただJSONでHTTPリクエストを送るだけ、の簡単なお仕事です。HTTPクライアントで僕はnode-fetchを使っていますが、しばらく前にversion 3に代替わりしました。V3はES Modulesのみのライブラリになっていて、ずっとBabelを使っている僕にはとても都合が悪く、NodeJSのESMサポートとBabelのESMサポートがケンカしていまだにV2を使っているという悲しい出来事が起きています。そろそろBabelを捨てるべきでしょうか..それは本論とは何の関係もないので、置いておきましょう。fetchで取ってきたHTTPのレスポンスにCSV形式のデータが一緒についてくるのでそれをパースしてJSONに変換して、BigQueryのAPI経由でそのデータをデータベースに突っ込みましょう。そしてそのソースコードをAWS LambdaかGCP Cloud Functionにでもデプロイして、1日に1回更新するよう設定すればOKです。
分析するテキストの前処理について
形態素解析,係り受け解析にはGinzaを使います。GinzaはPython製の自然言語処理ライブラリで、 spaCyをベースに実装されておりネイティブ環境でのビルドが必要な他のライブラリと比べて導入のしやすさが特徴的です。GinzaはSudachiというライブラリをベースにしており、Sudachiは速度はMecabに劣るがメモリ効率は優っているそうです。精度は同じくらいとのこと。僕は実のところあまりPythonが好きではない(配列のポインタを変数に代入してその値を変えると、配列の要素まで入れ替わるところとか信じられない)ので、テキストの処理リクエストと実際の解析はプロセスを分離したい。だからexpressみたいなnodejsのフレームワークを使ってサーバーを立てて、そこから新しいプロセスを立ててGinzaの処理を行う仕組みにすることにする。BigQueryから取り出したテキストをJSONかMessagePackか何かの形式でGinzaの処理リクエストを受け取るサーバーに投げて、帰ってきた解析済みのデータをBigQueryの別のテーブルに突っ込んでおくことにします。
特徴抽出のための確率分布による検定について
カイ2乗検定について説明します。独立に標準正規分布に従う複数の確率変数である時に一定の式から算出される変数に従う確率分布のことで母分散の区間推定や適合度の検定、独立性の検定などに使用されます。正確な定義についてはググって調べるのが一番正確で早いと思われるのでここでは割愛します。
カテゴリ毎のキーワードまたはフレーズの独自性のスコアを算出することは、所謂、独立性の検定に該当します。カイ2乗分布の関数は複雑な数式なのでそこは割愛するとして、定義や導出についてはGoogleに聞けば教えてくれるのでそこは各々でご確認いただくとして、そこに明るくなくてもscipyというライブラリでアルゴリズムが実装されていて誰でも簡単に使えます。chi2_contingencyという関数を母集団とターゲットをクロスした行列を読み込ませることでそのスコアが返ってくるくるという超簡単な処理です。
つまり購入の有無、購入金額のレンジ毎に単語・フレーズの出現頻度をクロス集計して、chi2_contingency関数に集計した行列を渡して返ってきたスコアを使ってランキング化することによって、ショールームにきたお客さんのうち購入してくれた人、たくさんの金額を使ってくれた人の特徴が単語・フレーズのランキングから抽出できるという仕組みです。
本当は実際のテキストや分析結果のサンプルを載せることで、もっとわかりやすく伝えたかったのですが、それは会社の許可が降りたらこの記事に追記していこうと思います。