转自:http://blog.csdn.net/liuchonge/article/details/72614524

这几周因为在做竞赛所以没怎么看论文刷题写博客,今天抽时间把竞赛用到的东西总结一下。先试水了一个很小众的比赛–文因互联,由AI100举办,参赛队不足20个,赛题类型是文本分类。选择参赛的主要原因是其不像阿里们举办的竞赛那样,分分钟就干一件事就是特征工程和调参,然后数据又多又乱,不适合入门。其次一个原因就是目前我的研究方向就是NLP,之前也做过一个文本分类的东西,所以就参赛了。这里将主要介绍我在比赛中用到的几个模型,从理论到代码实现进行总结,代码我也放在了我的github中。

1,数据集

大家可以到竞赛官网查看赛题并下载数据集,数据集中主要包含下面几个文件,可见数据集很小也很简单,只需要使用training.csv文件进行训练我们的文本分类模型,使用testing.csv进行预测并提交结果即可: 

下面是训练集的前两行,每一行的第一个数字表示该行文本的类别,后面的描述就是要建模的文本。这个数据集是11个公司的描述数据,我们要根据4774条训练数据去预测2381条数据的类别标签。除此之外,我们还可以看到这些训练数据存在较严重的类别不平衡问题。如下图所示: 

2,合晟资产是一家专注于股票、债券等二级市场投资,为合格投资者提供专业资产管理服务的企业。公司业务范围包括资产管理、投资咨询和投资顾问服务。公司管理的私募基金产品主要包括股票型、债券型资产管理计划或证券投资基金,管理总资产规模80亿元左右。根据中国证券投资基金业协会数据,公司管理的私募证券投资基金(顾问管理)类规模较大,公司管理规模处于50亿元以上的第一梯队。
2,公司的主营业务为向中小微企业、个体工商户、农户等客户提供贷款服务,自设立以来主营业务未发生过变化。

了解完数据集,接下来我们开始进行文本分类,开始提交结果。

2, 朴素贝叶斯分类法

在这里插句题外话,往往这种竞赛大家喜欢一上来什么都不做先提交一个结果站站场面==也就是提交一个随机结果、均值等。因为我看到这个比赛的时候都已经快结束了,比较匆忙,所以第一次提交的也是直接用随机数生成的,后来还自作多情的按照训练集的类比占比作为每个类别概率生成随机数(结果显示确实有提高),代码如下所示2333:

import numpy as npwith open('output/random_out.csv', 'w') as f:for i in range(1, 2382):f.write(str(i))f.write(',')aa = np.random.random()b = 0if aa <= 0.25:b = 3elif aa <= 0.5:b = 4elif aa <= 0.7:b =6elif aa <= 0.775:b=7elif aa <= 0.825:b = 5elif aa <= 0.875:b = 8elif aa <= 0.925:b = 10elif aa <= 0.95:b = 11elif aa <= 0.975:b = 2elif aa <= 1:b = 9f.write(str(b))f.write('\n')

好,接下来说正经的,我用的第一种方法就是朴素贝叶斯,可以参见我之前的一篇博客,介绍了使用CHI选择特征,TFIDF计算特征权重,朴素贝叶斯分类的整体流程。因为之前做了这样的尝试,所以这里直接套过来看看效果如何,代码入下,这里的代码都是自己实现的,太丑,其实可以直接调用gensim的接口去做,以后有时间改改代码:

