bosyu.meの一覧ページを作成してみました。ちなみに僕はbosyuの運営とは何の関わりもありません。
ちょっと前にbosyuという募集を行うことができるサービスがリリースされました。応募が来るとサービス上で簡単一覧できる便利なサービスです。
ただ、Twitter上で自分のフォロワーさん宛に募集を行う形での利用を想定されて作られている感じのため、募集の一覧ページなどがありません。
そのため、募集一覧ページを勝手に作ってみました。
ただ、ただほんとに一覧するだけだとTwitter上で#bosyu
というハッシュタグを使って見ればいいだけなので、独自の機能としてカテゴリ分類機能を追加し、カテゴリ毎の募集を見られるようにしてみました。(カテゴリの自動分類方法詳細は後述)
1時間ごとくらいにツイートの保存処理を行っています。
こんな感じで初期化&取得しています。特に複雑な点はなく、基本通りそのままです。URLとハッシュタグで検索しているので、Twitter上での検索よりは精度が高いと思います。TwitterではURLで検索しても検索結果が出てきませんのでここはAPIのみの利点です。
$connection = new TwitterOAuth(
env('TWITTER_CONSUMER_KEY'),
env('TWITTER_CONSUMER_SECRET'),
env('TWITTER_ACCESS_TOKEN'),
env('TWITTER_ACCESS_TOKEN_SECRET')
);
$params = [
'q' => 'bosyu.me/users #bosyu',
'count' => 100,
];
if ($maxId = Tweet::getMaxId()) {
$params['since_id'] = $maxId;
}
$tweets = $connection->get("search/tweets", $params);
下記のような感じでリツイートや既に取得済みのツイートなどをフィルタリングしています。
public static function isAvailableStatus($status)
{
if (strpos($status->text, '#bosyu') === false) {
return false;
}
if (!empty($status->retweeted_status)) {
return false;
}
$bosyuId = self::getBosyuId($status);
if (!$bosyuId) {
return false;
}
return true;
}
Vue Materialで表示を行っているので、検索フォームもVue Materialだけで実装しました。
カテゴリは選択たらすぐに画面が切り替わるのですが、Date Pickerはどうも選択時のcallbackが無いようだったので、仕方なく検索ボタンを押してもらう形にしました。デザインは綺麗なのに肝心な機能が抜けていたりして微妙ですね。誰か本家にプルリクエストを送って実装してください。
別にフォームまるまるコンポーネント化しようとは思ってなかったのですが、上記理由でv-modelを利用した値の取得方法しかなかったため、コンポーネント化されています。全部v-modelで管理してボタンでlocation.href
するだけのシンプルなコンポーネントです。
<template>
<div>
<div class="row">
<div class="col">
<md-field>
<md-select v-model="currentCategoryId" name="category" id="category" placeholder="Category" @md-selected="selectCategory">
<md-option :value="0">Category</md-option>
<md-option v-for="category in categories" :value="category.id" :key="category.id">{{category.name}}</md-option>
<md-option :value="-1">その他</md-option>
</md-select>
</md-field>
</div>
</div>
<div class="row">
<div class="col-5 col">
<md-datepicker v-model="currentDate" @md-selected="console.log('changed')" />
</div>
<div class="col-5 col">
<md-field>
<label>Keyword</label>
<md-input v-model="currentKeyword"></md-input>
</md-field>
</div>
<div class="col-2 col">
<md-button class="md-icon-button md-raised md-primary" @click="search()">
<md-icon>search</md-icon>
</md-button>
</div>
</div>
</div>
</template>
<script>
import * as moment from 'moment';
export default {
props: {
categories: {
type: Array,
required: true
},
categoryId: {
type: Number,
default: 0
},
date: {
type: String,
default: null
},
keyword: {
type: String,
default: ''
}
},
data() {
return {
currentCategoryId: this.categoryId,
currentDate: this.date === null ? null : moment(this.date).toDate(),
currentKeyword: this.keyword
}
},
methods: {
selectCategory(categoryId) {
this.currentCategoryId = categoryId;
this.search();
},
search() {
let parts = [];
if (this.currentCategoryId !== 0) {
parts.push(`category_id=${this.currentCategoryId}`);
}
if (this.currentDate !== null) {
parts.push('date=' + moment(this.currentDate).format('YYYY-MM-DD'));
}
const keyword = this.currentKeyword.trim();
if (keyword !== '') {
parts.push('keyword=' + encodeURIComponent(keyword));
}
location.href = '/?' + parts.join('&');
}
}
}
</script>
今回作るサービスの肝です。これがなければTwitterで情報を見ることができるのでほとんど意味がなくなってしまいます。
とりあえずざっと思いついた流れは下記のようなものです。
この機能はそのまま クラス分類(Classification) というらしいです。機械学習としては恐らくよく用いられる分類だと思いますので、既にいくつも簡単に実装できるAPIやライブラリなどが数多く見つかりました。せっかくなので見つけて検討した順番にここで紹介していきます。
とりあえずGoogleなら何かあるだろ、と思って調べたら全くそのままのものがありました。これのclassifyText
メソッドを利用した「コンテンツの分類」という機能になります。しかもこれは学習させる必要がなく、予めGoogle側で定義されているカテゴリに分けてくれるというすぐれものです。しかもツイートであれば3万件ほどまで無料(多分)。
しかし試してみましたが、下記の問題がありました。
ということで一番手軽だったのですが、これは諦めることになりました…。
よくわからないのですがRecruitが無料で公開しているAPIです。こんなすごいものを無料で公開し続けるというのはいまいち良く分からないです。APIになっているのでインフラも無料では済まないでしょうし。どうなってるんだろう…。
機能的にはこれで問題なかったのですが、とりあえず最初にGoogleのAPIを知ってしまったので学習が要らないAPIを引き続き探しました。このAPIはデフォルトで求人関連のモデルが入っているので、その他の分類を行うためには自分でモデルを作る必要があります(簡単ですがデータを用意する必要があります)。
Watson Natural Language Classifier (自然言語分類)
これもA3RTと一緒だと思います。IBMが公開しているもので有料ですが無料枠があります。A3RTと同じ理由で次を探しました。
facebookresearch/fastText: Library for fast text representation and classification
こちらはfacebookが公開しているもので、A3RT、Watsonと同じクラス分類の機能があります。
なんかもうこれでいいんじゃないかな…と思ってこれを試しました。色々探しましたがGoogleのもののように良い感じに最初からカテゴリ分けされてるっぽいものはなさそうですし、ツイートであれば学習データを集めるのは特に難しいことではないし、学習させるというのも大事なことだと思ったためです。
また、下記のようなわかりやすい記事を見つけたのも試そうと思ったきっかけです。
機械学習で大量のテキストをカテゴリ別に分類してみよう!
具体的には
という感じで非常に簡単をクラス分類を行うことができるライブラリになっており、割とすんなり実装できました。
ちなみに僕は結局途中からpipで準備するのが面倒になったのでpythonもやめて直接コマンドを叩く形で実装しました。
./fasttext supervised -input data.txt -output model
./fasttext predict-prob model.bin 分類する文章が保存されているテキストファイルのパス
なんか、うまくいきませんでした。ツイートなので文章が全体的に短すぎるのか、何時間かしかかけずに集めたデータが少なすぎたのか、おかしなカテゴリに入ってしまうものが多発しました。
ということでここまで調べて実装しましたが機械学習でカテゴリ分けをするのはやめました。
ツイートに含まれるキーワードによりカテゴリ分けをする方法です。ひとつのカテゴリにいくつでもキーワードを設定できるようにしました。非常に的確にカテゴリ分類ができるようになりました。しかも非常に簡単です。そして非常にダサいです。
でも、今回の場合は募集ツイートに限るものだし、さほどバリエーションがあるとは思えません。文章も短く、精度も低くなりがちです。こういう場合にはわざわざ機械学習を導入せず、シンプルな方法を選択することも必要な場面はあると思います。今回はそれで良さそうな気がしています。分類されないものは全部「その他」カテゴリに入れています。
よろしければ実際に見てみてください。本家が一覧ページを作ったら消え去る運命のサイトです。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント