astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

アスタミューゼの開発組織と採用に関するQAアレコレ

こんにちは。並河(@namikawa)です。

随分と冬の足音が近づいて来た今日この頃、すっかりラーメンがより美味しく感じる季節となってまいりましたが、皆様いかがお過ごしでしょうか。

さて、今日はいつもとは趣向を変えて、開発組織の話をしようかと思います。

弊社では、優秀なエンジニアやデザイナーを絶賛大募集しているのですが、今年くらいから、私自身が本格的にエンジニア採用に携わるようになりました。このエントリでは、弊社での採用・選考(面接、面談)をどうやっているかと、その場でよく質問されることに対するQA集をまとめてみようかと思います。

弊社での業務に少しでも興味をお持ちの方に、弊社がどのような開発組織で、エンジニアがどのような働き方をしているのかのイメージ形成に役立てていただければと思います。

ちなみに募集職種や要項などは、以下の採用サイトに記載しておりますので、その補足エントリ、くらいで見てもらえれば幸いです。

弊社のエンジニア面接・面談について

f:id:astamuse:20171115181155j:plain

Q. 面接回数と時間はどのくらいですか?

大体のケースでは2〜3回で、1回あたり30〜60分程度です。面接時間が長くなる場合は、QA時間が長くなるケースが多数かなと思います。

お互いの事情で面接前に相談した上で、面接自体の回数(面接担当の組み合わせ等で調整)も変動することがあります。

Q. 面接はスーツ着用ですか?

服装はスーツでなくても大丈夫です。むしろ、普段着ているような格好で来ていただければと思います。

尚、弊社の業務中の服装は、TPOさえ考慮いただければ基本的に自由ですので。(夏は、Tシャツ・短パン・サンダル、の方もいらっしゃいます。)

Q. 面接でどういうところを見ているのですか?

面接の担当者によって様々かとは思います。

個人的には、できるだけ普段の雰囲気でかつ雑談のような感じで、カジュアルにお話しできればなと考えながらやらせてもらっていますが、端的にいうと、これはお互い様かとは思いますが、目の前に座っている方と楽しく一緒に仕事ができそうかどうか、ですかね。

サービス開発について

Q. 開発環境ってどんな感じですか?

  • 開発言語については、 Scala、Java、Python などを採用しています。
  • データベースや検索関連は、PostgreSQL、MongoDB、ElasticSearch、Groongaなどを利用しています。
  • データの生成や分析に Hadoop や Spark などの大規模データ処理基盤を構築・活用しています。
  • サービスインフラについては、Google Cloud Platform 等のクラウドサービスを中心に整備を進めています。

色々書きましたが、現状よりもより良いもの(技術・ツールなど)があれば常時、積極的に検討・導入しています。基本的に技術の選択については、各エンジニアが裁量を持ち責任とセットで導入してもらっている感じです。

また、支給されるPCについては、自身の開発環境を自由に選べるようにしています。また、拡張・増設など(モニタ、メモリ、SSD、キーボード等)も自身の判断で申請できます。

あ、そうそうオフィスの椅子は、ハーマンミラー社のエンボディチェアです。でも、個人的には会議室にあるアーロンチェアの方が好みなので、取り替えようかなぁと思っています。

正直、一番生産性が上がる形であれば、できる限りのサポートはしたいと思っています。人によってはスタンディングで作業していたり、バランスボールに乗っていたりと様々ではありますが・・・。

Q. エンジニアの方の1日の過ごし方を教えてください

基本的には、自社サービスでの開発となりますので、マーケティング担当やディレクターと一緒にサービスのKPIに沿った施策を検討し、そのあとは実際にプログラミングとテストを行いリリースとなります。

1日といった区切りで言うと、少々の打ち合わせ以外は、ほぼ何かしらのモノ作りに取り組んでいるイメージです。

f:id:astamuse:20171115171605p:plain http://recruit.astamuse.co.jp/

