毎朝、ニュースをいい感じに通知できると便利ですよね。というわけで、Google Apps Script(以下GAS)で作りました。
とあるニュースRSSからURLとタイトルが取得できるので、あとはそれなりの精度で分類して通知するプログラムを作りました。技術ニュースは英文のものも多いので、「日本語と英語をごちゃ混ぜの状態のものをいい感じに判定する」部分を工夫して実装しました。
実装
アイデア自体はシンプルで、以下の処理を行っているだけです。
- Google翻訳で英文に翻訳する(GASではLanguageAppで簡単に翻訳可)
- "-"などを取り除く
- 単語のn-gramを取って、特定の単語が含まれているものをタグ付けする
- (整形してチャットに通知)
単語のタグ付けのための辞書(ハッシュテーブル)を作る
こういう単語表を気合いで準備します。うまく判定出来なかったものがあれば、その都度追加していきます。
ここで、'machine-learning'
のような"-"区切りの単語は、2単語を表しています。
var raw_dict = {
'機械学習・データ処理': ['tensorflow', 'chainer', 'ai', 'ais', 'ml', 'deep-learning', 'reinforcement-learning',
'machine-learning', 'deep-learning', 'data-infrastructure', 'gpu',
'feature', 'analysis', 'p-hacking', 'natural-language', 'big-data', 'neural-network', 'jupyter', 'jupyter-notebook',
'data-science', 'data-scientist', 'data-scientists', 'statistics', 'statistical', 'predict', 'predicts',
'regression', 'linear', 'matplotlib', 'kagglers', 'kaggler', 'kullback-leibler', ...],
'セキュリティ': ['security', 'leakage', 'privacy', 'ssh', 'tls', ...],
# 以下略
先程の辞書を加工していきます。"-"の有り無しを両方ルールとして作るのは、例えば'ReactNative'と'React Native'のようなの表記ゆれに対応するためです。
function createDict(raw_dict) {
var result = {};
for (key in raw_dict) {
raw_dict[key].forEach(function(val) {
// "-"が有ってもなくても判定
result[val.replace('-', '')] = key;
result[val] = key;
});
}
return result;
}
英語に翻訳して判定する
TAGGING_DICT
が、先程の関数で作った辞書です。
ニュースの判定は、文頭から3単語→2単語→1単語の順にチェックしていきます。これによって、例えば'web-assembly'はフロントエンド技術として、'assembly'は情報工学系の話として判定することができます。
判定できなかった場合は「その他」に分類します。
function tag(title) {
// 日本語を英語に翻訳(英語は英語のまま)
var eng_title = LanguageApp.translate(title, 'ja', 'en');
// 小文字に統一し、余計な文字を取り除く
var words = eng_title.replace(/[\.|,|:|'|"|\!|\?| |\-||【|】|\[|\]]+/g, ' ').toLowerCase().split(' ');
return (createNgrams(words)).reduce(function(res, w) {
if (res) return res;
res = TAGGING_DICT[w];
return res;
}, null);
}
function createNgrams(words) {
// 3単語までに対応
return [3, 2, 1].reduce(function(res, n) {
return res.concat(createNgram(words, n))
}, [])
}
function createNgram(words, n) {
var queue = [];
return words.reduce(function(res, w) {
queue.push(w);
if (queue.length >= n) {
res.push(queue.join('-'));
queue.shift();
}
return res;
}, []);
}
現状の問題と今後の展望
それなりの精度で判定できるようになりましたが、いくつかの問題があります。
- 「AI」という単語を機械学習系のニュースとして扱うか困る
- 複数形の違いで判定できないことがある
- 「暗号通貨」「仮想通貨」など、日本語から英語への翻訳が一定でない単語がある
- ('virtual-currency', 'crypto-currency', 'cryptographic-currency', 'encryption-currency'などをその都度追加して対応)
- フロントエンドの「デザイン」と、バックエンドの「設計」が両方'design'になってしまう(英語としては正しいですが)
- セキュリティ関連のニュースなど、URLだけで明らかに判定できるものもあるのでURLの判定ルールを追加したい
- 一般的な単語が技術名に使われている場合に判定できない。例えばGo言語が単に'go'と表記されていた場合、判定できない。
- 単語ルールが肥大化してきたのでどうにしかして楽したい