您的位置:首页 > 其它

自动文本分类

2013-10-09 20:32 218 查看


文本自动分类

分类: 文本挖掘 自然语言处理 数据挖掘 机器学习2013-10-04
19:05 197人阅读 评论(5) 收藏 举报

使用机器学习方法 做文档的自动分类

套路:

1.根据每个文件 生成该文件的一个特征

2.根据特征 选择 分类器 进行文本分类

3.(可选)根据 2 步结果,调整参数/特征等

示例:

数据:搜狗文本分类语料库 精简版

分类器:朴素贝叶斯

编程语言:Python+nltk自然语言处理库+jieba分词库

[python] view
plaincopy

__author__ = 'LiFeiteng'

# -*- coding: utf-8 -*-

import os

import jieba

import nltk

## 由搜狗语料库 生成数据

folder_path = 'C:\LIFEITENG\SogouC.reduced\\Reduced'

#folder_path = 'C:\LIFEITENG\SogouC.mini\Sample'

folder_list = os.listdir(folder_path)

class_list = [] ##由于乱码等问题 仅以数字[0,1,...]来代表文件分类

nClass = 0

N = 100 #每类文件 最多取 100 个样本 70%train 30%test

train_set = []

test_set = []

all_words = {}

import time

process_times = [] ## 统计处理每个文件的时间

for i in range(len(folder_list)):

new_folder_path = folder_path + '\\' + folder_list[i]

files = os.listdir(new_folder_path)

class_list.append(nClass)

nClass += 1

j = 0

nFile = min([len(files), N])

for file in files:

if j > N:

break

starttime = time.clock()

fobj = open(new_folder_path+'\\'+file, 'r')

raw = fobj.read()

word_cut = jieba.cut(raw, cut_all=False)

word_list = list(word_cut)

for word in word_list:

if word in all_words.keys():

all_words[word] += 1

else:

all_words[word] = 0

if j > 0.3 * nFile:

train_set.append((word_list, class_list[i]))

else:

test_set.append((word_list, class_list[i]))

j += 1

endtime = time.clock()

process_times.append(endtime-starttime)

print "Folder ",i,"-file-",j, "all_words length = ", len(all_words.keys()),\

"process time:",(endtime-starttime)

print len(all_words)

## 根据word的词频排序

all_words_list = sorted(all_words.items(), key=lambda e:e[1], reverse=True)

word_features = []

## 由于乱码的问题,没有正确使用 stopwords;简单去掉 前100个高频项

## word_features 是选用的 word-词典

for t in range(100, 1100, 1):

word_features.append(all_words_list[t][0])

def document_features(document):

document_words = set(document)

features = {}

for word in word_features: ## 根据词典生成 每个document的feature True or False

features['contains(%s)' % word] = (word in document_words)

return features

## 根据每个document 分词生成的 word_list 生成 feature

train_data = [(document_features(d), c) for (d,c) in train_set]

test_data = [(document_features(d), c) for (d,c) in test_set]

print "train number:",len(train_data),"\n test number:",len(test_data)

## 朴素贝叶斯分类器

classifier = nltk.NaiveBayesClassifier.train(train_data)

print "test accuracy:",nltk.classify.accuracy(classifier, test_data)

## 处理每个文件所用的时间 可见到后面 处理单个文件的时间显著增长

## 原因 已查明

import pylab

pylab.plot(range(len(process_times)), process_times, 'b.')

pylab.show()

test上的正确率: 9个类别 74%



处理每个文件所用时间:



===============================

朴素贝叶斯:From 《数据挖掘概念与技术》



1.中文乱码问题,由于这个问题,在stopwords上简单去掉 前100个高频项 数据清洗不足

2.字典的选择上——简单以统计 所有文件词频,选用101-1100 1000个词作字典

我觉得 字典完全可以从 数据上 学习(要比上面方法高明些),就像在图像处理中 稀疏模型 学习字典(KSVD)一样

自然语言处理/文本处理 中也应该存在这样的方法

3.文件的特征 是[0,0,1,0,0,1,...]并不是统计每个文件的词频,

这跟选择的分类器相关,如果选择svm等 就要对文件 生成词频特征

4.到后面(见上图),单个文件处理时间显著增长,原因待查明——已查明 if
word in all_words.keys(): 改为all_words.has_key(word)

以 机器学习 的小无相功 打了一套 自然语言处理/文本挖掘 的招数

难免有些生硬 望专家指点


文本自动分类(续)

分类: 文本挖掘 数据挖掘 机器学习2013-10-09
19:02 76人阅读 评论(0) 收藏 举报

文本自动分类

关于单个文本处理时间显著增长的讨论

今天下午

使用了 stopwords 从网上搜了下 中文停用词

并解决了 Python 中文显示/输入输出的问题 line.decode('gbk')

[python] view
plaincopy

__author__ = 'LiFeiteng'

# -*- coding: utf-8 -*-

import os

import jieba

import nltk

## 由搜狗语料库 生成数据

folder_path = 'C:\LIFEITENG\SogouC.reduced\\Reduced'

#folder_path = 'C:\LIFEITENG\SogouC.mini\Sample'

folder_list = os.listdir(folder_path)

class_list = [] ##由于乱码等问题 仅以数字[0,1,...]来代表文件分类

nClass = 0

N = 100 #每类文件 最多取 50 个样本 70%train 30%test

train_set = []

test_set = []

all_words = {}

import time