例えば、上記の画像は、弊社の採用サイトのトップページですが、実際にアクセスしてもらうと、ある日の1日のスナップショットをコマ送りにした様子が確認できます。(PCからのみです。すみません。)

これを見ると、社内の1日の雰囲気を確認できるかなと思うのですが、多数の方が基本的には自席でコーディングしていることがほとんどです。

あと、採用サイトにも社員の1日の例が記載されているので、そちらもご覧ください。

働き方について

Q. 全体で何人くらいで、どういうチーム構成ですか?

2017/11/15現在、会社全体では約50名、開発・デザインの組織は、エンジニア10名、デザイナー4名となります(全て正社員)。サービス・データ開発のほぼ全てを内製化し、開発を進めています。

エンジニアは、アプリチーム・データチーム・インフラチームの3チームにわかれてサービスやデータ開発に取り組んでいます。各チームや職種の詳細については、(採用サイト)をご覧くださいませ。

Q. 勤務時間や残業時間はどんな感じですか?

開発・デザイン本部はフレックス制を導入していて、コアタイムは少し長めではありますが 10:30~17:30 となっています。基本的には、8時間 x 営業日数 (有給使用日数は除く) を一月単位で満たしていただければ良いという仕組みです。

それぞれが課されたタスクによって、自分にあった仕事の進め方で取り組んでいるため、みんな出社・帰社時間はバラバラです。だからこそみんな気にせず定時に帰れる雰囲気があり、残業時間は月平均で10時間未満です。

あと、巷で話題になりがちなリモートワークをしているエンジニアもいます。

Q. 研修制度とかってありますか?

明示されている(ルール化されている)ものはありませんが、良質なインプットが良質なアウトプットを産みだす、という考え方ですので、外部セミナー・勉強会への参加や登壇を奨励しています。

デブサミや Google Cloud Next や db tech showcase などは、毎年社員の多数が参加していますし、昨年の Cloudera World Tokyo では弊社のメンバーが登壇しています。

こういったカンファレンスやセミナーで情報収集することも大事なのですが、どちらかというと、こういった場で多くの刺激を受けて、業務につなげてほしいという期待を持っているので、基本的には参加にストップを出すケースは、よほどの事情がない限りほとんどないかと思います。

尚、必要な書籍は会社経費で購入できる他、持ち回りで毎週社内勉強会を開催していたり、このエンジニアブログの執筆をしています。

その他

Q. 会社の雰囲気ってどんな感じですか?

文章で表現するのが難しいのですが、割と落ち着いている方だと思います。

開発・デザイン本部ですと既婚者も多く、ご家庭の事情で早めに来て、早めに帰る方も多いですし、業後に勉強されている方もいます。

あとは、最近だと隔月くらいで会社全体の懇親会(任意参加)を開催していて、オフィスで他事業部の方とお酒を交えながらカジュアルな感じで話をする機会もあります。(大事)

懇親会の後に有志でボードゲームをやったり、個人的にはラーメン部(非公式)を作って活動日を決めていて、銀座・築地・新橋界隈の美味しいラーメン屋にメンバーとランチに繰り出しています。

f:id:astamuse:20171115181159j:plain

↑オフィスでの懇親会の雰囲気

Q. 社長ってどんな人ですか?

こんな人(以下リンク先)です。最近太っ・・・いや、なんでもないです。

Q. エンジニアってどういう人がいますか?

最近、エンジニア3名がそれぞれインタビューを受けましたので、僭越ながらそちらを紹介しておきます。よろしくお願い致します。

最後に本題

とまぁ、駆け足でしたが、弊社の開発・デザイン組織の雰囲気が少しでも伝われば幸いです。

冒頭でも書きましたが、弊社ではエンジニア・デザイナーを絶賛大募集しておりますので、少しでも気になれば、カジュアルにランチでもしながらお話ししましょう。またはお手数ですが (@namikawa) までDM等いただければと思います。

それでは!=͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞(๑•̀д•́

コード管理と構成管理(その1〜 バッチデプロイしちゃうよ?編 〜)

こんばんにちは。今週ブログを担当するnishikawaです。早いものでアスタミューゼに入社してからもう10ヶ月が経過しました。本当に時間が経つのは早いなぁと驚いております。

さて、今回はタイトルにも書きましたが弊社のサービスの一つである転職ナビで利用しているバッチをデプロイしたときに感じたコードの管理と構成の管理の話を数回に分けてしたいと思います。

転職ナビは求人票を掲載するためのアプリケーションと、データを色んなアプリケーション間で授受したり、メールを送信するなど裏で色んな作業をしてくれるためのバッチ群に大きく分かれます。

で、後者は大小さまざまなものが存在し、ひしめき合いながら日々の作業を行なってくれているのです。

そんなバッチさん、大体はScalaで作成されているものが多く本番の環境にはデプロイ時に生成したjarファイルが配置されているのですが、それをさらにbashスクリプトでラップするというよくあるパターンで構成されています。

これが本番環境およびステージング環境に配置されているわけですが、このプロダクトの管理方法、いくつか問題があるなぁと色々開発していて感じました。それは・・・

  • アプリケーションの設定ファイルが配置する環境ごとに違うものを作成しなければいけない(というか作成されているw)
  • スクリプトも複数環境分用意しなければいけない(というかされているww)
  • 挙句jenkinsなどのCIツールでプロダクトのデプロイを考えたときにデプロイスクリプトも複数作って用意しなければならない(というかされているwww)

とういことになり管理が煩雑になりがちです。 この状態が続くと設定ファイルの反映漏れや配置ミスが発生しデプロイしたけど動かないという問題や一応動いているけど本番環境とステージング環境で差異が出るなど運用面でよくないことが起こります。

そこで、これらの問題を解決するために実際にやってみたことや、それに対する考察していきたいと思います。

やったこと: 構成管理用のフレームワークを使用してみる

まず実際に私が半年ぐらいでやってみた構成を書いてみます。

バッチさんの紹介

お名前 求人票データの取り込みバッチ
おところ 転職ナビ保有の本番バッチサーバおよびステージングサーバ
種別 Scala製
特技 特定ディレクトリに配置された求人票(CSVファイル)をデータベースに投入するよ!

構成(Before)

今回の「求人票データの取り込みバッチ」の開発プロジェクトのディレクトリ構成は以下です。

joboffer-csv-import-batch
├── csvroot
│   ├── astamuse
│   │   └── csv
│   └── <提携先ごとの求人票配置ディレクトリ>
├── joboffer-csv-import-batch.iml
├── pom.xml
├── project
├── shell
│   ├── local
│   │   ├── CsvImportForAstamuse.sh
│   │   └── <各提携先の実行スクリプト(ローカル用)>
│   ├── production
│   │   ├── CsvImportForAstamuse.sh
│   │   └── <各提携先の実行スクリプト(本番用)>
│   └── staging
│       ├── CsvImportForAstamuse.sh
│       └── <各提携先の実行スクリプト(ステージング用)>
├── src
│   ├── main
│   │   ├── resources
│   │   │   ├── application.conf
│   │   │   ├── application_production.conf
│   │   │   ├── application_staging.conf
│   │   │   ├── logback-production.xml
│   │   │   ├── logback-staging.xml
│   │   │   └── logback.xml
│   │   └── scala
│   │       └── <ソースコード群>
│   └── test
│       └── <テストコード群>
└── target

以上を見て分かる通り、スクリプトも設定ファイルも本番用、ステージング用、ローカル試験用で別れているのが分かります。 そして、これらが配置後は以下のようになります。

joboffer-csv-import-batch
├── CsvImportForAstamuse.sh
├── <提携先ごとのスクリプト>
├── csvroot
│   ├── astamuse
│   │   ├── csv
│   │   └── old_csv
│   └── <提携先ごとの求人票配置ディレクトリ>
├── joboffer-csv-import-batch.jar
└── logs

で、この構成を実現するために以下の手順でデプロイを行います。

■ローカルで実施

  • ビルド用のワークディレクトリを作成する
  • gitリポジトリから資材をダウンロードしてくる
  • 設定ファイルをコピーする
  • ビルドする

■リモートで実施

  • デプロイ先のディレクトリを全て作成する
  • スクリプトをコピーする
  • ビルドされたjarファイルをコピーする

さて、上のデプロイ手順、一つずつ手でやっていたらとても面倒です。 弊社ではjenkinsを利用してこれらの作業をやっているのですが、使用しているのはpythonスクリプトです。 そのため、jenkinsで利用するスクリプトも本番環境用とステージング環境用で分かれております。

構成(After)

そこで、構成管理用フレームワークを利用し先に述べたデプロイの手順を実施します。以下は私が作った定義ファイル群とそのディレクトリ構成です。(chefが使えないのでAnsibleです。Chefファンの皆様ごめんなさい。

joboffer-csv-import-batch/
├── host_vars
│   ├── hosts
│   ├── localhost.yml
│   ├── prd-tennavi-bch01.yml
│   └── stg-tennavi-bch01.yml
├── roles
│   ├── create_package
│   │   ├── files
│   │   │   └── conf
│   │   │       ├── application.conf
│   │   │       └── logback.xml
│   │   ├── tasks
│   │   │   └── main.yml
│   ├── deploy_package
│   │   ├── files
│   │   │   └── shells
│   │   │       ├── CsvImportForAstamuse.sh
│   │   │       └── <提携先ごとのスクリプト群>
│   │   └── tasks
│   │       └── main.yml
│   └── get_repository
│       └── tasks
│           └── main.yml
├── site_create_package.yml
├── site_local.yml
├── site_prd.yml
└── site_stg.yml

これを利用するためにとった開発プロジェクトの構成が以下になります。

joboffer-csv-import-batch
├── joboffer-csv-import-batch.iml
├── pom.xml
├── project
├── src
│   ├── main
│   │   ├── resources
│   │   │   ├── application.conf
│   │   │   └── logback.xml
│   │   └── scala
│   │       └── <ソースコード群>
│   └── test
│       └── <テストコード群>
└── target

結果

いかがでしょうか?テコ入れをする前の構成に比べてディレクトリがすっきりしていることと思います。 ここで注目していただきたいのは本番やステージングにアップロードするための設定が環境ごとに存在しないということです。 これで設定漏れが最小限に防げると思います。 当たり前といえば当たり前の構成ですが、構成管理用のフレームワークがなかった頃は、この構成にするためには手順書をたくさん書かないといけなかったので、それがコードだけで管理できるというのがどれほど素晴らしいか理解していただけるかと思います。

以上で、ある程度の煩雑さは解消されました。しかしまだ この構成でも煩雑さは残ります。 これについては次回以降、考察を行っていきたいと思います。それではまた今度。

お手軽に英文文書にメタ情報を!!Pythonでgensimを使ったLDAに挑戦してみた。

f:id:astamuse:20171101221349j:plain

こんにちは。白木(@YojiShiraki)です。デザイナーです。
前回はpolyglotを用いて英文から名詞を抽出する処理を行いました。今回は、その延長でLDAという手法にチャレンジしたいと思います。

背景

当社ではぼちぼち大量の自然文章データを取り扱っています。通常、これらのデータを読み解いてクライアントへの提案に繋げているのですが、概観を把握する場合は、膨大なデータを一つ一つ丁寧に読んでいる余裕などありません

そうなると、できる限りメタ情報を付与して、対象データの中身を読まずにだいたい把握するニーズが高くなりますが、残念ながら最初からデータに豊かなメタ情報が付与されているケースは稀であり、あってもカテゴリが一つ与えられているくらいです。

そこで自分たちでメタ情報を付与できないか、ということでLDAをやってみたという流れです。

LDAとは?

ざっくり言うと、対象となる文書がどういったトピックによって構成されているかを推定する方法です。潜在的ディレクリ配分法と言われます。数学的な解説は他サイトに譲りまして、ここでは直感的にLDAがどういったものか解説します。

まず、ある文書があったときに、その文書のトピックとは何か、ということです。

f:id:astamuse:20171101220040j:plain
文書の主たるトピックを明らかにする

例えばある野球ニュースがあったしましょう、この時、その文書(ニュース)がクライマックスシリーズのニュースであればトピックは「DeNA」「ソフトバンク」「試合結果」「ホームラン」といったところでしょうか。こういった情報が把握できればニュースを全部読まなくてもだいたい何の話かわかりますよね。

注意点

「なんだ楽勝じゃん」と思われるかもしれませんが注意点が二つあります。

  1. トピックは母集団となる文書群から抽出される
  2. トピックは明確的には抽出できない

どういうこと?と思われるでしょう。以下に簡単に説明いたします。

1.トピックは母集団となる文書群から抽出される

文書の成分として推定されるトピックは対象となる文書群から抽出されます。 例えば以下の二つのケースを考えてみます。

  1. 日本のすべてのニュース(文書群)を対象としてトピックを推定した場合
  2. スポーツニュース(文書群)を対象としてトピック推定をした場合

1の場合、おそらく上がってくるトピックは「経済」「政治」「芸能」「スポーツ」などで、2の場合は「野球」「サッカー」「バスケット」「ラグビー」などでしょう。

1よりも2の方がスポーツに関して偏った文書群であり、自然と単語の出現頻度もより具体的な単語が支配的になるためです。

f:id:astamuse:20171101220249j:plain
トピックは母集団となる文書群によって変化する

2.トピックは明確的には抽出できない

ここまでで便宜上ではあったにせよトピックは「経済」「政治」「野球」「サッカー」など、明確に与えられるように書きました。しかし実際はトピックも単語の成分として与えられます(OMG)

イメージとしては以下のようなものです。

f:id:astamuse:20171101220414j:plain
トピックは単語の成分で与えられる

つまり処理手順はこういうイメージです

  1. 文書群から
  2. トピック成分を抽出し
  3. トピックを定義する
  4. そのうえで個別の文書を分析にかけ
  5. その文書のトピックの構成比率を明らかにする

実践

ということであとはコードでも書いていきましょう。前回ご紹介したPolyglotを利用してますので、まだご存じない方はこちら)をご覧ください。

なお、以下のコードは説明しやすいよう便宜的なデータセットで用意しています。実際はちゃんとDBを使ってデータの管理を行なっております。また本筋に関連の薄い処理は割愛しております。あらかじめご了承ください。

1. 名詞の抽出

polyglot)を利用します。

