基于KNN的文本分类实战

标签: 机器学习 | 发表时间:2015-04-03 10:39 | 作者:
出处:http://www.letiantian.me/

2015-04-03

本文讲述如何使用scikit-learn的KNN工具对文本进行分类。

关于KNN


K-近邻算法,简称KNN(k-Nearest Neighbor),是一个相当简单的分类/预测算法。其主要思想就是,选取与待分类/预测数据的最相似的K个训练数据,通过对这K个数据的结果或者分类标号取平均、取众数等方法得到待分类/预测数据的结果或者分类标号。

关于KNN,笔者在 浅入浅出:K近邻算法有较为详细的介绍。

数据集介绍


数据集是有8个分类的文本数据集,使用了结巴分词对每个文本分词,每个单词当作特征,再利用二元词串构造更多特征,然后去掉停用词,去掉出现次数太多和太少的特征,得到了19630个特征。取1998个样本用于训练,509个用于测试。基于词袋模型的思路将每个文本转换为向量,训练集和测试集分别转换为矩阵,并用python numpy模块将其保存为npy格式。

https://github.com/letiantian/dataset 下载text-classification.7z,解压后导入数据:

  $ ls
test_data.npy  test_labels.npy  training_data.npy  training_labels.npy  
$ ipython
>>> import numpy as np
>>> training_data = np.load("training_data.npy")
>>> training_data.shape
(1998, 19630)
>>> training_labels = np.load("training_labels.npy")
>>> training_labels
array([6, 6, 6, ..., 2, 2, 2])  
>>> training_labels.shape
(1998,)
>>> test_data = np.load("test_data.npy")
>>> test_data.shape
(509, 19630)
>>> test_labels = np.load("test_labels.npy")
>>> test_labels.shape
(509,)

如何找一样本的最近k个邻居


方法1:

  >>> from sklearn.neighbors import NearestNeighbors
>>> nbrs = NearestNeighbors(n_neighbors=6, algorithm='ball_tree')
>>> nbrs.fit(training_data)  # 构造BallTree,可以快速找出6个最近邻居,原理待学习
NearestNeighbors(algorithm='ball_tree', leaf_size=30, metric='minkowski',
         metric_params=None, n_neighbors=6, p=2, radius=1.0)
>>> distances, indices = nbrs.kneighbors(test_data[0])  # 找training_data中离样本test_data[0]的最近的6个样本
>>> indices  # 6个最近样本,每个值是指在training_data中的第几个样本
array([[500, 294,  62, 802, 732, 703]])
>>> distances  # 对应的距离
array([[ 13.37908816,  13.60147051,  13.60147051,  13.60147051,
         13.60147051,  13.6381817 ]])

也可以依次找出多个测试样本的最近的6个训练样本:

  >>> distances, indices = nbrs.kneighbors(test_data[0:2])
>>> indices
array([[ 500,  294,   62,  802,  732,  703],
       [  62,  294,  636, 1945,  802, 1091]])
>>> distances
array([[ 13.37908816,  13.60147051,  13.60147051,  13.60147051,
         13.60147051,  13.6381817 ],
       [  7.93725393,   7.93725393,   8.1240384 ,   8.36660027,
          8.54400375,   8.54400375]])

方法2:

  >>> from sklearn.neighbors import BallTree
>>> bt = BallTree(training_data, metric='euclidean')
>>> distances, indices = bt.query(test_data[0], k=6)                  
>>> indices
array([[500,  62, 802, 294, 732, 703]])
>>> distances
array([[ 13.37908816,  13.60147051,  13.60147051,  13.60147051,
         13.60147051,  13.6381817 ]])

基于KNN的文本分类


令k=6:

  >>> from sklearn.neighbors import KNeighborsClassifier
>>> knn = KNeighborsClassifier(n_neighbors=6, metric='euclidean')
>>> knn.fit(training_data, training_labels) # 训练
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='euclidean',
           metric_params=None, n_neighbors=6, p=2, weights='uniform')
>>> predict_labels = knn.predict(test_data) # 预测
>>> sum(predict_labels == test_labels)
230
>>> 230./509  # 正确率
0.4518664047151277

令k=20:

  >>> from sklearn.neighbors import KNeighborsClassifier
>>> knn = KNeighborsClassifier(n_neighbors=20, metric='euclidean')
>>> knn.fit(training_data, training_labels) # 训练
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='euclidean',
           metric_params=None, n_neighbors=20, p=2, weights='uniform')
>>> predict_labels = knn.predict(test_data) # 预测
>>> sum(predict_labels == test_labels)
276  # 效果比k=6时提升了一些
>>> 276./509   # 正确率
0.5422396856581533

这个正确率并不高。在 基于贝叶斯的文本分类实战中笔者使用了多项式贝叶斯对同样的数据集进行分类,正确率达到近90%。

做个优化


我们将每个样本归一化,看看效果。

先写一个归一化工具(mytools.py):

  # !/usr/bin/env python
# -*- encoding:utf-8 -*-

import numpy as np

def uniformization(X):
    if X.ndim != 2:
        return None
    X2 = X.copy()
    X2 = X2.astype(float)
    rows = X2.shape[0]
    for i in xrange(0, rows):
        sum_of_squares = sum(X2[i, :]**2)
        if sum_of_squares == 0: continue
        sqrt_sum_of_squares = sum_of_squares**0.5
        X2[i, :] = X2[i, :] / sqrt_sum_of_squares
    return X2 

if __name__ == '__main__':
    arr = np.array([[1,2,3],[4,5,6],[0,0,0]])
    print uniformization(arr)

运行结果如下:

  [[ 0.26726124  0.53452248  0.80178373]
 [ 0.45584231  0.56980288  0.68376346]
 [ 0.          0.          0.

处理原始数据集,生成新的数据:

  >>> from mytools import uniformization
>>> new_training_data = uniformization(training_data)
>>> new_test_data = uniformization(test_data)

令k=6:

  >>> knn = KNeighborsClassifier(n_neighbors=6, metric='euclidean')
>>> knn.fit(new_training_data, training_labels) # 使用新数据训练
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='euclidean',
           metric_params=None, n_neighbors=6, p=2, weights='uniform')
>>> predict_labels = knn.predict(new_test_data) # 预测
>>> sum(predict_labels == test_labels)
294  # 由230提升到294
>>> 294./509  # 正确率有提升
0.5776031434184676

令k=20:

  >>> from sklearn.neighbors import KNeighborsClassifier
>>> knn = KNeighborsClassifier(n_neighbors=20, metric='euclidean')
>>> knn.fit(new_training_data, training_labels)  # 使用新数据训练
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='euclidean',
           metric_params=None, n_neighbors=20, p=2, weights='uniform')
>>> predict_labels = knn.predict(new_test_data)  # 预测
>>> sum(predict_labels == test_labels)
314  # 由276提升到314
>>> 314./509  # 正确率有提升
0.6168958742632613

可以看到,归一化后,预测分类的正确率提升很多。

参考


1.6. Nearest Neighbors
sklearn.neighbors.KNeighborsClassifier

(完)

相关 [knn 文本 分类] 推荐:

基于KNN的文本分类实战

- - 樂天笔记
本文讲述如何使用scikit-learn的KNN工具对文本进行分类. K-近邻算法,简称KNN(k-Nearest Neighbor),是一个相当简单的分类/预测算法. 其主要思想就是,选取与待分类/预测数据的最相似的K个训练数据,通过对这K个数据的结果或者分类标号取平均、取众数等方法得到待分类/预测数据的结果或者分类标号.

数据挖掘-基于贝叶斯算法及KNN算法的newsgroup18828文档分类器的JAVA实现(上)