N=4774
# 读取停词表
def stop_words():stop_words_file = open('stop_words_ch.txt', 'r')stopwords_list = []for line in stop_words_file.readlines():stopwords_list.append(line.decode('gbk')[:-1])return stopwords_listdef jieba_fenci(raw, stopwords_list):# 使用结巴分词把文件进行切分word_list = list(jieba.cut(raw, cut_all=False))for word in word_list:if word in stopwords_list:word_list.remove(word)# word_set用于统计A[nClass]word_list.remove('\n')word_set = set(word_list)return word_list, word_setdef process_file(train_path, test_path):'''本函数用于处理样本集中的所有文件。并返回处理结果所得到的变量:param floder_path: 样本集路径:return: A:CHI公示中的A值,嵌套字典。用于记录某一类中包含单词t的文档总数。第一层总共9个key,对应9类新闻分类第二层则是某一类中所有单词及其包含该单词的文档数(而不是出现次数)。{{1:{‘hello’:8,‘hai’:7}},{2:{‘apple’:8}}}TFIDF:用于计算TFIDF权值。三层嵌套字典。第一层和A一样,key为类别。第二层的key为文件名(这里使用文件编号代替0-99).第三层key为单词,value为盖单词在本文件中出现的次数。用于记录每个单词在每个文件中出现的次数。train_set:训练样本集。与测试样本集按7:3比例分开。三元组(文档的单词表,类别,文件编号)test_set:测试样本集。三元组(文档的单词表,类别,文件编号)'''stopwords_list = stop_words()# 用于记录CHI公示中的A值A = {}tf = []i=0# 存储训练集/测试集count = [0]*11train_set = []test_set = []with open(train_path, 'r') as f:for line in f:tf.append({})label = int(line.split(',')[0])-1if label not in A:A[label] = {}count[label] += 1content = ""for aa in line.split(',')[1:]:content += aaword_list, word_set = jieba_fenci(content, stopwords_list)train_set.append((word_list, label))for word in word_set:if A[label].has_key(word):A[label][word] += 1else:A[label][word] = 1for word in word_list:if tf[i].has_key(word):tf[i][word] += 1else:tf[i][word] = 1i += 1print "处理完数据"tf2 = []j = 0with open(test_path, 'r') as g:for line in g:tf2.append({})label = int(line.split(',')[0])-1content = ""for aa in line.split(',')[1:]:content += aaword_list, word_set = jieba_fenci(content, stopwords_list)test_set.append((word_list, label))for word in word_list:if tf2[j].has_key(word):tf2[j][word] += 1else:tf2[j][word] = 1j += 1return A, tf, tf2, train_set, test_set, countdef calculate_B_from_A(A):''':param A: CHI公式中的A值:return: B,CHI公职中的B值。不是某一类但是也包含单词t的文档。'''B = {}for key in A:B[key] = {}for word in A[key]:B[key][word] = 0for kk in A:if kk != key and A[kk].has_key(word):B[key][word] += A[kk][word]return Bdef feature_select_use_new_CHI(A, B, count):'''根据A,B,C,D和CHI计算公式来计算所有单词的CHI值,以此作为特征选择的依据。CHI公式:chi = N*(AD-BC)^2/((A+C)*(B+D)*(A+B)*(C+D))其中N,(A+C),(B+D)都是常数可以省去。:param A::param B::return: 返回选择出的1000多维特征列表。'''word_dict = []word_features = []for i in range(0, 11):CHI = {}M = N - count[i]for word in A[i]:#print word, A[i][word], B[i][word]temp = (A[i][word] * (M - B[i][word]) - (count[i] - A[i][word]) * B[i][word]) ^ 2 / ((A[i][word] + B[i][word]) * (N - A[i][word] - B[i][word]))CHI[word] = log(N / (A[i][word] + B[i][word])) * temp#每一类新闻中只选出150个CHI最大的单词作为特征a = sorted(CHI.iteritems(), key=lambda t: t[1], reverse=True)[:100]b = []for aa in a:b.append(aa[0])word_dict.extend(b)for word in word_dict:if word not in word_features:word_features.append(word)return word_featuresdef document_features(word_features, TF, data, num):'''计算每一篇新闻的特征向量权重。即将文件从分词列表转化为分类器可以识别的特征向量输入。:param word_features::param TFIDF::param document: 分词列表。存储在train_set,test_set中:param cla: 类别:param num: 文件编号:return: 返回该文件的特征向量权重'''document_words = set(data)features = {}for i, word in enumerate(word_features):if word in document_words:features[word] = 1#TF[num][word]#*log(N/(A[cla][word]+B[cla][word]))else:features[word] = 0return featuresA, tf, tf2, train_set, test_set, count = process_file('data/training.csv', 'data/testing.csv')
B = calculate_B_from_A(A)
print "开始选择特征词"
word_features = feature_select_use_new_CHI(A, B, count)
#print word_features
print len(word_features)
for word in word_features:print wordprint "开始计算文档的特征向量"
documents_feature = [(document_features(word_features, tf, data[0], i), data[1])for i, data in enumerate(train_set)]print "测试集"
test_documents_feature = [document_features(word_features, tf2, data[0], i)for i, data in enumerate(test_set)]
#将我们处理之后的结果保存,这样在之后训练模型是直接读取数据即可,省去重复的数据处理
json.dump(documents_feature, open('tmp/documents_feature.txt', 'w'))
json.dump(test_documents_feature, open('tmp/test_documents_feature.txt', 'w'))

这里我们可以为每个类选出最具代表性的十个词语看一下,从下面的特征词可以看出来,我们程序提取的特征词还是很具有类别区分度的,也可以看出第四类和第九类、第五类和第八类较为相似,可能在分类上会比较难区分:

feature_words = [[u'物业管理', u'物业', u'房地产', u'顾问', u'中介', u'住宅', u'商业', u'开发商', u'招商', u'营销策划'],[u'私募', u'融资', u'金融', u'贷款', u'基金', u'股权', u'资产', u'小额贷款', u'投资', u'担保'],[u'软件', u'互联网', u'平台', u'信息化', u'软件开发', u'数据', u'移动', u'信息', u'系统集成', u'运营'],[u'制造', u'安装', u'设备', u'施工', u'机械', u'工程', u'自动化', u'工业', u'设计', u'装备'],[u'药品', u'医药', u'生物', u'原料药', u'药物', u'试剂', u'GMP', u'片剂', u'制剂', u'诊断'],[u'材料', u'制品', u'塑料', u'环保', u'新型', u'化学品', u'改性', u'助剂', u'涂料', u'原材料'],[u'养殖', u'农业', u'种植', u'食品', u'加工', u'龙头企业', u'产业化', u'饲料', u'基地', u'深加工'],[u'医疗器械', u'医疗', u'医院', u'医用', u'康复', u'治疗', u'医疗机构', u'临床', u'护理'],[u'汽车', u'零部件', u'发动机', u'整车', u'模具', u'C36', u'配件', u'总成', u'车型'],[u'媒体', u'制作', u'策划', u'广告', u'传播', u'创意', u'发行', u'影视', u'电影', u'文化'],[u'运输', u'物流', u'仓储', u'货物运输', u'货运', u'装卸', u'配送', u'第三方', u'应链', u'集装箱']]

接下来调用train.py函数,就可以得到我们的预测结果,这里我使用了朴素贝叶斯、决策树、SVC三种算法,但是结果显示朴素贝叶斯效果更好,根据参数不同测试集准确率大概达到了78%~79%左右。此外还有几个地方可以调节:

  1. 特征词维度的选择,即上面代码feature_select_use_new_CHI()函数中每个类别选择多少个特征词,取值范围在100-500
  2. 特征权重的计算方式,即上面代码document_features()函数中对每个特征词的权重计算方式,我们可以认为只要出现就记为1,否则为零;或者使用其在该文本中出现次数作为权重;或者使用TF-IDF作为权重,或者其他方法。。。
  3. 分类器的选择及参数调整,其实我们应该取出500条记录作为测试集去验证模型好坏以及作为参数选择的依据,但是因为时间比较紧迫,所以我并未作这部分工作==
documents_feature =json.load(open('tmp/documents_feature.txt', 'r'))
test_documents_feature = json.load(open('tmp/test_documents_feature.txt', 'r'))print "开始训练分类器"
classifier = nltk.NaiveBayesClassifier.train(documents_feature)
#classifier = nltk.DecisionTreeClassifier.train(documents_feature)
#classifier = SklearnClassifier(SVC(), sparse=False).train(documents_feature[:4000])
#test_error = nltk.classify.accuracy(classifier, documents_feature)
#print "test_error:", test_error
#classifier.show_most_informative_features(20)
results = classifier.classify_many([fs for fs in test_documents_feature])with open('output/TFIDF_out.csv', 'w') as f:for i in range(2381):f.write(str(i+1))f.write(',')f.write(str(results[i]+1))f.write('\n')

此外,在获得了上面所说的类别特征词之后(每类取十个),我还尝试着用简单的类别匹配方法进行分类,思路很简单,就是看测试集包含哪个特征集中的单词更多,代码入下:

result = []
qq = 0
with open('data/testing.csv', u'r') as f:for line in f:content = ""for aa in line.split(',')[1:]:content += aaword_list, word_set = jieba_fenci(content, stopwords_list)label = 2count = 0for i, cla in enumerate(feature_words):tmp = 0for word in word_list:if word in cla:tmp += 1if tmp > count:count = tmplabel = i+1if count == 0:qq += 1result.append(label)

这个效果一般,准确率好像是在69%或者74%左右,记不太清了。

3,XGBoost算法–文本分类

考虑到xgboost算法在各类竞赛中都有很好的效果,我也决定使用该算法尝试一下效果如何,在网上找了一篇博客,直接套用到这里。我们使用所有的词作为特征进行one-hot编码(使用from sklearn.feature_extraction.text import CountVectorizer和 from sklearn.feature_extraction.text import TfidfTransformer),代码如下:

# -*- coding: utf-8 -*-
import xgboost as xgb
import csv
import jieba
#jieba.load_userdict('wordDict.txt')
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer# 读取训练集
def readtrain(path):with open(path, 'rb') as csvfile:reader = csv.reader(csvfile)column1 = [row for row in reader]content_train = [i[1] for i in column1] # 第一列为文本内容,并去除列名opinion_train = [int(i[0])-1 for i in column1] # 第二列为类别,并去除列名print '训练集有 %s 条句子' % len(content_train)train = [content_train, opinion_train]return traindef stop_words():stop_words_file = open('stop_words_ch.txt', 'r')stopwords_list = []for line in stop_words_file.readlines():stopwords_list.append(line.decode('gbk')[:-1])return stopwords_list# 对列表进行分词并用空格连接
def segmentWord(cont):stopwords_list = stop_words()c = []for i in cont:text = ""word_list = list(jieba.cut(i, cut_all=False))for word in word_list:if word not in stopwords_list and word != '\r\n':text += wordtext += ' 'c.append(text)return cdef segmentWord1(cont):c = []for i in cont:a = list(jieba.cut(i))b = " ".join(a)c.append(b)return ctrain = readtrain('data/training.csv')
train_content = segmentWord1(train[0])
train_opinion = np.array(train[1])     # 需要numpy格式
print "train data load finished"
test = readtrain('data/testing.csv')
test_content = segmentWord(test[0])
print 'test data load finished'vectorizer = CountVectorizer()
tfidftransformer = TfidfTransformer()
tfidf = tfidftransformer.fit_transform(vectorizer.fit_transform(train_content))
weight = tfidf.toarray()
print tfidf.shape
test_tfidf = tfidftransformer.transform(vectorizer.transform(test_content))
test_weight = test_tfidf.toarray()
print test_weight.shapedtrain = xgb.DMatrix(weight, label=train_opinion)
dtest = xgb.DMatrix(test_weight)  # label可以不要,此处需要是为了测试效果
param = {'max_depth':6, 'eta':0.5, 'eval_metric':'merror', 'silent':1, 'objective':'multi:softmax', 'num_class':11}  # 参数
evallist  = [(dtrain,'train')]  # 这步可以不要,用于测试效果
num_round = 100  # 循环次数
bst = xgb.train(param, dtrain, num_round, evallist)
preds = bst.predict(dtest)
with open('XGBOOST_OUTPUT.csv', 'w') as f:for i, pre in enumerate(preds):f.write(str(i + 1))f.write(',')f.write(str(int(pre) + 1))f.write('\n')

效果不错,测试集可以达到80%的准确度,出乎意料的好==然后我还尝试将提取出来的特征用到XGBoost模型上,也就是在train.py中调用xgboost模型,结果发现准确度出不多也是80%左右,没有很大提升。其实这里也应该做参数优化的工作,比如xgboost的max_depth、n_estimate、学习率等参数等应该进行调节,因为时间太紧我这部分工作也没做,而是使用的默认设置==

4, 卷积神经网络

这里使用YOON KIM的模型框架,代码使用WILDML的,可以参见我之前的一篇博客,为了适用于本任务,修改一下 data_helpers.py文件中的代码,增加load_AI100_data_and_labels()函数,用于读取训练集和测试集。然后就可以训练了,这里使用随机初始化的词向量,让其随模型训练,效果不错,测试集精确度达到了82%以上,之后我还尝试了一下使用char-cnn模型,但是效果不太好,根本就没有办法收敛,可能是参数选择的不对或者训练集太小了,但是到这比赛就结束了,我也没有时间和机会去尝试更所得模型和参数==

5,别人的方法

赛后,举办方请第一名的选手分享了方法和经验,我发现他也是使用的卷积神经网络,不过分词的时候加入了词性标注,然后使用gensim单独训练词向量,然后卷积层的使用了1000个卷积核等等吧,其分享链接为:http://geek.ai100.com.cn/2017/05/18/1580 
模型架构如下图所示: 

