@spiritnotes
2016-03-16T08:45:37.000000Z
字数 14494
阅读 3978
读书笔记
机器学习
import numpy as np
a = np.array([1,2,3,4,5,6])
a.ndim, a.shape
a.reshape((3,2))
a[1][0] = 77
c = a.copy()
#对数组的操作传递到每个元素上
a*2
a**2
Scipy提供了基于NumPy数据结构之上的高效算法
fp1,*_ = sp.polyfit(x, y, n, full=True) 趋势线
f = sp.polyld(fp1) 创建模型函数
对数据进行拟合除了正常的数据还包括噪声。
data = sklearn.datasets.load_iris()
features = data['data']
feature_names = data['feature_names']
target = data['target']
for t,marker,c in zip(range(3), '>ox', 'rgb'):
plt.scatter(features[target == t,0],
features[target == t,1],
marker=marker,c=c)
通过花瓣长度可以将Iris Setosa与其他两种区分,其最大为1.9,而另外两种最小为3,另外两种之前的分类可以通过在特征上遍历阀值,最后选用最好特征上的最好阀值。
训练误差:训练集上面的误差;测试误差:测试集上面的误差;交叉验证:将数据分成n份,迭代使用n-1份进行训练,另外一份进行测试;
去一法: 极端交叉验证,每次只取出一个样本进行测试,对所有的样本同样进行;
常使用5折或者10折交叉验证。注意保持数据分布的均衡。去一法是对模型泛化能力的可靠估计。
分类模型的构成:
- 模型结构
- 搜索过程
- 损失函数
谨慎选择损失函数,一种可能情况是一种错误比另一种的代价更大,例如医疗中的假阴性和假阳性。
特征工程: 实际上不是新的测量值,而是部分可测量特征所组成的函数。这些特征对系统性能可能有很大影响。
好特征的目标是在重要的地方取不同的值,而在不重要的地方不变。特征选择就是将其中的好特征选择出来。
Z-score: 表示特征值离它的平均值有多远,用标准方差的数量来计算。
features -= features.mean(axis=0)
features /= features.std(axis=0)
多分类系统往往是通过二分类来实现的。
vec = sklearn.feature_selection.text.CountVectorizer(min_df=1)
x = vec.fit_transform(contents)
vec.get_feature_names()
x.toarray()
n_samples, n_features = x.shape
vec_new = vec.transform(new_content)
如下参数:
min_df = 1 / 0.1
analyzer = word
token_pattern = ...
sp.linalg.norm((V1-V2).toarray())
进行遍历时,可以使用 sys.maxint 来赋初始值。
V1_normalized = V1 / sp.linalg.norm(V1.toarray())
vectorizer = CountVectorizer(min_df=1, stop_words='english') #也可传入词表
vectorizer.get_stop_words()
语义相同而形式不同(过去式/进行时等)需要归约到特定的词干形式。
nltk.stem.SnowballStemmer('english').stem('buying')
将stemmer通过钩子放入向量化中:
class StemmedCountVectorizer(CountVectorizer):
def build_analyzer(self):
analyzer = super(StemmedCountVectorizer, self).build_analyzer()
return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))
TF-IDF(词频-反转文档频率),倾向于过滤常见的词语,留下重要的词语。
词频 (term frequency, TF) 指的是词语在该文件中出现的次数。为防止文件长短的影响,字通常会被归一化,通过除以文件总词数或者文件中词语出现的最大次数。
逆向文件频率 (inverse document frequency, IDF)是指示词语对该文件的识别度。可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。
class StemmedTfidfVectorizer(sklearn.feature_extraction.text.TfidfVectorizer):
def build_analyzer(self):
analyzer = super(TfidfVectorizer, self).build_analyzer()
return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))
聚类分为扁平聚类和层次聚类,扁平聚类往往需要预先指定簇的个数,而层次聚类则形成类似树的结构。
vectorizer = StemmedTfidVectrizer(min_df=10,max_df=0.5,stop_words='english',charset_error='ignore')
vectorized = vectorizer.fit_transform(dataset.data)
from sklearn.cluster import KMeans
km = kMeans(n_clusters=50,init='random',n_init=1,verbose=1)
km.fit(vectorized)
km.labels_
km.cluster_centers_
new_post_vec = vectorizer.transform([new_pos])
new_post_label = km.predict(new_post_vec)[0]
构建帖子列表
similar_indices = (km.labels_==new_post_label).nonzero()[0]
similar = []
for i in similar_indices:
dist = sp.linalg.norm((new_pos_vec - vectorized[i]).toarray())
similar.append((dist, data[i]))
similar = sorted(similar)
max_features
sklearn.metrics
线性判别式分析也称为LDA,在sklearn中有实现,非这里的LDA。
从最近邻开始,揭示其效果为啥不好
切换回逻辑回归
如何选择最佳模型
数据样本为文本,标签为二值数据
多种训练器选择
Stackoverflow的数据
按时间选择一部分
用cElementTree来解析XML
将大于0定义为正例,小于等于0的定义为负类
from sklearn import neighbors
knn = neighbors.KneighborsClassifier(n_neighbors=2)
knn.fit(data, target)
knn.predict(new_data)
knn.predict_proba(new_data)
特征:答案中的html链接数,可以发现多数答案没有链接
采用链接数使用cv进行测试,正确率很低,低于随机
from sklearn.cross_validation import KFold
scores = []
cv = KFold(n=len(X), k=10, indices=True)
for train,test in cv:
x_train, y_train = X[train], y[train]
x_test, y_test = X[test], y[test]
clf = KneighborsClassifier()
clf.fit(x_train, y_train)
scores.append(clf.score(x_test, y_test))
统计答案中代码行数
句子中的平均词语个数
帖子中词语的平均字符个数
大写形式的词语个数
感叹号的个数
由于采用knn,其不同特征维度范围不一致,其导致结果变差
这种时候增加数据用处不大,模型过于简答化,方法是增加更多特征,让模型更复杂或其他模型
测试误差开始有下降,随着数据规模扩大,和训练误差越来越接近
模型对于数据过于复杂,获取更多数据,降低模型复杂度,删减特征
测试误差与训练误差之间存在着巨大差距
from sklearn.liner_model import LogisticRegression
clf = LogisticRegression() #C为则化参数
clf.fit(x, y)
clf.intercept_, clf.coef_
从结果看仍然是高偏差
准确率
召回率
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(y_test, clf.predict(x_test))
#选取所需阀值
thresholds = np.hstack(([0],thresholds[midium]))
idx80 = precision>= 0.8
thresh80 = threshold[idx80][0]
probs_for_good = clf.predict_proba(answer_feature)[:1]
answer_class = probs_for_good > thresh80
from sklearn.metrics import classification_report
classification_report(y_test, clf.predict_proba[:1]>0.63, target_names=['not accepted','accepted'])
一个特征的系数越高其决定好坏的作用就越大,负值表示将其分成负类的作用。
可视化
观点挖掘
介绍分类算法:朴素贝叶斯
阐释词性标注(Part of speech,POS)是如何工作以及如何帮助我们
展示sklearn工具箱中的一些小技巧
贝叶斯
Lidstone平滑:
使用log
sklearn.naive_bayes
很多推文是中性的,将中性推文过滤掉,将Y赋值为0,1,
构建分类器
from sklearn.feature_extraction.text import TfidfVectorizer
from sklaern.naive_bayes import MultinomiaNB
from sklearn.pipeline import Pipeline
tfidf_ngrams = TfidfVectorizer(ngram_range=(1,3),analyer='word',binary=False)
clf = MultinomiaNB()
pipeline = Pipeline([('vect',tfidf_ngrams),('clf',clf)])
训练
from sklearn.metrics import precision_recall_curve,auc
from sklearn.cross_validation import ShuffleSplit
cv = ShuffleSplit(n=len(X),n_iter=10,test_size=0.3,indices=True,random_state=0)
for train,test in cv:
clf = pipeline()
clf.fit(x_train, y_train)
train_score = clf.score(x_train,y_train)
test_score = clf.score(x_test,y_test)
scores.append(test_score)
proba = clf.predict_proba(x_test)
precision,recall,pr_thresholds=precision_recall_curve(y_test,proba[:,1])
pr_scores.append(auc(recall,precision))
np.mean(scores),np.std(scores),np.mean(pr_scores),np.std(pr_scores)
AUC=0.88
使用GridSearchCV():
Param_grid={"vect__ngram_range"={(1,1),(1,2)...}
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import f1_score
cv = ShuffleSplit(n=len(X),n_iter=10,test_size=0.3,indices=True,random_state=0)
param_grid=dict(vect__ngram_range=[(1,1),...]...)
grid_search = GridSearchCV(pipeline(),param_grid=param_grid,cv=cv,score_fun=f1_score,verbose=10)
grid_search.fit(X,Y)
grid_serach.best_estimator_
为tfidfVectorizer提供自己定制的preprocessor()
将表情符号以及替代词语转换为正面或者负面语言
用正则表达式及其扩展来定义那些缩写形式:
r'\br\b','are'
TfidfVectorizer(preprocessor=preprocessor,...)
nltk.pos_tag()
http://sentiwordnet.isti.cnr.it
提高的文件中包含了POS分数和NEG分数,对于有几个意思的词语取平均dict_[(type_, word_)]
实现方式是继承自BaseEstimator
class LinguisticVectorizer(BaseEstimator):
pass
针对每个doc分别将其拆分后计算出如下值,各个词之间可以求均值
中性分值,正分值,负分值,名词个数,副词个数,动词个数,形容词个数,allcaps,!个数,?个数,#个数,@个数
tfidf_ngrams = TfidfVectorizer(preprocessor=preprocessor,analyzer="word")
ling_stats = LinguisticVectorizer()
all_features = FeatureUnion([('ling',ling_states),('tffidf',tfidf_ngrams)])
clf = MultinomialNB()
pipeline = Pipeline([('all',all_features),('clf',clf)]
普通最小二乘法(OLS,Ordinary Least Squares)
lasso法
岭(ridge)回归
弹性网络(elastic net)
w, total_error, _, _ = np.linalg.lstsq(x,y)
均方根误差,与标准差
x = np.array([np.concatenate([v,[1]],axis=0) for v in boston.data])
w, error, _, _ = np.linalg.lstsq(x, boston.target)
from sklearn.linear_model import LinearRegression
lr = LinearRegression(fit_intercept=True)
lr.fit(boston.data, boston.target)
p = map(lr.predict, x)
e = p-y
total_error = np.sum(e*e)
rmse_train = np.sqrt(total_error/len(p))
from sklearn.cross_validation import Kfold
kf = KFold(len(x), n_folds=10)
err = 0
for train, test in kf:
lr.fit(x[train],y[test])
p = map(lr.predict, x[test])
e = p - y[test]
err += np.sum(e*e)
rmse_10cv = np.sqrt(err/len(x))
惩罚式回归是偏差-方法折中的另一个例子,在使用惩罚项的时候,由于增加了偏差,我们会得到一个训练效果差一些的拟合。但另外一个方面,我们降低了方差,从而更易于避免过拟合。整体泛化效果更好。
L1惩罚模型通常叫做Lasso法,L2惩罚模型叫做岭回归(Ridge regression)。两者结合形成弹性网(Elastic net)模型。
Lasso法会使更多的系数为0,可以通过该方法进行特征选择。
from sklearn.linear_model import ElasticNet
en = ElasticNet(fit_intercept=True, alpha=0.5)
即特征数多于样本数目
采用10-k reports数据,由于特征比样本多。
sklearn中含有LassoCV,RidgeCV,ElasticNetCV来进行内部参数封装交叉验证检查。
from sklearn.linear_model import ElasticNetCV
met = ElasticNetCV(fit_intercept=True)
kf = KFold(len(target),n_folds=10)
for train,test in kf:
met.fit(data[train],target[train])
p = map(met.predict, data[test])
p = np.array(p).ravel()
e = p - target[test]
err += np.dot(e,e)
rmse_10cv = np.sqrt(err/len(target))
设置为回归问题更好
构建电影特定模型
构建用户特定模型
reg = LassoCV(fit_intercept=True,alphas=[.125,.25,.5,1,2,4,8])
u = reviews[i]
u = u.array().ravel() #转为一维数组
ps, = np.where(u > 0)
us = np.delete(np.arange(reivews.shape[0]),i) #其他用户除了i
x = reviews[us][:,ps].T
y = u[ps] #用户打分过电影
kf = KFold(len(y), n_folds=4)
for train,test in kf:
xc,x1 = movie_norm(x[train])
reg.fit(xc,y[train]-x1)
xc,x1 = movie_norm(x[test])
p = np.array(map(reg.predict,xc)).ravel()
e = (p+x1)-y[test]
err += np.sum(e*e)
def movie_norm(x):
xc = x.copy().toarray()
x1 = np.array([xi[xi>0]].mean() for xi in xc)
x1 = np.nan_to_num(x1) #只有本用户看的电影,其他会为NAN,赋值0
for i in range(xc.shape[0]):
xc[i] -= (xc[i]>0)*x1[i] #减去均值进行归一化
return xc,x1
将之前的打分矩阵,改变为二值矩阵,看过的就改为1,没有看过改为0
可视化
from matplotlib import pyplot as plt
imamedata = reviews[:200,:200].todense()
plt.imshow(imagedata, interpolation='nearest')
计算用户之间的相似性
np.corroef(a,b)[0,1]
估算分数
bu = user > 0
br = rest > 0
ws = all_correlations(bu,br)
selected = ws.argsort()[-100:]
estimates = rest[selected].mean(0)
estimates /= (.1+br[selected].mean(0))
for i in range(nmovies):
movie_likeness[i] = all_correlations(review[:,i],reviews.T)
movie_likeness[i,i] = -1
likes = movie_likeness[movie_id].argsort()
likes = [::-1]
for movie in likes:
if reviews[u_id, movie] > 0:
return reviews[u_id, movie]
集成学习
寻找真正的是:相比基准,在统计上更可能购买Y的购买了X的客户
而不是推荐热销产品,个性化推荐上没有更好
超市购物篮数据
可视化
提升度:规则和基线所得到的概率之间的比值
pymining程序
对MP3分类:古典、乡村、流行。。。
数据集: GTZAN
把所有音乐转换为WAV格式,scipy可以直接读取
import scipy as sp
from matplotlib.pyplot import specgram
sample_rate, X = scipy.io.wavfile.read(wave_filename)
specgram(X, Fs=sample_rate, xextent=(0,30))
从原始样本中(储存在X中)提取频率强度,并传进分类器。频率强度可以通过快速傅里叶变换得到(Fast Fourier Transform,FFT)
sox --null -r 22050 sina_a.wav synth 0.2 sine 400
fft_features = abs(scipy.fft(X)[:1000])
np.save(data_fn, fft_features)
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
通常说的图像处理是对图像进行处理,得到一张新的或更好的图片(可能含有较少的噪声或者是另外一个样子)。
图像预处理
分类
图像的局部特征
import mahotas as mh
image = mh.imread(file_name)
阀值
binarized = (image > threshold_value)
image = mh.colors.rgb2gray(image, dtype=np.uint8)
thresh = mh.thresholding.otsu(image)
thresh2 = mh.thresholding.rc(image)
高斯模糊
image = mh.colors.rgb2gray(image)
im8 = mh.gaussian_filter(iamge, 8) #滤波器的标准差,越大越模糊
增加椒盐噪声
salt = np.random.random(lenna.shape) > 0.975 #白
pepper = np.random.random(lenna.shape) > 0.975 #黑
lenna = mh.stretch(lenna)
lenna = np.maximum(salt*170, sep)
lenna = np.minimum(pepper*30+lenna*(~pepper),lenna)
计算特征
mh.features.haralick(image)
特征
加速稳健特征(speeded up robust feature)
尺度不变特征变换(scala-invariant feature transform, SIFT)
降维的原因:
大致分为特征选择法和特征抽取法。使用PCA(principal component analysis,主成分分析)/LDA(linear discriminant analysis,线性判别式法)/MDS(multidimensional scaling,多维标度法)
如果数据特征之间没有依赖关系,同时又和预测值相关,删除任何一个特征都会导致性能的下降。
两种通用做法:筛选器(filter)和封装器(wrapper)。
基于统计的方法找出冗余或者无关特征
把特征的重要性放到模型的训练流程中。
RFE(recursive feature elimination,特征递归消除),将一个估算器和预期数量的特征当做参数,然后只要发现一个足够小的特征子集,就在这个特征子集中训练估算器。
from sklearn.feature_selection import RFE
selector = RFE(clf, n_feature_to_select = 3)
selector = selector.fit(X,Y)
selector.support_
selector.ranking_
有些选择是根植于机器学习方法中。如决策树、L1正则化。
PCA是一个线性方法。在给定原始特征空间,PCA会找到一个更低维空间的线性映射。
最终的重构误差(从变换后特征回到原始特征)是最小的;
矩阵的特征值预示着方差的大小。
from sklearn.decomposition import PCA
pca = PCA(n_components=x)
Xtrans = pca.fit_transform(X)
pca_.explained_variance_ratio ## 保留的方差
只能针对线性数据,对于非线性数据,有 kernel PCA 进行扩展
如果分类最佳特征出现在方差弱的特征上,则其有问题(PCA不考虑结果值)
LDA是一个有监督的降维方法。
from sklearn import lda
lda_ = lda.LDA(n_components=1)
X_trans = lda_.fit_transform(X, Y)
当类别变多后,每种类的样本空间变少,LDA的效果会变差。因此选用方法只能是具体情况具体分析。
MDS在降维的时候试图尽可能保留样本间的相对距离。对一个高维数据集试图获得视觉印象的时候非常有用。
MDS多数据点本身并不关心,对数据集点间的不相似性很感兴趣,并将不相似性解释为距离。
MDS试图在低空间中放置数据点,使得新的距离尽可能与原始空间中的距离相似。MDS是一个揭示数据相似性的有用工具。
from sklearn import manifold
mds_ = manifold.MDS(n_components=3)
X_trans = mds_.fit_transform(X)
略