- - CSDN博客推荐文章
本文主要研究基于贝叶斯算法及KNN算法的newsgroup18828文档分类器的设计及实现,数据预处理、贝叶斯算法及KNN算法实现工程源码下载见:. 对newsgroup文档集进行预处理,提取出30095 个特征词. 计算每篇文档中的特征词的TF*IDF值,实现文档向量化,在KNN算法中使用. 用JAVA实现了KNN算法及朴素贝叶斯算法的newsgroup文本分类器.

LibShortText - 短文本分类

- - 互联网旁观者
Chih-Jen Lin的新作.   青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟.

用scipy(scikit-learn)做文本分类

- - CSDN博客研发管理推荐文章
文本挖掘的paper没找到统一的benchmark,只好自己跑程序,走过路过的前辈如果知道20newsgroups或者其它好用的公共数据集的分类(最好要所有类分类结果,全部或取部分特征无所谓)麻烦留言告知下现在的benchmark,万谢. 20newsgroups官网上给出了3个数据集,这里我们用最原始的 20news-19997.tar.gz.

python 中文文本分类 - CSDN博客

- -
3,结构化表示--构建词向量空间. 即已经分好类的文本资料(例如:语料库里是一系列txt文章,这些文章按照主题归入到不同分类的目录中,如 .\art\21.txt). 推荐语料库:复旦中文文本分类语料库,下载链接:http://download.csdn.net/detail/github_36326955/9747927.

[转]Tensorflow实现的CNN文本分类

- - Soul Joy Hub
在这篇文章中,我们将实现一个类似于Kim Yoon的卷积神经网络语句分类的模型. 本文提出的模型在一系列文本分类任务(如情感分析)中实现了良好的分类性能,并已成为新的文本分类架构的标准基准. 本文假设你已经熟悉了应用于NLP的卷积神经网络的基础知识. 如果没有,建议先阅读Understanding Convolutional Neural Networks for NLP 以获得必要的背景.

文本分析漫谈-分类器中的关键词提取

- flychen50 - UGC广播站
作者:人人网UGC团队成员 刘威 人人网UGC团队博客. 面对人人网海量的UGC,数据挖掘工作势在必行,能把用户最想要的信息推荐出来,是我们正在研究的课题之一. 在推荐系统中,分类器是个非常重要的部分. 分类器的研究重点落在两个方面,一方面是文本关键词的提取,一方面是对已有关键词或标签的文本进行训练分类.

[转载]基于贝叶斯算法的文本分类算法

- - 小蚊子乐园
原文地址: 基于贝叶斯算法的文本分类算法 作者: TBKKEN.     因为要做一个关于数据挖掘的算法应用PPT,虽然知道很多数据挖掘的算法怎么使用,但是需要讲解它们的原理,还真的需要耗费很多精力,之前做一个曲线拟合,已经发在博客里,现在做贝叶斯算法的基础原理. 分类是把一个事物分到某个类别中.

[转][转]Facebook 开源的快速文本分类器 FastText

- - heiyeluren的blog(黑夜路人的开源世界)
比深度学习快几个数量级,详解Facebook最新开源工具——fastText. 导读:Facebook声称fastText比其他学习方法要快得多,能够训练模型“在使用标准多核CPU的情况下10分钟内处理超过10亿个词汇”,特别是与深度模型对比,fastText能将训练时间由数天缩短到几秒钟. Facebook FAIR实验室在最新博客中宣布将开源资料库fastText,声称相比深度模型,fastText能将训练时间由数天缩短到几秒钟.

自然语言处理第一番之文本分类器

- - 小石头的码疯窝
文本分类应该是自然语言处理中最普遍的一个应用,例如文章自动分类、邮件自动分类、垃圾邮件识别、用户情感分类等等,在生活中有很多例子,这篇文章主要从传统和深度学习两块来解释下我们如何做一个文本分类器. 传统的文本方法的主要流程是人工设计一些特征,从原始文档中提取特征,然后指定分类器如LR、SVM,训练模型对文章进行分类,比较经典的特征提取方法如频次法、tf-idf、互信息方法、N-Gram.