文本分类实战--从TFIDF到深度学习(附代码)相关推荐

  1. 文本分类实战--从TFIDF到深度学习CNN系列效果对比(附代码)

    向AI转型的程序员都关注了这个号

  2. bert使用做文本分类_使用BERT进行深度学习的多类文本分类

    bert使用做文本分类 Most of the researchers submit their research papers to academic conference because its ...

  3. textcnn文本词向量_基于Text-CNN模型的中文文本分类实战

    1 文本分类 文本分类是自然语言处理领域最活跃的研究方向之一,目前文本分类在工业界的应用场景非常普遍,从新闻的分类.商品评论信息的情感分类到微博信息打标签辅助推荐系统,了解文本分类技术是NLP初学者比 ...

  4. 视频教程-自然语言处理实战——LSTM情感分析-深度学习

    自然语言处理实战--LSTM情感分析 CSDN讲师名下集合了诸多业界知名讲师的公开课内容,内容涵盖人工智能.大数据.区块链等诸多热门技术领域的最佳技术实践,聚合美团.滴滴.AWS.科大讯飞等知名企业的 ...

  5. 自然语言处理入门实战2:基于深度学习的文本分类

    自然语言处理入门实战2:基于深度学习的文本分类 数据集 数据预处理 模型 模型训练 模型测试 参考 本文参考复旦大学自然语言处理入门练习,主要是实现基于深度学习的文本分类. 环境:python3.7 ...

  6. 英文文本分类实战总结

    之前参加了一个英文文本的分类比赛.比赛结束到了过年,加上开学又有一些事情,所以总结的工作就一直没有进行.现在空了一些,所以把之前的工作写一写,比赛中用到的代码也会放到github上. 对这个比赛的任务 ...

  7. 【英文文本分类实战】之三——数据清洗

    ·请参考本系列目录:[英文文本分类实战]之一--实战项目总览 ·下载本实战项目资源:神经网络实现英文文本分类.zip(pytorch) [1] 为什么要清洗文本   这里涉及到文本分类任务中:词典.词 ...

  8. 【项目实战课】NLP入门第1课,人人免费可学,基于TextCNN的新闻文本分类实战...

    欢迎大家来到我们的项目实战课,本期内容是<基于TextCNN的新闻文本分类实战>. 所谓项目课,就是以简单的原理回顾+详细的项目实战的模式,针对具体的某一个主题,进行代码级的实战讲解,可以 ...

  9. word2vec模型评估_NLP之文本分类:「Tf-Idf、Word2Vec和BERT」三种模型比较

    字幕组双语原文:NLP之文本分类:「Tf-Idf.Word2Vec和BERT」三种模型比较 英语原文:Text Classification with NLP: Tf-Idf vs Word2Vec ...

最新文章

  1. AD上删除了Exchange容器,再重装时报'找不到企业组织容器
  2. 【新周报(045)】青少年编程竞赛交流群周报
  3. Fork 一个仓库并同步
  4. 学习ASP.NET一定要学习ASP.NET AJAX吗?
  5. TopCoder入门教程
  6. WCF 客户端调用服务操作的两种方法
  7. Codeforces Round #739 (Div. 3)(AK实况)
  8. 动态路由协议的基本配置---RIP
  9. 【渝粤教育】国家开放大学2018年秋季 1020t国际私法 参考试题
  10. 学生信息管理系统html界面,学生信息管理系统jsp课程设计.doc
  11. 华为服务器SNMP协议怎么修改,华为迈普交换机、瑞斯康达SNMP协议配置方法
  12. linux 下tar打包举例,Linux tar打包命令
  13. Axure实战002:APP原型设计思路
  14. 金蝶中间件公司CTO袁红岗
  15. 小米妙想PC端连接平板5教程
  16. 谈一谈Coders Programmer Developer的区别
  17. viper4android历史版本,VIPER4Android最新版本
  18. ff14显卡测试软件,最终幻想14首台4K电脑环境搭建测试实录
  19. 高中计算机专业班主任工作总结,大学班主任工作总结5篇
  20. vue 使用 XLSX 导入表格

热门文章

  1. 车主委托过户和电子委托书
  2. CAN 网络通信矩阵
  3. 插件化基础(二)——加载插件资源
  4. 互联网日报 | 3月5日 星期五 | 抖音成为2020欧洲杯官方合作伙伴;携程GMV连续三年全球旅企第一;华为发布好望云服务...
  5. Java并发编程 - 第三章 Java内存模型
  6. 吴恩达机器学习——反向传播算法
  7. java版b2b2c社交电商分布式微服务-Spring Cloud Netflix
  8. Redis入门——3.Redis key的设计技巧
  9. 01.奇特的一生——柳比歇夫一生的秘密
  10. 沃尔玛中国将采用唯链雷神区块链追踪食品供应链