用机器学习过滤微博
@自扯自蛋的写的扯经系列很有意思。作者的博客有早期的扯经的合集。为了看扯经有段时间还天天翻新浪微博。不过后来看不到扯经更新了,以为是作者不写了,直到有一天,作者说在网易微博上还在写!这不是坑爹吗!!!害我追了大半天,结果在别的地方开坑了!总不能又翻一遍网易微博,在作者的碎碎念中找一个个扯经吧,所以一直想把网易微博上的扯经过滤出来。最近一直在做 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 格式的文件传递信息真的是非常的方便啊。