あうのかあわないのかはっきりしろや!的なCLIを書いてみた。
自分のブログに似ているかどうかをベイズ分類しています。似てないのサンプルを集めるのが面倒だったけど、アメブロあたりから適当にチョイスしました。もちろん西野カナはあわないほうに分類しておいた。
一応、5/25の入門機械学習読書会の宣伝も兼ねているので、機械学習に興味があったり、つけナポリタンを食べたかったり、会いたかったり会えなかったりするヒトは参加するといいです。今日はPythonで書いていますが、次回の読書会では由緒正しきRでベイズ分類器を実装していきます。
入門 機械学習
Drew Conway
オライリージャパン / 3360円 ( 2012-12-22 )
例えば伊東のGentoo過激派と私の相性は
$ ./nk "http://blog.karky7.net/feeds/posts/default?alt=rss"
きみにあうよ
あうかな: ffmepgコマンドでmp4の動画からm4a(音声)を抜き出してみた
あうかな: HACKING: 美しき策謀(第2版) がたまらなく面白い
あうかな: gentooのpython-pptxで美人の水着画像をpptx化する
あうかな: 静岡Python会、Shizuoka.py行ってきました
あうかな: gentooのJuicyPixelsのebuildを作りました
あうかな: gentooでudevのUpdateにはご注意下さい...
あうかな: gentooで emacs + cscope を使ってタグジャンプでコードを飛びまくる
あうかな: 2日酔いからPersistentでキーを使って直接データを引く
あうかな: WebデザイナーこそGentooを使うべき4つの理由
あわない: 2013年 プログラマーの皆さん河津桜の季節です
あうかな: Linuxでカーネルオプションを探す方法
あわない: 2013年 伊東オレンジビーチマラソン走りました
あうかな: セガール君、お土産 in America
あうかな: Sabayon Linuxにちょっと惹かれてしまった
あわない: 新年の山走り行ってきました
あうかな: HaskellのPersistent MySQLを試してみた
あわない: 2012年大晦日オフロードツーリングへ行ってきたよ
あうかな: LXCのネットワーク設定...続き
あうかな: GentooでPersistent-MySQLのebuildを作ってみた
あうかな: GentooのLXC(Linux Container)をやってみた
あうかな: Gentooでemacs+haskell環境を作る
あうかな: HaskellのFunctorのおさらい
あうかな: TemplateHaskellを調べてみた
あうかな: btrfsを実際に触ってみた
あうかな: Gentoo + nginx + FastCGI PHP で高速PHP環境を構築する
余裕であえますね。これっぽっちも切なくなんかない。
eしずおかからお酒のブログ
$ ./nk http://osake.eshizuoka.jp/index.xml
きみにあうよ
あうかな: 富士山、世界遺産登録勧告ということで
あわない: チケット3日で完売の、焼津の酒イベント
あわない: さぁ今日は無礼講だ!季節限定ベアード
あわない: ZUNビールの味に近いベアード販売中
あうかな: 再々入荷しました!幻の米の臥龍梅
あわない: 豊田一丁目、倉庫火災出動
あうかな: お寺の庭のゆず♪ 季節限定ベアード
あうかな: 【入荷】志太泉の普通酒が普通じゃない
あうかな: 5.3 由比桜えびまつりヽ(゚∀゚)ノ
あわない: 裏鈴木酒店 『とある酒屋の超萌酒会2』
あうかな: 【入荷】英君の特別純米の袋吊り雫だ
あうかな: 【入荷】杉錦の誉富士山廃純米生原酒
あうかな: 再入荷しました♪ 臥龍梅の渡船!
あわない: 駿河区にまた大型ショッピングセンター
あわない: 眼鏡っ娘のめがね拭きができました!
あわない: 焼津のあの娘(仮)の、大きめ画像
あうかな: お手頃♪ 臥龍梅、純米吟醸ワンカップ
あうかな: 【再入荷】最後の、そに子の痛茶です!
あうかな: 【入荷】臥龍梅。幻すぎる、短稈渡船だ
あわない: 静鉄の長沼駅でさりげなく萌えてみる
萌えよりも日本酒ってことでしょうか?あと、ビールも飲めってことかな。
というわけで、適当に作ったわりには良い感じで分類できている気がしますね。
使い方
$ ./nk --help
Nishino Kana
Usage:
nk ([-l <conf>|--learn=<conf>] | <url>)
Options:
-h --help show this screen
-l <conf> --learn=<conf> training
設定ファイルはjsonです。kanaがあうほうでanakがあわないほうです。
{
"kana": ["http://127.0.0.1:5000/rss/"],
"anak": [
"http://feedblog.ameba.jp/rss/ameblo/nishino-kana/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/yamamo-tomato/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/financilthory011/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/hazu-r72t/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/hitomi19800911/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/1983mayumayu/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/2pmoneday2/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/to-meee/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/sa-ku-ra-0706/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/taiyakisuki8/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/pikatyu-tyu/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/urakamimieko/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/wins-motomiya/rss20.xml",
"http://feedblog.ameba.jp/rss/ameblo/taisukekmft2/rss20.xml"
]
}
コード
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import feedparser
import MeCab
import re
import json
import nltk
from docopt import docopt
import pickle
html_tag = re.compile(r'<[^>]+>')
cmd = """Nishino Kana
Usage:
nk ([-l <conf>|--learn=<conf>] | <url>)
Options:
-h --help show this screen
-l <conf> --learn=<conf> training
"""
def morph(entry):
txt = html_tag.sub('', entry.summary_detail.value)
words = []
try:
t = MeCab.Tagger()
m = t.parseToNode(txt.encode('utf-8'))
while m:
if m.stat < 2:
if re.match('名詞', m.feature): words.append(m.surface)
m = m.next
except RuntimeError:
pass
return words
def feed_parse(url):
d = feedparser.parse(url)
words = []
for entry in d.entries:
words.extend(morph(entry))
return words
def extract_features(document):
documentwords = set(document)
return dict([('contains(%s)' % word, True) for word in documentwords])
def learn(conf):
c = json.load(open(conf), encoding="utf-8")
kana = []
anak = []
for url in c["kana"]:
kana.extend(feed_parse(url))
for url in c["anak"]:
anak.extend(feed_parse(url))
training_documents = [(kana, "kana"), (anak, "anak")]
train_set = nltk.classify.apply_features(extract_features, training_documents)
classifier = nltk.NaiveBayesClassifier.train(train_set)
with open("classifier.pickle", "wb") as f:
pickle.dump(classifier, f)
def test(url):
classifier = pickle.load(open("classifier.pickle"))
d = feedparser.parse(url)
rcode = {"kana": "あうかな", "anak": "あわない"}
total = 0
result = {"status": None, "entry": []}
for entry in d.entries:
doc = morph(entry)
r = classifier.classify(extract_features(doc))
if r == "kana":
total += 1
result['entry'].append((rcode[r], entry.title.encode("utf-8")))
if total > 3:
result['status'] = "きみにあうよ"
else:
result['status'] = "きみにあわないよ"
return result
if __name__ == '__main__':
args = docopt(cmd)
conf = args.get('--learn')
url = args.get('<url>')
if conf:
learn(conf)
elif url:
r = test(url)
print r['status']
print
for code, title in r['entry']:
print "{}: {}".format(code, title)
尚、TDMを構築するのが面倒だったのでNLTKを使いました。
入門 自然言語処理
Steven Bird
オライリージャパン / 3990円 ( 2010-11-11 )