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