粒子群优化算法演示
快速排序

用机器学习过滤微博

scturtle posted @ 2011年12月01日 14:52 in algorithm , 2674 阅读

@自扯自蛋的写的扯经系列很有意思。作者的博客有早期的扯经的合集。为了看扯经有段时间还天天翻新浪微博。不过后来看不到扯经更新了,以为是作者不写了,直到有一天,作者说在网易微博上还在写!这不是坑爹吗!!!害我追了大半天,结果在别的地方开坑了!总不能又翻一遍网易微博,在作者的碎碎念中找一个个扯经吧,所以一直想把网易微博上的扯经过滤出来。最近一直在做 Stanford 的在线的 Machine Learning 课程 programming exercise 6 中给出了如何用支持向量机(support vector machine,SVM)来过滤垃圾邮件的例子,这不正好用上了,遂有此文,是以为记。

首先要得到作者的所有3560条微博,想用 api 爬,结果发现这也需要 oauth 登录。使用 oauth.net/code/ 上推荐的库 python-oauth2 没成功。直接上网易微博自己的 python 库 t4py 。按照说明改 t4py\tblog\constants.py 里的 CONSUMER_KEY 和 CONSUMER_SECRET 以及 在ACCESS_TOKEN_FILE 所指的文件中加上自己的名字,Acess token 和 Acess token secret。

按照 example 写了这样一个脚本得到自扯自蛋的所有微博:

# -*- coding: utf-8 -*-

import json

from t4py.tblog.tblog import TBlog
from t4py.tblog.constants import CONSUMER_KEY
from t4py.tblog.constants import CONSUMER_SECRET
from t4py.http.oauth import OAuthToken
from t4py.utils.token_util import TokenUtil

util = TokenUtil()
str = util.get_token_str('scturtle')
t = TBlog(CONSUMER_KEY, CONSUMER_SECRET)
t._request_handler.access_token = OAuthToken.from_string(str)

all=[]
last_id=None

tweets = t.statuses_user_timeline({'name':'自扯自蛋','count':200,'trim_user':'true'})
tweets = json.read(tweets)
for i in tweets:
    all.append(i['text'])
print 'So far:',len(all)
last_id = tweets[-1]['cursor_id']

for page in range(20):
    tweets = t.statuses_user_timeline({'name':'自扯自蛋','count':200,'trim_user':'true', 'since_id':last_id})
    tweets = json.read(tweets)
    try:
        for i in tweets:
            all.append(i['text'])
    except:
        print 'error:',tweets
        break
    print 'So far:',len(all)
    if len(tweets) == 0:
        break
    last_id = tweets[-1]['cursor_id']

print 'Got:',len(all)
with file('alltweets.txt','w') as f:
    f.write(json.write(all))

print 'Done!'

在网易的库里发现一个简单的 json 库,很好用,下面就用它而不是 python 自带的库了。

然后该提取 features 了。个人考虑,重要关键字基本上都是两个字的,比如“扯经”,“小北”,“师父”等等。于是就把所有微博按两个字一词地统计了一下词频。

dicts={}

for t in tweets:
    for i in range(len(t)-1):
        dicts[t[i:i+2]]=dicts.get(t[i:i+2],0)+1

看了一下,想要的关键词差不多都包含在前200个词里面,于是没有继续筛选,直接上前200个词作为 features。

接着该找 training set 和 test set 。从所有微博中 sample 出300个来,80%作为 training set ,20%作为 test set 。training set 和 test set 都要按照 features 转化成01向量,即微博中有某 feature 则对应向量中的哪一位为1否则为0。同时还写了个脚本人工判断结果,否则就不能 train 和 test 了。

res = [ [t,[],0] for t in tset ]

for i,r in enumerate(res):
    print 'Training set:',i
    print '<<',r[0].decode('utf8') ,'>>'
    res[i][1]=map(lambda f: 1 if f[0] in r[0] else 0, features)
    ans = raw_input('Yes? ')
    res[i][2]=1 if ans else 0

接着就是 octave 的戏份了。调用 exercise 中提供的 octave 脚本(用到的有svmTrain.m, linearKernel.m 和 svmPredict.m)训练和预测就可以了。

%% Initialization
clear ; close all; clc

fprintf('Loading training set and test set ...\n');

allX = load('t_x.mat');
ally = load('t_y.mat');

m=length(ally);

training_percent = 0.8;

X = allX(1:ceil(m * training_percent),:);
y = ally(1:ceil(m * training_percent),:);

Xtest = allX(ceil(m * training_percent):end,:);
ytest = ally(ceil(m * training_percent):end,:);

C = 0.1;

% training set 
model = svmTrain(X, y, C, @linearKernel);

p = svmPredict(model, X);
fprintf('Training Accuracy: %f\n', mean(double(p == y)) * 100);

fprintf('Program paused. Press enter to continue.\n');
pause;

% test set
p = svmPredict(model, Xtest);
fprintf('Test Accuracy: %f\n', mean(double(p == ytest)) * 100);

fprintf('Program paused. Press enter to continue.\n');
pause;

% sort and save features
fprintf('Sorting features ...\n');
[weight, idx] = sort(model.w, 'descend');

fprintf('Saving features ...\n');
out = fopen('feature.json','w');
fprintf(out,'[ %d',idx(1));
for i=2:length(idx),
	fprintf(out,', %d',idx(i));
end
fprintf(out,']');
fclose(out);

fprintf('Program paused. Press enter to continue.\n');
pause;

% predict all
fprintf('Predict for all ...\n');

Xall = load('all_x.mat');
p = svmPredict(model, Xall);

% to json
out = fopen('predict.json','w');
fprintf(out,'[%d',p(1));
for i=2:length(p),
	fprintf(out,', %d',p(i));
end
fprintf(out,']');
fclose(out);

fprintf('Done! Press enter to exit.\n')
pause;

结果按 json 格式保存出来再用 python 处理一下即可。

训练中可以看到 training set 和 test set 的准确率都达到了惊人的100%。打印出权重最高的几个 feature 可以看到符合预期,包含了“扯经”,#号,【】号,“小北”,“师父”等重要关键字:

扯经
#扯
小北
 #
】【
?】
】
已经
师父
【师
怎么
,一
,就
。】

分类后的微博也非常理想。扯经类里一溜儿的扯经。搜索非扯经类里,没有“小北”,含“师父”的一条并不是扯经,有几个含“扯经”的扯经没有分对,但是也有几个含“扯经”的确实只是一些讨论。总体效果很理想。

总结一下,python 很给力,无论是网络部分还是字符串处理部分,要是会 numpy 和 scipy 的话说不定 octave 的部分也能包办了。ML 课程的练习质量很高,既提供了很多好思路又提供了一些实际可用的脚本,不会让人上完课后还感到无从下手。还有在脚本之间用 json 格式的文件传递信息真的是非常的方便啊。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter