数据不平衡时分类器性能评价之ROC曲线分析

大家在将统计学习方法用于实际应用时,不免会遇到各类间数据不太平衡的情况。比如垃圾邮件的识别、稀有病情的诊断、诈骗电话识别、情感分析等等情况。导致数据不平衡的原因有很多,有可能是因为不恰当的采样方法,也可能真实的数据分布就是如此;然而真实的数据分布在大多数情况下我们是无从得知的,于是我们只好认为我们所取得的样本是“真实”的,再从中进行学习。那么针对数据不平衡有很多研究点,最近稍微调研了一下,这也算是一个比较老的Topic了。2000 AAAI/2003 ICML先后有两次Workshop对此进行讨论,之后似乎研究的人就比较少了。

本文主要关注的是在类间数据不平衡的情况下,如何评价分类器的性能?至于这个问题本身的更详细分析,只要在google scholar中搜索“Learning from Imbalance data”就会看一堆资料了,我也看了一些,但是不细致,最近实在是很忙。


在AAAI(2000) Workshop上,有两个问题最受关注。

  1. 在类不平衡(class imbalances)的情况下,如何评价学习算法的性能?
  2. 类不平衡与代价敏感学习(cost-sensitive Learning)的关系。

今天稍微研究了一下第一个问题。既然要评价,那么也就默认了一个前提假设:类样本不平衡是符合实际数据分布的(训练集和测试集同分布)。要评价一个二元分类器的性能,人们自然而然地想到Accuracy。而对于不平衡数据,这是否合适?看一个简单的例子:假设这个世界上有99.9%的人不患癌症,0.01%的人身患癌症。于是我们想设计一个分类器,来判断一个病人是否身患癌症。那么在已有先验知识的情况下,我只需要认为所有病人都不患癌症,那么分类器至少能达到99.9%的分类准确率。显然,这个分类器一点儿价值也没有。同理,对于n:1(n比较大)的类样本分布,只需要认为所有样本都属于n那一类,准确率就可以达到非常高,可是没有任何意义和参考价值。所以,Accuracy的衡量标准在这里是不合适的。

ROC分析为这个问题提供了一个比Accuracy更为准确的度量方式:)

先简单看一下混淆矩阵(confusion matrix)。混淆矩阵是评估分类器可信度的一个基本工具。以二元分类器为研究对象,下面的混淆矩阵显示了一个分类器可能遇到的所有情况:

positive negative
positive’ TP (true positive) FP (false positive)
negative’ FN (false negative) TN (true negative)

 

其中列对应于样本实际的类别,行对应于样本被预测的类别。这四个基本指标可以衍生出多个分类器指标:

  1. FP rate = FP / N;N为负样本数
  2. TP rate = TP / P;P为正样本数
  3. Accuracy = (TP + TN) / (P + N);//我们一般用的
  4. Precision = TP / (TP + FP)
  5. Recall = TP / P
  6. F-score = Precision * Recall

其中Accuracy是我们最经常使用的,在某些领域,Precision/Recall也很频繁。

以上这些都属于静态的评价指标,如前所述,当正负样本不平衡时存在严重的问题。

于是,ROC曲线和AUC(曲线包围面积)应运而生。

ROC曲线描述的是混淆矩阵中FPR(FP rate)和TPR两个量之间的相对变化关系。如果二元分类器给出的是对正样本的一个分类概率,那么通过设定不同的阈值,可以得到不同的混淆矩阵,而每个混淆矩阵都对应于ROC曲线上的一个点。将这些点描绘出来可以得到一条平滑的曲线,这时,我们可以用曲线所包围的面积,即AUC,来评估该二元分类器的可信度。这就是ROC分析,说完啦。看一幅来自Wikipedia的图:

横轴为FPR,纵轴为TPR。如果混淆矩阵表示的点(FPR,TPR)处在中间那根红线上,则表示该分类器没有区分能力。以前面的n:1为例,如果分类器简单地把所有样本分至n这一类,则正好处在右上角,即(1, 1)。再试想一下数据平衡1:1的情况,当分类器处于红线上时,容易计算出Accuracy为50%,对于二元分类器而言,没有什么比准确率低于50%更丢人的事情了……

所以,点若处在左上角部分,则说明分类器性能不错,若不幸在右下角,那么这个分类器无疑是一坨。。

我们根据不同的阈值得到了ROC曲线之后:

可以通过计算该曲线所包围的面积(AUC)来衡量分类器的可信度。面积越大,则可信度越高。不过面积可不好计算,因为我们得到的都是离散点。对此有兴趣的话,可以参考下这篇文章(ICML 2006)

The Relationship Between Precision-Recall and ROC Curves

这篇文章附着一个计算AUC的Java工具包:http://mark.goadrich.com/programs/AUC/

一般认为,对于一个诊断实验,AUC在0.5~0.7之间时,诊断价值较低;在0.7~0.9之间,诊断价值中等;在0.9以上时诊断价值较高。这是医学诊断上的经验了,对于其他领域的分类器如何,还需要在实践中摸索。

 

Categories: Machine Learning | Tags: , , , , , , , | 6 Comments

Semi-supervised Learning – 记Sigml第0期活动

此次活动主要从分类问题的角度来讨论半指导学习(Semi-supervised Learning)。半指导学习的概念说起来一点儿也不复杂,即从同时含有标注数据和未标注数据的训练集中学习模型。半指导学习是介于有指导学习与无指导学习之间的一种机器学习方式。

在NLP领域的很多任务中,标注数据其实是很难获取的。尤其像句法、语义等训练资源在标注时往往需要比较深厚的专家知识(如语言学知识)作为指导,从而导致标注成本太高。尽管现在大家都在提倡标注简单化、大众化甚至娱乐化,但是对于这种知易行难的问题,要找到一种能利用群体智慧的标注方式又是何其难也。近年来比较热的“众包”技术也没能够有效地解决这种“专家级”标注问题。从这个角度来看,半指导学习是非常有意义而且值得研究的。上半年UIUC的高晶学姐回学校做了一次关于融合有指导学习与无指导学习的报告,我个人觉得很受启发。

于是,就有了我们的第0期Sigml(Special Interest group of Machine Learning)活动。

由于半指导学习本身理解起来并不难,因此概念以及定义之类的这里就不赘述了。下面主要总结一下本次活动中所讨论的半指导学习方法(模型)。

Self-Training Models

自学习模型的基本假设是,分类器对样本进行预测时,置信度高的样本被正确分类的可能性大。比如SVM对某个样本进行分类时,离分类界面距离较远的那些样本可以认为被正确分类。那么基于这个假设,自学习模型就显得异常简单了。假设我有两堆数据A和B,其中A是已标注的数据,即带Label的;而B是未标注数据。Self-Training的做法如下:

  1. 从已标注数据A中训练一个分类模型M
  2. 用该模型对B进行预测
  3. 将预测结果中置信度高的K个样本,连同它们的Label加入训练数据A,并从B中删除
  4. 回到第1步。

当然,第3步可以有很多实现方法,比如可以将B中所有样本加入A,根据预测时置信度的不同给样本赋予不同的权重。

自学习模型是最简单也最易实现的半指导模型,但是简单的东西往往不怎么好用,这世上既简单又好用的东西实在不多。自学习的缺点在于,如果一个错误分类的样本被加入了原来的训练集,那么在其后的训练过程中,它所犯的错误只会越来越深,还会诱使其他样本犯错,这种outlier实在罪不容恕。而自学习模型对此表示无能为力。

Generative Models

判别模型与生成模型如何区分依然是大家争论的一个重点。推荐大家看看2009年NIPS的一个workshop:http://gen-disc2009.wikidot.com/。判别模型与生成模型的融合是我一直想做的一个课题,尽管已经在Parse Reranking上做过一些实验,但是总是觉得不深入,对两者的理解仍然不够深。

生成模型在半指导学习中的应用比较简单,我们经常遇到的高斯混合模型(GMM)就是一种典型的生成模型(当然,还有其他的混合密度分布,如混合多项式分布)。GMM总是和EM算法紧紧地捆绑在一起的。我们知道,如果在GMM中,每个样本属于哪个类别(高斯分布)是已知的话,那么很容易通过MLE对其进行参数估计。如果所有的样本都不知道类别,那么我们一般使用EM算法迭代地估计其参数。前者是有指导学习,后者是无指导学习。于是很容易想到第三种情况,即部分样本的类别已知,而剩余的样本类别未知。这时,只需要将似然函数的形式稍作改变即可用EM算法求之。

