zoukankan      html  css  js  c++  java
  • sklearn+nltk ——情感分析(积极、消极)

    转载:https://www.iteye.com/blog/dengkane-2406703

    步骤:

    1 有标签的数据。数据:好评文本:pos_text.txt  差评文本:neg_text.txt

    2 构造特征:词,双词搭配(Bigrams),比如“手机 非常”,“非常 好用”,“好用 !”这三个搭配作为分类的特征。以此类推,三词搭配(Trigrams),四词搭配都是可以被作为特征的.

    3 特征降维:使用统计方法找到信息量丰富的特征。包括:词频(Term Frequency)、文档频率(Document Frequency)、互信息(Pointwise Mutual Information)、信息熵(Information Entropy)、卡方统计(Chi-Square)等等。

    4 特征表示:nltk——[ {“特征1”: True, “特征2”: True, “特征N”: True, }, 类标签 ]

    5 构建分类器并预测:选出最佳算法后可以调整特征的数量来测试准确度。(1)用分类算法训练里面的训练集(Training Set),得出分类器。(2)用分类器给开发测试集分类(Dev-Test Set),得出分类结果。(3)对比分类器给出的分类结果和人工标注的正确结果,给出分类器的准确度。

    其中,nltk 主要负责处理特征提取(双词或多词搭配需要使用nltk 来做)和特征选择(需要nltk 提供的统计方法)。scikit-learn 主要负责分类算法,评价分类效果,进行分类等任务。

     实验:

    1.处理数据。str 是全部pos+neg的数据。类型是:str()

    def text():
        f1 = open('pos_text.txt','r') 
        f2 = open('neg_text.txt','r')
        line1 = f1.readline()
        line2 = f2.readline()
        str = ''
        while line1:
            str += line1
            line1 = f1.readline()
        while line2:
            str += line2
            line2 = f2.readline()
        f1.close()
        f2.close()
        return str

    2.构建特征

    #把单个词作为特征
    def bag_of_words(words):
        d={}
        for word in words:
            d[word]=True
        return d
    
    print(bag_of_words(text()[:5]))
    {'除': True, '了': True, '电': True, '池': True, '不': True}
    import nltk
    from nltk.collocations import  BigramCollocationFinder
    from nltk.metrics import  BigramAssocMeasures
    
    #把双个词作为特征,并使用卡方统计的方法,选择排名前1000的双词
    def bigram(words,score_fn=BigramAssocMeasures.chi_sq,n=1000):
        bigram_finder=BigramCollocationFinder.from_words(words)  #把文本变成双词搭配的形式
        bigrams = bigram_finder.nbest(score_fn,n)  #使用卡方统计的方法,选择排名前1000的双词
        newBigrams = [u+v for (u,v) in bigrams]  # bigrams知识个双词列表
        return bag_of_words(newBigrams)  #调用bag_of_words 变成{词:True}的字典
    
    print(bigram(text()[:5],score_fn=BigramAssocMeasures.chi_sq,n=1000))
    {'了电': True, '池不': True, '电池': True, '除了': True}
    #把单个词和双个词一起作为特征
    def bigram_words(words,score_fn=BigramAssocMeasures.chi_sq,n=1000):
        bigram_finder=BigramCollocationFinder.from_words(words)
        bigrams = bigram_finder.nbest(score_fn,n)
        newBigrams = [u+v for (u,v) in bigrams]
        
        word_dict = bag_of_words(words) #单个字的字典
        bigrams_dict = bag_of_words(newBigrams)#二元词组的字典
        word_dict.update(bigrams_dict)  #把字典bigrams_dict合并到字典word_dict中
        return word_dict
    
    print(bigram_words(text()[:10],score_fn=BigramAssocMeasures.chi_sq,n=1000))
    {'除': True, '了': True, '电': True, '池': True, '不': True, '给': True, '力': True, ' ': True, '都': True, '很': True, ' 都': True, '不给': True, 
    '了电': True, '力 ': True, '池不': True, '电池': True, '给力': True, '都很': True, '除了': True}
    import jieba
    #结巴分词作为特征
    def read_file(filename): stop = [line.strip() for line in open('stopword.txt','r',encoding='utf-8').readlines()] #停用词 f = open(filename,'r') line = f.readline() str = [] while line: s = line.split(' ')#去掉换行符 #print('s:',s)#['…… '] #print('s[0]:',s[0])#['……'] fenci = jieba.cut(s[0],HMM=True) #False默认值:精准模式 参数HMM=True时,就有了新词发现的能力 str.append(list(set(fenci)-set(stop))) line = f.readline() return str #str 是一个整个评论的列表了
    print(read_file('pos_text.txt')[:2])
    [['真的', '大屏', '僵尸', '好', '敢', '出色', '300', '14', '多买块', '都', '大战', '双核', '秒杀', '帮', '苹果', '一点', '一张', 'G11', '分辨率', '入手',
    '地方', '植物', '会', ' ', '值得', '16G', '请', '电池', '不给力', '才', '4', '2820', '拿下', '综合', '盖', '感觉', '回答', 'C6', '选', '10', '留言', '玩机',
    '大屏幕', '一起', '放', '照相', '3', '不在乎', '哥', '不是', '非常', '画面', '水果', '游戏', '本来', '再', '贵', '机子', '朋友', '之间', '果断', ' ', '不敢',
    'G14', '一会', '咨询', '差', '判定', '觉得', '小', '尽量', '办公室', '想', '高', '多天', '开后', '心动', '打算', '不会', '极品飞车', '纠结', '买', '玩', '很无语',
    '不到', '安徽', '阜阳', '老婆', '很', '块', '卡', '俩', '差不多', '价格', '带', '500W'], ['9', '希望', '能够', '电池', '很漂亮', '很棒', '屏幕', '不错', '寸',
    '几乎', '完机', '高', '性价比', '4', 'sense', '运行', '都', '值得', '现在', '烫手', '16', '2.3', '一点', '4.3', '长时间', '霸气', '行', '软件', '解决', '入手',
    '很', '确实', '瑕不掩瑜', '其实', ' ', '流畅', '兼容', '还', '3.0', '问题', '真机', '整体', '清晰', '机无', ' ']]
    from nltk.probability import  FreqDist,ConditionalFreqDist
    from nltk.metrics import  BigramAssocMeasures
    
    #获取信息量最高(前number个)的特征(卡方统计)
    
    def jieba_feature(number):   
        posWords = []
        negWords = []
        for items in read_file('pos_text.txt'):#把集合的集合变成集合
            for item in items:
                posWords.append(item)
        for items in read_file('neg_text.txt'):
            for item in items:
                negWords.append(item)
    
        word_fd = FreqDist() #可统计所有词的词频
        #FreqDist中的键为单词,值为单词的出现总次数。实际上FreqDist构造函数接受任意一个列表,
        #它会将列表中的重复项给统计起来,在本例中我们传入的其实就是一个文本的单词列表。
        
        cond_word_fd = ConditionalFreqDist() #可统计积极文本中的词频和消极文本中的词频
        #条件频率分布是频率分布的集合,每个频率分布有一个不同的条件,这个条件通常是文本的类别。
        #条件频率分布需要处理的是配对列表,每对的形式是(条件,事件),在示例中条件为文体类别,事件为单词。
        #成员方法
        #conditions(),返回条件列表
        #tabulate(conditions, samples),根据指定的条件和样本,打印条件频率分布表格
        #plot(conditions, samples),根据给定的条件和样本,绘制条件频率分布图
    
        for word in posWords:
            word_fd[word] += 1
            cond_word_fd['pos'][word] += 1
    
        for word in negWords:
            word_fd[word] += 1
            cond_word_fd['neg'][word] += 1
    
        pos_word_count = cond_word_fd['pos'].N() #积极词的数量
        neg_word_count = cond_word_fd['neg'].N() #消极词的数量
        total_word_count = pos_word_count + neg_word_count
    
        word_scores = {}#包括了每个词和这个词的信息量
    
        for word, freq in word_fd.items():#word_fd={'word':count}
            pos_score = BigramAssocMeasures.chi_sq(cond_word_fd['pos'][word],  (freq, pos_word_count), total_word_count) 
            #计算积极词的卡方统计量,这里也可以计算互信息等其它统计量.
            #卡方x2值描述了自变量与因变量之间的相关程度:x2值越大,相关程度也越大
            
            neg_score = BigramAssocMeasures.chi_sq(cond_word_fd['neg'][word],  (freq, neg_word_count), total_word_count) 
            
            word_scores[word] = pos_score + neg_score #一个词的信息量等于积极卡方统计量加上消极卡方统计量
    
        best_vals = sorted(word_scores.items(), key=lambda item:item[1],  reverse=True)[:number] #把词按信息量倒序排序。number是特征的维度,是可以不断调整直至最优的
        best_words = set([w for w,s in best_vals])
         
        return dict([(word, True) for word in best_words])
    #调整设置,分别从四种特征选取方式开展并比较效果
    
    def build_features():
        feature = bag_of_words(text())#第一种:单个词
        #feature = bigram(text(),score_fn=BigramAssocMeasures.chi_sq,n=500)#第二种:双词
        #feature = bigram_words(text(),score_fn=BigramAssocMeasures.chi_sq,n=500)#第三种:单个词和双个词
        #feature = jieba_feature(300)#第四种:结巴分词
    
        posFeatures = []
        for items in read_file('pos_text.txt'):
            a = {}
            for item in items: #item是每一句的分词列表
                if item in feature.keys():
                    a[item]='True'
            posWords = [a,'pos'] #为积极文本赋予"pos"
            posFeatures.append(posWords)
            
        negFeatures = []
        for items in read_file('neg_text.txt'):
            a = {}
            for item in items:
                if item in feature.keys():
                    a[item]='True'
            negWords = [a,'neg'] #为消极文本赋予"neg"
            negFeatures.append(negWords)
            
        return posFeatures,negFeatures
    #获得训练数据
    
    posFeatures,negFeatures = build_features()
    
    from random import shuffle
    import sklearn
    from nltk.classify.scikitlearn import  SklearnClassifier
    from sklearn.svm import SVC, LinearSVC,  NuSVC
    from sklearn.naive_bayes import  MultinomialNB, BernoulliNB
    from sklearn.linear_model import  LogisticRegression
    from sklearn.metrics import  accuracy_score
    
    shuffle(posFeatures) 
    shuffle(negFeatures) #把文本的排列随机化 
    
    train =  posFeatures[300:]+negFeatures[300:]#训练集(70%)
    test = posFeatures[:300]+negFeatures[:300]#验证集(30%)
    
    data,tag = zip(*test)#分离测试集合的数据和标签,便于验证和测试
    
    def score(classifier):
        classifier = SklearnClassifier(classifier) 
        classifier.train(train) #训练分类器
        pred = classifier.classify_many(data) #给出预测的标签
        n = 0
        s = len(pred)
        for i in range(0,s):
            if pred[i]==tag[i]:
                n = n+1
        return n/s #分类器准确度
    
    print('BernoulliNB`s accuracy is %f' %score(BernoulliNB()))
    print('MultinomiaNB`s accuracy is %f' %score(MultinomialNB()))
    print('LogisticRegression`s accuracy is %f' %score(LogisticRegression(solver='lbfgs')))
    print('SVC`s accuracy is %f' %score(SVC(gamma='scale')))
    print('LinearSVC`s accuracy is %f' %score(LinearSVC()))
    #print('NuSVC`s accuracy is %f' %score(NuSVC()))

    3.结果

    # BernoulliNB`s accuracy is 0.858333
    # **** MultinomiaNB`s accuracy is 0.871667*****
    # LogisticRegression`s accuracy is 0.820000
    # SVC`s accuracy is 0.805000
    # LinearSVC`s accuracy is 0.795000
    #第四种:结巴分词
    # **** BernoulliNB`s accuracy is 0.761667*****
    # MultinomiaNB`s accuracy is 0.701667
    # LogisticRegression`s accuracy is 0.756667
    # SVC`s accuracy is 0.688333
    # LinearSVC`s accuracy is 0.733333
    #第三种:单个词和双个词
    # ***** BernoulliNB`s accuracy is 0.773333******
    # MultinomiaNB`s accuracy is 0.688333
    # LogisticRegression`s accuracy is 0.726667
    # SVC`s accuracy is 0.661667
    # LinearSVC`s accuracy is 0.726667
    #第二种:双词
    # BernoulliNB`s accuracy is 0.641667
    # MultinomiaNB`s accuracy is 0.616667
    #***** LogisticRegression`s accuracy is 0.668333*****
    # SVC`s accuracy is 0.545000
    # LinearSVC`s accuracy is 0.653333
    #第一种:单个词

  • 相关阅读:
    构造函数初始化与赋值
    C代码中如何调用C++ C++中如何调用C
    C用函数指针模拟重载 C++重载
    【2019.10.30】意料之外的小黄衫——获得小黄衫感言
    【2019.10.30】SDN上机第1次作业
    【2019.10.17】十天Web前端程序员体验(软件工程实践第五次作业)
    【2019.10.07】《重生之我是程序员》
    【2019.09.30】“福大同好”——原型设计展示~
    【2019.09.30】构建之法《四五八章读后感》
    【2019.09.25】《构建之法》前三章读后感
  • 原文地址:https://www.cnblogs.com/DHuifang004/p/11406211.html
Copyright © 2011-2022 走看看