from polyglot.text import Text
from polyglot.detect import Detector

# 文書群(実際にはこういった文書が100万以上あるイメージです)
documents = [
      {
          'desc' : 'A beach safe for all those who want a carefree beach holiday. The HBT BELSAFER the HBT brings a mobile vault on the market, which offers a premium value protection with smart additional features.'
      },
      {
          'desc' : 'The south curve must stay! The SOUTH CURVE is THE place of active FCC fans. Here come for generations the blue-yellow-white trailer together, showing brilliant choreography, are creative and unmistakable behind their team.'
      },
      {
          'desc' : 'Darling4me - Video Dating and dating service on the smartphone. Find your soul mate on the smartphone with just one click on your smartphone. Darling4me is the first truly Video Dating app for your smartphone (Iphone, Ipad and Android). Darling4me dating service does not require lengthy questionnaires and extensive information from you to find your soul mate. They are tired of seeing it on various dating sites on the Internet images of singles that look quite different in reality? They also do not believe that you will find his true love with a questionnaire? Then try just the new Video Dating Darling4me! It has never been easier to find love. Get your partner suggestions from your environment and see with just one click on your smartphone, the videos of the singles that could be suitable for you. Live and real!'
      }
]

for doc in documents:
    desc     = doc['desc']
    text     = Text(desc)
    nouns    = []

    for tag in text.pos_tags:
        word       = tag[0]
        word_class = tag[1]

        if word_class != 'NOUN':
            continue

        if len(word) < 3:
            continue

        nouns.append(word.lower())
    doc['nouns'] = nouns
    print(nouns)

こんな名詞データが取れます。実際には名詞データを格納する際にクレンジングなどを行う必要があります。今回はサンプルとして2文字以下の名詞は含めない処理を書いてあります。

['beach', 'beach', 'holiday', 'vault', 'market', 'premium', 'value', 'protection', 'features']
['south', 'curve', 'curve', 'place', 'fans', 'generations', 'blue', 'trailer', 'choreography', 'team']
['video', 'dating', 'service', 'smartphone', 'soul', 'mate', 'smartphone', 'smartphone', 'video', 'dating', 'app', 'smartphone', 'iphone', 'ipad', 'service', 'questionnaires', 'information', 'soul', 'mate', 'dating', 'sites', 'images', 'singles', 'reality', 'love', 'questionnaire', 'video', 'dating', 'love', 'partner', 'suggestions', 'environment', 'smartphone', 'videos', 'singles', 'live']

2.辞書の作成

先ほど抽出した名詞の配列から、単語と出願回数がペアになったデータを整備します。このタイミングで出現頻度の著しく高い単語や低い単語をフィルタリングしておきます。

import gensim
from gensim import corpora, models, similarities

words = [x['nouns'] for x in documents]

dictionary = corpora.Dictionary(words)

# 出現頻度の100回以下の単語は除外
# 5割の文書に出現している単語は除外
dictionary.filter_extremes(no_below=100, no_above=0.5)