Cluster-then-Label

从前面的EM算法在半指导学习中的运用,可以很自然地想到,无指导方法一般都可以用于半指导学习。K-Means是EM算法的一种简单形式,那么能否将聚类用于半指导学习呢?

Cluster-then-Label,顾名思义:先聚类,再分类。其算法如下:

  1. 对所有样本(包括已标注数据A和未标注数据B)进行聚类
  2. 对于聚类结果中的每个簇,执行第3、4步。令S为该簇中已标注的样本
  3. 如果S非空,那么在S上学习一个分类器,并对该簇中未标注的样本进行预测
  4. 如果S为空,那么根据所有已标注的数据来预测该簇中未标注的样本

这样,我们就得到的所有样本的类别。想法非常简单,但是究竟效果好不好还有待实验进行验证。

Co-Training

第一次接触Co-Training这个词是在大三的时候,那时对机器学习几乎没有什么概念,脑海里只充满了对人工智能各种各样的幻想。那时对Co-Training的理解是:有两个Robots,能够相互Teaching,相互Learning。听起来很高深的样子,呵呵。后来证明真实的Co-Training也与之差相仿佛了。

Co-Training又叫协同训练或协同学习,是一种MultiView算法。Multiview是指认识事物的多个角度。比如对于“月亮”,我们会在脑海里浮现出一轮飞镜似的明月,或圆或缺,或明或暗,我们甚至还会联想到古代词人吟风弄月的很多佳句。当然也有人会立刻联想到月亮的各种特征,比如它是地球的卫星,它的表面有环形山,它绕地运行……等等一系列特征。这便是看待同一件事物的两个角度。那么从不同的角度看待训练数据,我们能够得到不同的特征空间。而在不同的特征空间中,我们又能够得到不同的分类模型。这就是Co-Training的基本思想。

协同训练的过程如下:假设数据有两种特征表达,比如图像特征(X-1, Y-1)和文本特征(X-2, Y-2)。对于未标注数据同样有两种View。算法如下:

  1. 从(X-1, Y-1),(X-2, Y-2)分别训练得到两个个分类模型F-1,F-2
  2. 分别使用F-1与F-2对未标注数据进行预测
  3. 将F-1所预测的前K个置信度最高的样本加入F-2的训练数据集
  4. 将F-2所预测的前K个置信度最高的样本加入F-1的训练数据集
  5. 回到第1步

基本的Co-Training算法还是很简单的。如何将其应用到NLP的Task里又有很多研究点。我觉得从Co-Training的思想出发可以稍微帮助理解一下人工智能。一直以为人工智能一定是群体作用的结果,一个封闭的自学习系统是很难激发出智能的,除非本身拥有一个非常强大的知识集和归纳、演绎系统。一个智能体,在幼儿时主要依靠专家指导(我们的父母亲人)来强化自身的学习系统(人脑神经网络),在学习系统成长的过程中,我们也在不断地和我们的同伴相互对比,相互学习。在这不断地碰撞和启发中,我们才渐渐地拥有了知识和对事物准确的判断力。人的这种获取智能的方式应该是值得机器学习方法所借鉴的。或许有一天,我们真的能够模拟人脑的思维,而不再仅仅是模拟人类的行为。

Categories: Machine Learning | Tags: , , , , , | 12 Comments

漫谈有指导学习之判别模型

        前些天,有人问我机器学习与模式识别有何区别?当时很模糊地回答了一下。这两天重新翻了一下Vapnik的统计学习理论本质,终于有了比较清晰的理解。统计机器学习有三大类问题,分别是模式识别、回归分析以及密度估计。在NLP领域,模式识别无疑是应用最广泛的学习问题。可以这样认为,模式识别旨在解决应用层问题,比如分类,目的只是为了正确分类样本,至于采用的是何种模型(最大熵,SVM,GDA……),这些模型是否反应真实数据分布是它所不关心的。而回归分析旨在刻画数据分布,以数据拟合为例,我们力求找到一条符合样本点的期望曲线,来拟合已有的数据。相对于模式识别而言,回归则更加能反应数据的本质。密度估计则在回归的基础上又深了一层,大部分密度估计都被转化为参数估计问题,比如混合高斯分布(GMM),具体密度函数形式一般由先验或者启发信息给出,这通常被称为归纳偏置。就目前而言,模式识别和回归分析问题在应用中使用有指导的方法居多,而在密度估计问题中,无指导方法使用得更多,最常用的莫过于EM算法了。

         刚刚听完Andrew Ng教授的开放课程前几讲,收获颇丰,因而想写一个系列式的总结。本篇将从回归以及分类的角度来总结一下判别方法(Discriminative Algorithms)。

         很多人搞不清楚判别模型(Discriminative Model)与生成模型(Generative Model)的区别与联系。谈一下我的理解:判别模型是对似然概率P(x|y)进行建模,而生成模型是对后验概率,或者联合概率进行建模。“生成”二字大有深意。因此,像最小二乘法(Least Squares),Logistic Regression等算法属于判别方法,而朴素贝叶斯(Naïve Bayes),HMM等则是生成模型。

线性回归

         问题定义很简单:给定一系列样本点(X, Y),其中X为特征向量,Y为目标预测值。回归的任务是要找到一个假设 Y=h(X) 来拟合这些样本点。如果h为关于X的一个线性函数,那么问题称为线性回归,如果h是一个sigmoid函数,则称为Logistic回归。Logistic回归的预测值在一个小区间内(标准的sigmoid函数,[0, 1]),利用这一特点,可将Logistic回归用于分类问题,将回归用于分类?这听起来似乎不可思议,其实想想分类的本质就清楚了。以二元分类为例,要判断一个实例属于A类还是B类,用统计学的方法可以计算出该实例属于A类的概率以及属于B类的概率,概率显然是[0, 1]的一个实数值,因此用Logistic回归就很自然了。

         为了解决回归问题,即找到一个合适的假设,我们一般的做法是定义如下的损失函数:

         这就是我们常常会用到的最小二乘法。优化该损失函数的方法有很多,用的比较多的是梯度下降,可有增量梯度下降(又叫随机梯度下降,stochastic gradient descent),以及批量梯度下降(batch gradient descent)。这和perceptron的两种训练方法类似。通常,随机梯度下降比批量梯度下降收敛更快,因此在实际应用中也用的更多。

         除了梯度下降,还可以用伪逆矩阵的方法来求解,这种方法非常直观,无需迭代,但是涉及到矩阵求逆,因此效率不高,对于大数据量的情况下不合适。

         那么,最小二乘法为什么是判别模型?它又是如何对似然概率进行建模呢?(终于讲到重点了…)

最小二乘法与最大似然估计

         首先做两点很自然的假设:1、数据中存在噪声;2、我们永远无法将所有特征encode到模型中。因此,一个样本点的期望预测值与实际值之间是有误差的,即:

         现在,给出第三个假设,之间独立同分布,并且服从均值为0的正态分布。即:

         那么很自然的会有:

        那么,似然函数的形式就呼之欲出了,最大化对数似然函数显然等价于最小化误差平方,即最小二乘法的损失函数。因此,最小二乘法是在正态分布假设之下对参数theta的最大似然估计。

 

局部加权线性回归

         局部加权线性回归(Locally Weighted Linear Regression)是一种思想类似K近邻的非参数回归方法。其实思路是如此的自然,观下图便知:

         我们不知道所有样本应该以一个什么函数去拟合,但是局部地看,我们很有理由相信,一个样本应该和与它离得最近的那些样本点有着相似的目标值。因此,我们在原来的损失函数的基础之上,增加了一个实例权重:

         权重的选择当然是距离相关的,距离越近的实例,权重越高,离的远的实例,权重较低,甚至可以为零。类似KNN,这里的距离可以是欧氏距,也可以是街市距,马氏距。

         这种方法之所以是非参数方法,是因为每次作预测时都要重新计算参数值,因而从始自终都要依赖所有的训练样本。

分类以及Logistic回归

         前面我们提到,可以将Logistic回归用于分类,下面仔细来看一下具体如何操作。

         假设在给定参数的前提下,实例分别属于类1和类0(这里使用0和1表示两个类别)的概率为:

         考虑到概率的区间范围,我们令h为sigmoid函数。sigmoid函数以其非常特殊而优美的导数性质,而成为模式识别中非常常用的一种函数形式。在BP神经网络中更是大展鸿图。对其不熟的读者可以阅读相关文档和书籍。有了上面的概率假设,于是:

        有了这个式子,就可以对theta进行最大似然估计了。

         取对数再求导可以得到(具体求导过程这里再不给出):

         这个式子真是太熟悉了!假如h不是sigmoid函数而是符号函数,那么这就不就是Perceptron么?可见,基于Logistic回归的分类是在伯努利(Bernoulli)分布假设下的最大似然估计。

         以上是二元分类的情况,其实扩展到多元分类也不难,只是运算比较复杂。这时候就不能只用一个实数值来表示属于某一类的概率了,而要使用向量。可以借鉴一下BP神经网络的原理,每一个输出神经元的值即为属于某一类别的概率。这里不再推导了。

         事实上,在最大似然估计的框架之上,还有一个更大的框架,称为:Generalized Learning Machine(GLM)。这个框架建立在指数函数家族(Exponential Family)的基础之上,可以将以上所讨论的最小二乘法,Logistic回归分类都涵盖进去。

         行文至此,似乎可以结束了,也许会有人问,那SVM属于判别模型还是生成模型呢?SVM的推导过程中既没有似然概率也没有后验概率啊。我认为把它归为任一类都不合适,SVM实际上是在基于VC维理论的一个更大框架之下的模型,事实上,SVM本身就是一个框架,它也是我目前认为最优美的模型。

Categories: Machine Learning | Tags: , , , , , , , , , | 3 Comments

使用Google Web 1T 5-gram

最近的工作用到了Google的海量语言模型,因其海量,使用它时远没有想像当中那么简单。经过一周时间的探索,总算找到一种较为合理的方法,记录一下:-)

Google语言模型的一些基本情况和背景可以参考52nlp上的这篇介绍,以及LDC上的介绍Web 1T 5-gram Version 1
压缩的语言模型(1-5 gram)大小为24G,完全解压之后应该就是1T了。这么大的语言模型,无论是模型的训练(Google提供的是n-gram的计数文件)还是加载过程,几乎都不现实,我一想就头疼。对于一般用户而言,这么大的语言资源的确是收藏意义大于使用。

关于模型的训练
首先纠结的问题是要不要对其进行训练。用过SRILM的人都知道,SRILM可以将训练过程分割成两部分,先从Corpus生成计数文件,也就是Google所提供给我们的形式;再根据计数文件训练Language Model。而且一旦有了Model,就能很好很方便地满足我计算句子概率的需求,SRILM提供这样的接口。
可是最终我还是放弃了,心想如果只用到bigram或许还现实一点,更高阶的我心里没底,至少训练时间会很漫长,而且内存是最大的障碍,这道障碍,似乎无法逾越。值得一提的是:SRILM的FAQ中提供了一种针对google ngram的训练方法,读者不妨尝试一下:http://www-speech.sri.com/projects/srilm/manpages/srilm-faq.7.html (B6)
既然选择不训练语言模型,那么数据平滑以及概率、困惑度计算的工作就需要自己来完成了。这也并非难事,只要有ngram的频率信息,什么事情都好办。

如何有效地索引数据
一开始借鉴康维鹏师兄的方法,尝试使用Lucene对其进行索引。方法是将每个(ngram, count)作为一个Document。试验了unigram和bigram,效果还不错。只是处理起来比较麻烦,由于索引文件比源文件大30%左右,需要人为地将索引文件分成多个,Search时根据ngram的区间来确定读取哪个索引文件。缺点显而易见,比如对于2-gram和3-gram,这种方法重复存储了太多的内容。不过也不失为一种方法。

