はじめに ある日 急に集計を依頼されたものの、元のデータがフリーテキストで困ったエンジニア の話をします。
ロジカルスタジオでは独自の日報システムを使用しています。 その日報を入力する際、作業種別をプルダウンから選ぶようになっています。
ある程度の種別を用意しているものの、どうしても「その他」という選択肢も必要になります。
「その他」の内容として入力されたフリーテキストから、 どういった内容が「その他」として登録されているのか集計する というのが目的になります。
フリーテキストなので助詞や接続詞などで表記が揺れて集計しずらい為、 NLPライブラリを利用して集計しやすいようにします。
茶番が長いので本編までSKIP
茶番 ある日ー…
1週間後ー…
本谷さんの席
STEP1:NLPライブラリの選択 さっそく「日本語 NLP ライブラリ」でgoogle検索しましょう。
GiNZA一択ですね。
公式 を軽く読むとPythonの環境が要るらしい。 環境を作っていきましょう。
STEP2:Python環境を作る 茶番に書いたようにPython得意(笑)だったら良かったのですが、 現実には1度触ったことが有るくらいです。 windows上でやるかdockerでやるか。 悩んだ結果dockerを選択しました。 (windowsの場合詰まった時に何が原因か分からんイメージが。。)
「python docker image」でgoogle検索します。
オフィシャルも良いですが、先人の知恵が詰まっていそうなので 3つ目のqiitaの記事 を参考にしました。 この方は「jupyterlab」を使いたかったようですが、この記述をGiNZAに変更します。 GiNZAの公式を見ると、セットアップは下記のコマンドで良いとの事。
pip install -U ginza https://github.com/megagonlabs/ginza/releases/download/latest/ja_ginza_electra-latest-with-model.tar.gz
Dockerfileはこうなります。 docker-compose.ymlは記事のままで良いでしょう。
FROM python:3
USER root
RUN apt-get update
RUN apt-get -y install locales && \
localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install -U ginza "https://github.com/megagonlabs/ginza/releases/download/latest/ja_ginza_electra-latest-with-model.tar.gz"
後は普通にdocker-composeでビルドします。
STEP3:抽出処理 pythonのコンテナに入り、~/optへ移動するとそこがマウントディレクトリになっています。 ここでスクリプトを組んでいきます。
今回やりたいのは、フリーテキストがずらっと並んだCSVに1行ずつNLPの処理をかまし、 助詞を取り除いた名詞句を抜き出して集計するという内容です。
元となるCSVはこんな内容。
1.GiNZAライブラリをインポート 2.CSVを読み込む 3.1行づつnlpをかます
という流れなので、 GiNZA公式にある 「Pythonコードによる解析処理の実行」 という節の内容に従って、 まずは1行だけ試してみます。 コードはこちら。
import spacy
nlp = spacy.load('ja_ginza_electra')
f = open('daily_report_details.csv', 'r')
datalist = f.readlines()
doc = nlp(datalist[0])
for sent in doc.sents:
for token in sent:
print(token.i, token.orth_, token.lemma_, token.pos_, token.tag_, token.dep_, token.head.i)
print('EOS')
f.close()
さっそく実行しましょう。
root@7bc5aff4e1f3:~/opt# python aaaa.py
0 " " PUNCT 補助記号-一般 punct 2
1 # # SYM 補助記号-一般 compound 2
2 日報 日報 NOUN 名詞-普通名詞-一般 nmod 5
3 へ へ ADP 助詞-格助詞 case 2
4 通知 通知 NOUN 名詞-普通名詞-サ変可能 compound 5
5 テスト テスト NOUN 名詞-普通名詞-サ変可能 ROOT 5
6 " " PUNCT 補助記号-一般 punct 5
EOS
7
NOUN 空白 ROOT 7
EOS
う~ん、10行目の第4引数の「token.pos_」というのがNOUNになってるものが抽出出来れば良さそうだけども。。 何というか細かく分かれ過ぎている気がします。 出来れば「通知テスト」みたいにまとまったワードが欲しい。
調べてみると、8行目のdoc.sentsの代わりにdoc.noun_chunksというのが使えるらしい。 試してみると、
root@7bc5aff4e1f3:~/opt# python aaaa.py
"#日報
通知テスト
これじゃぁ~~~!!!
得たい結果の出し方が分かったので、 後はひたすらcsvを1行ずつ読んでnoun_chunksを吐き出していくだけです。 一応、実行前にcsvからダブルクォーテーションや・や#などの要らん記号は削除しておきましょう。
ソース内容はこうなりました。
import spacy
nlp = spacy.load('ja_ginza_electra')
f = open('daily_report_details.csv', 'r')
wf = open('result.txt', 'w')
datalist = f.readlines()
for dataline in datalist:
doc = nlp(dataline)
for np in doc.noun_chunks:
wf.write(str(np) + '\n')
f.close()
wf.close()
で、実行しますが…
GPU使わんなぁ。。 公式にはCUDAを使用する方法が書いてありますが、 会社のPCにCUDAなんか入ってないので仕方ないですね。 15,000行の処理をひたすら待ちます。
待つこと12分。 出力したテキストを小文字→大文字に変換した上でソートしExcelに貼り付けると、 良い感じに同じ作業内容が並ぶ結果になりました。 弊社の社内雑務「その他」のTOP10までを発表します。
うーん納得の結果。 面白いのが、9位に「その他」が再出現している事。 これはもう分からんな。。
ま・と・め ・日本語NLPはGiNZAというライブラリが有名らしい
・GiNZA関係の記事を読むと
nlp = spacy.load('ja_ginza')
というサンプルが良く見つかるが、これは古いバージョンで下記のエラーが起きる。
Can't find model 'ja_ginza'. It doesn't seem to be a shortcut link, a Python packageor a valid pathto a data directory
現行バージョン(v5.x)では、
nlp = spacy.load('ja_ginza_electra')
・下記プロパティで、少しまとまった名詞句を取得できる
doc.noun_chunks
・ロジカルスタジオは朝礼の時間を削減するなど業務改革の必要がある
・ロジカルスタジオでは後輩に仕事を押し付けるとコロコロで殴られる
最後に さて、弊社ロジカルスタジオでは種類を問わず様々な職種・技術で一緒に働ける方を募集しております。
採用サイト には 会社の雰囲気 や 社員インタビュー など、 たくさんの情報が掲載されているのでお気軽に覗いてみてください!