# 必要であれば辞書データを保存しておいてください。
dictionary.save_as_text('dict.txt')

# 保存した辞書のロード
dictionary = corpora.Dictionary.load_from_text('dict.txt')

辞書の中はこのような形です。

99416
142 ability 1285
269 access  1190
112 accident    1059
175 account 1100
250 action  1077
164 activities  2936
48  activity    1239
369 addition    3438
61  adults  1203
208 advance 1527
85  age 2557
323 amount  4965
244 animals 1380
260 anyone  2604
94  anything    3794
362 area    3266
147 areas   1832
66  art 2847

左からID, 単語, 出現回数となっています。

3.辞書と単語配列データからコーパスデータを作成

ここでは単語とその出現回数をセットにしたデータ(BoW)のまとまりをコーパスと呼びます。

corpus = []
for word in words:
    bow = dictionary.doc2bow(word)
    corpus.append(bow)

print(len(corpus))
for c in corpus:
    print(c[0:5])

出力内容はこちら。

99416
[(226, 1), (348, 1)]
[(16, 1), (386, 1)]
[(22, 2), (73, 3), (107, 1), (213, 1), (256, 1)]
[(16, 1), (32, 1), (38, 1), (51, 2), (53, 5)]
[(13, 2), (27, 13), (44, 1), (50, 1), (53, 2)]
[(112, 1), (227, 1), (256, 2), (358, 1), (367, 1)]
[(120, 1), (130, 1), (222, 1), (404, 1)]
[(130, 2), (205, 1), (234, 1), (275, 1), (349, 1)]

先ほどの辞書のIDの単語が各ドキュメントで何回出現しているのかが見て取れます。

4.トピックの抽出

さて全体での単語の出現頻度や、個別文書での単語の出現頻度のデータが整備できました。これによって出現確率が計算できるようになります。コード上でもいよいよトピックの抽出を行います。

topic_N = 5 # トピックの数(これは恣意的に設定できる。対象文書群が大きいなら数字は10にするなど)

lda = gensim.models.ldamodel.LdaModel(
          corpus     = corpus
        , num_topics = topic_N
        , id2word    = dictionary
      )

# モデルを保存する
lda.save('cf_lda.model')

# 見やすく出力
for i in range(topic_N):
    print("\n")
    print("="*80)
    print("TOPIC {0}\n".format(i))
    topic = lda.show_topic(i)
    for t in topic:
        print("{0:20s}{1}".format(t[0], t[1]))

出力はこんな感じです。

================================================================================
TOPIC 0

children            0.04091190129015311
community           0.03130555261697799
people              0.029479935059319066
school              0.02772734591535905
trip                0.024166451030072957
families            0.02161773848009083
food                0.021610873859255263
students            0.01979379324892966
funds               0.017129066919807687
donations           0.016645475281216793


================================================================================
TOPIC 1

family              0.05142340959037838
time                0.02913106744366217
life                0.027162997294828555
years               0.024956546073125124
home                0.01966655399836955
year                0.018690935949895755
bills               0.018176062282802562
cancer              0.017468175859926792
kids                0.016755068548548788
surgery             0.016417772028110674


================================================================================
TOPIC 2

cause               0.3400466352795431
progress            0.3288091973047845
supporter           0.326162187172668
name                0.002616388814580179
list                0.0007183396591630143
style               0.0001032523653516189
size                5.034349340074679e-05
time                1.8874650176037916e-05
business            1.802981647432903e-05
text                1.8023864292905654e-05


================================================================================
TOPIC 3

name                0.04493116909991208
dream               0.03237160912917436
team                0.026269755943711323
music               0.024893502207153875
time                0.01889772053109854
equipment           0.018581267347826023
http                0.017372070771627068
support             0.017230217254967435
girls               0.016372972121079955
year                0.016264355823729516


================================================================================
TOPIC 4

people              0.03610631244471521
business            0.0258750156278881
world               0.023791209653958246
life                0.02243440793115274
time                0.018039148524328114
way                 0.015300038103529194
project             0.014480208478364773
years               0.01395798245176747
campaign            0.012818022865819834
work                0.011415802285745767

面白いですね。ところどころでnamehttpなどのノイズがあるので、これは調整が必要そうです。ストップワード作ってフィルタしてしまうのもありだと思います。 さて、母集団である文書群を考え各トピックの意味を仮に以下のように定めます。

TOPIC0: 福祉・教育
TOPIC1: 健康
TOPIC2: ビジネス
TOPIC3: 夢の実現
TOPIC4: 人

4.個別のドキュメントの分析

最後に、文書を指定してその文書のトピックがどのようになっているか分析しましょう。 対象となっている文書のコーパスデータをldaインスタンスに渡すだけです。

topic_label = [
    "福祉・教育",
    "健康",
    "ビジネス",
    "夢の実現",
    "人"
]

target_record = 5 # 分析対象のドキュメントインデックス

for topics_per_document in lda[corpus[target_record]]:
   print("{0:30s}{1}".format(topic_label[topics_per_document[0]], topics_per_document[1]))

こんな結果になります。この文書はビジネスの性質が強く出ている、というのがわかります。あとは閾値などを設けて実際にメタ情報として活用できます。

福祉・教育                    0.025503321280086557
健康                          0.025001172222024352
ビジネス                      0.7468590388122892
夢の実現                      0.02545997949638024
人                            0.17717648818921963

終わりに

いかがでしょうか?膨大な文書に対して全体像にフィットしたカテゴリ情報・メタ情報を付与したいときにはなかなか使えそうな方法ではないでしょうか。

勿論、いざやってみると、データのクレンジング、ストップワード処理やステミングなど前処理の手間がそれなりにかかりますし、パラメータの調整もそれなりの難しさがあります。 またトピックの善し悪しの判断も必要です(トピックはできれば距離が離れているほうが望ましい)。こういったことを踏まえると到底「お手軽」とは言えませんが一度試してみるのは良いかと思います。

では、本日も最後までお読みいただきありがとうございました。

例によって当社では一緒に開発してくれるメンバーを募集しております。カジュアル面談も随時行っておりますので、「ちょっと話聞きたい」という方は、このブログのサイドバー下にあるアドレスか@YojiShirakiあたりにDMいただければと思います。採用サイトもありますので↓↓↓のバナーから是非どうぞ!ちなみに次回はデザインの話に戻ります。

Copyright © astamuse company, ltd. all rights reserved.