那能不能使用数据库呢?顺着这个思路我找到了Web1T5-Easy,也就是我现在所用的方法。Web1T5-Easy是一个德国人Stefan Evert用Perl写的将Google Web 1T ngram导入SQLite的工具包。试用了一下,还是非常不错的。下载地址

使用前需要安装DBI、DBD-SQLite,对版本要求比较严格。
使用的一些细节,比如如何建库,如何查询等等,在README里写的很详细。下面简述一下过程:

第一步,创建词表。

  • perl perl/mk_vocab_db.perl –normalize 1gram/vocab.gz vocabulary.dat

normalize选项负责将所有字符串转换成小写,同时,将数字存储为“NUM”,标点符号存储为“PUN”,一些未知由“UNK”表示。这样做能一定程度上减少存储空间。另外,在创建词表的过程中,将每个词映射到一个整型的id,在之后的ngram数据表中就可以用id来表示,这也是一种非常简单有效的压缩手段。

第二步就是基于创建好的词表构建ngram数据库了。

  • perl perl/mk_ngram_db.perl –normalize –temp=${TMPDIR} 1 1-grams.dat vocabulary.dat
  • perl perl/mk_ngram_db.perl –normalize –temp=${TMPDIR} 2 2-grams.dat vocabulary.dat ${WEB1T5}/2gms/*.gz
  • perl perl/mk_ngram_db.perl –normalize –temp=${TMPDIR} 3 3-grams.dat vocabulary.dat ${WEB1T5}/3gms/*.gz
  • ……

目前暂时用到3-gram,在2.67GHz,16G内存的服务器上跑,一共用了两天时间。其中normalize过程占用了大部分的时间。

工具包中同时提供查询脚本,可以方便地进行精确及模糊查找,以及简单的正则表达式查找。不过一旦使用正则表达式或者模糊查找,速度将急剧减缓。

另外,Web1T5-Easy还提供一个简单的Web-Service,也非常不错。

Categories: Language Model | Tags: , , , , | 4 Comments

LTP正式开放源代码

经过近两周的努力,终于赶在今天这个天真烂漫的节日完成了LTP的开源工作。昨天与车老师聊天时才知道,LTP是实验室各位前辈历时十年才开发‘完成’的,当真是十年磨一剑。如果说之前的目标代码共享以及WebService访问方式让江湖中从此有了这把剑的传说,那么这次的开源,便是真正的亮剑。

这一次开源引起的反响还是挺大的,远胜我内心的波澜不惊。第一天就收到很多申请共享的邮件,从邮件行文的字里行间可以体会到用户对于开源的的热心支持。希望会有越来越多的人能加入到开源的队伍中来,至少在NLP界。我曾经有一个设想,如果人类总能够完美地继承前人的智慧以及成果,那么文明的发展是否会更加顺利而且迅速。至少,不会出现历史上明清交替时的文化断层。想秦皇再燓几次儒家经典,五胡再乱我中华,也不怕文化自此遗失。开源正是一种好的继承和发展方式。

诚然,LTP的源代码远非完美,不过这也正是开源的意义之一。因此希望各位同行在使用LTP或者阅读LTP源码时多多指教。

以下新闻引自:http://ir.hit.edu.cn/phpwebsite/index.php?module=announce&ANN_user_op=view&ANN_id=361

语言技术平台(Language Technology Platform,LTP)是哈工大社会计算与信息检索研究中心历时十年开发的一整套中文语言处理系统。LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic Link Library, DLL)的应用程序接口,可视化工具,依存树库等语料资源,并且能够以网络服务(Web Service)的形式进行使用。

从2006年9月5日开始该平台对外免费共享目标代码,截止目前,已经有国内外400多家研究单位共享了LTP,也有国内外多家商业公司购买了LTP,用于实际的商业项目中。2010年12月获得中国中文信息学会颁发的行业最高奖项:”钱伟长中文信息处理科学技术奖”一等奖。

2011年6月1日,为了与业界同行共同研究和开发中文信息处理核心技术,我中心正式将LTP的源代码对外共享,LTP由C++语言开发,可运行于Windows和Linux操作系统。详见:http://ir.hit.edu.cn/ltp/

欢迎各界朋友共享!

Categories: NLP | Tags: , , , , | 2 Comments