process_times = [] ## 统计处理每个文件的时间

for i in range(len(folder_list)):

new_folder_path = folder_path + '\\' + folder_list[i]

files = os.listdir(new_folder_path)

class_list.append(nClass)

nClass += 1

j = 0

nFile = min([len(files), N])

for file in files:

if j > N:

break

starttime = time.clock()

fobj = open(new_folder_path+'\\'+file, 'r')

raw = fobj.read()

word_cut = jieba.cut(raw, cut_all=False)

word_list = list(word_cut)

for word in word_list:

if all_words.has_key(word):#if word in all_words.keys():

all_words[word] += 1

else:

all_words[word] = 0

if j > 0.3 * nFile:

train_set.append((word_list, class_list[i]))

else:

test_set.append((word_list, class_list[i]))

fobj.close()

j += 1

endtime = time.clock()

process_times.append(endtime-starttime)

print "Folder ",i,"-file-",j, "all_words length = ", len(all_words.keys()),\

"process time:",(endtime-starttime)

## 根据word的词频排序

all_words_list = sorted(all_words.items(), key=lambda e:e[1], reverse=True)

## 由于乱码的问题,没有正确使用 stopwords;简单去掉 前100个高频项

## word_features 是选用的 word-词典

stopwords_file = open('stopwords_cn.txt', 'r')

stopwords_list = []

for line in stopwords_file.readlines():

#print line.decode('gbk')

stopwords_list.append(line.decode('gbk')[:-2])

#print stopwords_list

def words_dict_no_use_stopwords(deleteN):

#dict_name = "dict_"+str(deleteN)+".txt"

#dict = open(dict_name, 'w')

n = 0

word_features = []

for t in range(deleteN, len(all_words), 1):

if n > 1000:

break

#print all_words_list[t][0]

#dict.writelines(str(all_words_list[t][0]))

#dict.writelines(' ')

n += 1

word_features.append(all_words_list[t][0])

return word_features

#dict.close()

def words_dict_use_stopwords(deleteN):

#dict_name = "dict_stopwords_"+str(deleteN)+".txt"

#dict = open(dict_name, 'w')

n = 0

word_features = []

for t in range(deleteN, len(all_words), 1):

if n > 1000:

break

#print all_words_list[t][0]

if all_words_list[t][0] not in stopwords_list and (not all_words_list[t][0].isdigit()):

#dict.writelines(str(all_words_list[t][0]))

#dict.writelines(' ')

n += 1

word_features.append(all_words_list[t][0])

return word_features

#dict.close()

def document_features(document):

document_words = set(document)

features = {}

for word in word_features: ## 根据词典生成 每个document的feature True or False

features['contains(%s)' % word] = (word in document_words)

return features

def TextClassification():

## 根据每个document 分词生成的 word_list 生成 feature

train_data = [(document_features(d), c) for (d,c) in train_set]

test_data = [(document_features(d), c) for (d,c) in test_set]

print "train number:",len(train_data),"\n test number:",len(test_data)

## 朴素贝叶斯分类器

classifier = nltk.NaiveBayesClassifier.train(train_data)

test_error = nltk.classify.accuracy(classifier, test_data)

print "test accuracy:", test_error

return test_error

deleteNs = range(0, 1000, 20)

test_errors_no_use = []

test_errors_use = []

for n in deleteNs:

word_features = words_dict_no_use_stopwords(n)

test_error = TextClassification()

test_errors_no_use.append(test_error)

word_features = words_dict_use_stopwords(n)

test_error = TextClassification()

test_errors_use.append(test_error)

## 处理每个文件所用的时间 可见到后面 处理单个文件的时间显著增长

## 原因 已查明

import pylab

plot1 = pylab.plot(deleteNs, test_errors_no_use)

plot2 = pylab.plot(deleteNs, test_errors_use)

pylab.legend(('no use stopwords', 'using stopwords'), 'best')

#pylab.xlabel("no using stopwords")

pylab.show()

对数据的处理:

由于没有事先的词典dict

我的处理方法是:把所有文档的分词结果放到一个 dictionary里面,然后根据词频从高到低 排序

由于处理每个文档的时候,就没有去除一些杂乱信息,比如标点符号,无意义的数字等

所以 在试验中 构造最终词典(固定选取1000个词)的时候 逐渐去除词典的部分高频项,观察正确率的变化



(图像:纵轴代表分类9个文档的正确率,横轴-去除高频项的个数(0::20::1000),绿线-使用停用词的正确率)

从测试准确率图像中可以看到此举 在初期还是有显著效果的 当去除更多高频词汇的数据时 正确率又会显著下降

这跟理论分析是符合的——应该观察排序后的字典,深入到数据中去

同时也可看到 使用停用词 在前半段 争取率有不错的提升

==========================================================

1.应该在 处理每个文本的时候 应该去除一些杂乱信息 减少内存占用等

2.如果在事先有 词典的情况下 可以直接提取文本特征

3.没有词典的时候, 程序员应该自己 构造词典 甚至在大量样本中 学习词典

4.特征维数的选取 在本文中固定 1000 维,可以做做 正确率关于维数的变化

5.特别说明:因为 分类器用的是 朴素贝叶斯 所以文本特征是 [TRUE, FALSE, ...] 文本是否包含字典中词的判别

p(feature_i | C_k) = ... 见文本自动分类 贝叶斯介绍部分

如果是使用 SVM softmax等 那么特征应该是 词频 或者 TDIDF等
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: