文本情感分类 - CSDN
  • 预选赛题——文本情感分类模型 Data Analysis 先来观察下数据,训练集和测试集分别存储在当前目录下的train.csv和20190520_test.csv中 train_data = pd.read_csv('train.csv', lineterminator='\n') # 行分隔符 = '...

    预选赛题——文本情感分类模型

    Data Analysis

    先来观察下数据,训练集和测试集分别存储在当前目录下的train.csv和20190520_test.csv中

    train_data = pd.read_csv('train.csv', lineterminator='\n') # 行分隔符 = '\n'
    test_data = pd.read_csv('20190520_test.csv', lineterminator='\n')
    train_data['label'] = train_data['label'].map({'Negative':0, 'Positive':1})
    train_data.head()
    

    Data Processing

    数据处理差不多花了我1整天的时间,主要还是我太菜,对python的很多用法不太熟

    首先我把label标签离散为0-1Negative0Positive1

    然后将遍历每一行,对review这一列的文本进行清洗,很明显的看到,文本里面有各种垃圾信息,比方说有emoji表情,还有各种标点符号、数字等等。过滤掉这些符号以后,再将一行文本全部转换成小写,之后按照空格进行分隔,然后再用一个空格隔开进行拼接,这样做的目的是因为,一行文本里面两个词之间可能不止用一个空格隔开,所以我干脆人为用一个空格隔开,还有一些乱七八糟符号的干扰大家可以用自己的办法过滤

    train_data['label'] = train_data['label'].map({'Negative':0, 'Positive':1})
    rmSignal = ['.', '?', '!', ':', '-', '+', '/', '"', ',']
    
    def review_to_words(data):
        
        # 正则去除表情
        emoji_pattern = re.compile(u'[\U00010000-\U0010ffff]')
        data = emoji_pattern.sub(u'', data)
        
        # 正则去除标点
        fuhao_pattern = re.compile(u'\.*')
        data = fuhao_pattern.sub(u'', data)
        
        # 正则去除数字
        digit_pattern = re.compile(u'\d+')
        data = digit_pattern.sub(u'', data)
        
        # 空格拆分词语
        words = data.lower().split()
        
        # 去掉rmSignal
        meaningful_words = [w for w in words if not w in rmSignal]
        
        # 将筛分好的词合成一个字符串,并用空格分开
        words = " ".join(meaningful_words)
        return words
    
    clean_train_reviews = []
    for i in range(0, len(train_data)):
        clean_train_reviews.append(review_to_words(train_data['review'][i]))
    clean_train_reviews[:5]
    
    输出:
    ['jo bhi ap se tou behtar hoon',
     'ya allah meri sister affia ki madad farma',
     'yeh khud chahta a is umar main shadi krna had ogi',
     'tc apky mun xe exe alfax achy nae lgty',
     'good']
    

    接着使用TF-IDF构建词袋,然后查看一下词频最高的十个词

    tfv = TfidfVectorizer()
    train_data_features = tfv.fit_transform(clean_train_reviews)
    train_data_features = train_data_features.toarray()
    cntWords = sorted(tfv.vocabulary_, key=lambda x:x[0])
    cntWords[-10:]
    
    输出:
    ['اے', 'بیٹھی', 'جیڑی', 'سی', 'ناں', 'کردی', 'کر', 'ھاں', '賭easar', '鄭h']
    

    Model Selection

    Bayes

    在模型选择上,对于这种文本分类问题,贝叶斯是一个简单又好用的分类器,算法思想挺简单的,这里不再介绍原理

    利用cross_val_score对训练集进行交叉训练,这里我设定的是20折,大家可以试试别的参数,包括贝叶斯的参数我也用的默认的,也可以适当调参

    model_NB = MNB()
    model_NB.fit(train_data_features,train_data["label"])
    
    score = np.mean(cross_val_score(model_NB,train_data_features, train_data["label"], cv=20, scoring='roc_auc'))
    print("多项式贝叶斯分类器20折交叉验证得分: ",score) # 0.8614076771593228
    

    Logistic Regression

    同时我也顺便建立了一下Logistic Regression模型

    model_LR = LR(random_state = 0)
    model_LR.fit(train_data_features,train_data["label"])
    
    score = np.mean(cross_val_score(model_LR,train_data_features, train_data["label"], cv=20, scoring='roc_auc'))
    print("Logistic Regression20折交叉验证得分: ", score) # 0.844763864535499
    

    Predict

    从训练集的结果上来看,贝叶斯更优,因此我就用训练好的贝叶斯分类器对测试集进行预测

    首先也要把测试集的数据进行清理,然后通过已经训练好的TF-IDF模型求出词频-逆文件频率矩阵,带入到贝叶斯分类器进行测试即可

    clean_test_reviews = []
    for i in range(0, len(test_data["review"])):
        clean_test_reviews.append(review_to_words(test_data["review"][i]))
    clean_test_reviews[:5]
    
    test_data_features = tfv.transform(clean_test_reviews)
    test_data_features = test_data_features.toarray()
    
    result = model_NB.predict_proba(test_data_features)
    #print(result[:,1])
    output = pd.DataFrame(data={"ID":test_data["ID"], "Pred":result[:,1]})
    output.to_csv("out_model.csv", index=False, quoting=3)
    

    提交后Score为0.86241116,咸鱼水平有限,大佬们勿喷

    数据集和代码可以访问咸鱼的Github

    展开全文
  • 预选赛题——文本情感分类模型 本预选赛要求选手建立文本情感分类模型,选手用训练好的模型对测试集中的文本情感进行预测,判断其情感为「Negative」或者「Positive」。所提交的结果按照指定的评价指标使用在线评测...

    预选赛题

    预选赛题——文本情感分类模型

    本预选赛要求选手建立文本情感分类模型,选手用训练好的模型对测试集中的文本情感进行预测,判断其情感为「Negative」或者「Positive」。所提交的结果按照指定的评价指标使用在线评测数据进行评测,达到或超过规定的分数线即通过预选赛。

    比赛数据

    数据样本格式:
    NO 列名 类型 字段描述
    1 ID int 文本唯一标识
    2 review string 文本纪录
    3 label string 文本的情感状态

    其中,训练集的样本规模为6328,测试集的样本规模为2712。

    提交结果

    选手提交.csv的结果文件,文件名可以自定义,但文件内的字段需要对应。其中,ID表示文本唯一标识,pred表示预测该条文本的情感状态是否为「Positive」。

    结果文件的内容示例:

    ID Pred
    1 0.123456
    2 0.654321
    3 0.799212

    评估方法

    选手提交结果的评估指标是AUC(Area Under Curve),本次测评采用Public-Private榜与实时测评方式,即参赛选手提交结果文件后几分钟内便可获知分数。

    代码操作部分

    导入包
    import numpy as np
    import pandas as pd
    import re
    import warnings
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    #导入特征提取包,导入朴素贝叶斯分类器
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.naive_bayes import MultinomialNB as NB
    from sklearn.metrics import classification_report
    
    获取数据,训练集和测试集

    在后续我将训练集和测试集合并在了一起,方便数据清洗,且我在训练词袋也是用的总数据。

    train = pd.read_csv('train.csv',lineterminator='\n')
    test = pd.read_csv('test1.csv',lineterminator='\n')
    

    注意:如果后面不加lineterminator=’\n’,可能会报如下错:

    ParserError: Error tokenizing data. C error: Buffer overflow caught - possible malformed input file.
    
    数字化

    label列是评论的态度,只有Negative和Positive两类,我们可以将其数字化,方便以后数据的分析和计算。

    train['label'] = train['label'].map(lambda x: 0 if x == 'Negative' else 1)
    
    查看数据集、测试集
    train.head()
    

    在这里插入图片描述

    test.head()
    

    在这里插入图片描述

    合并数据集
    All = train.append(test, ignore_index=True)#合并训练集和测试集,方便以后处理数据,不用训练集测试集处理两次
    

    计算训练集长度,方便后面数据清洗后将总的数据集切割为训练集和测试集

    lentrain = len(train)
    lentrain
    
    6328
    
    数据清洗
    #数据清洗
    # 去除标点符号、数字、特殊字符。去除的内容与参数[^a-zA-Z#]有关
    All['review'] = All['review'].str.replace("[^a-zA-Z#]", " ")
    
    查看清洗后的数据
    All.head()
    

    在这里插入图片描述
    可见,数据清洗后已经没有了表情,标点符号和数字,特殊字符了,这样,数据集就可以用来建词库了。

    numpy_array = All.as_matrix()#将数据转换成数组形式
    numpy_array[:4]
    
    array([[1, 0.0, 'Jo bhi ap se tou behtar hoon'],
           [2, 1.0, 'ya Allah meri sister Affia ki madad farma'],
           [3, 0.0, 'Yeh khud chahta a is umar main shadi krna   had ogi'],
           [4, 0.0, 'Tc   Apky mun xe exe alfax achy nae lgty   ']],
          dtype=object)
    
    corpus = numpy_array[: , 2]
    corpus
    
    array(['Jo bhi ap se tou behtar hoon',
           'ya Allah meri sister Affia ki madad farma',
           'Yeh khud chahta a is umar main shadi krna   had ogi', ...,
           'Aala taleem nay unhain  liberal  bana dia tha ',
           'Unhone tu kuch bhi nhe parhaya tu nazar kiya ata',
           'Sahi khel gaey'], dtype=object)
    
    #采用TfidfVectorizer提取文本特征
    tfidf = TfidfVectorizer()
    re = tfidf.fit_transform(corpus)#用所有文本来提取
    
    #输出词袋模型
    print(re.shape)#此词袋有9040行文本,共21477个词汇
    
    (9040, 21477)
    

    截取训练集X_train,测试集X_test。

    X_train = re[:lentrain] # Separate back into training and test sets. 
    X_test = re[lentrain:]
    print(X_train[:2, :])
    #显示的内容是训练集的第一行和第二行文本的特征词汇在词库中的位置以及词汇的权重
    
      (0, 9362)		0.32296057314704796
      (0, 2836)		0.2700387235197587
      (0, 1139)		0.3432300862856022
      (0, 17709)	0.22620994756759527
      (0, 19953)	0.4257037761290801
      (0, 2550)		0.4881827570097263
      (0, 7942)		0.4839954692246799
      (1, 20993)	0.27180540037912754
      (1, 866)		0.21217865778719738
      (1, 12834)	0.2957075374410748
      (1, 18392)	0.47571699016920305
      (1, 462)		0.5338231280015991
      (1, 10704)	0.139695225538808
      (1, 11904)	0.3553711846525529
      (1, 5989)		0.3695698474715519
    

    取y_train

    y_train = train.label.as_matrix()
    y_train = y_train.astype('int8')
    y_train[:6]
    
    array([0, 1, 0, 0, 1, 0], dtype=int8)
    

    用X_train、y_train学习、训练模型,再用X_test预测结果

    mnb_tfid_stop = NB()
    mnb_tfid_stop.fit(X_train, y_train)   # 学习
    pre = mnb_tfid_stop.predict(X_test)    # 预测
    pre[:6]
    
    array([1, 1, 1, 1, 1, 0], dtype=int8)
    
    Pred = mnb_tfid_stop.predict_proba(X_test)
    Pred
    
    array([[0.09666661, 0.90333339],
           [0.1829802 , 0.8170198 ],
           [0.19821264, 0.80178736],
           ...,
           [0.38031899, 0.61968101],
           [0.5402817 , 0.4597183 ],
           [0.44133509, 0.55866491]])
    
    mnb_tfid_stop.score(X_test, pre)
    
    1.0
    
    data3 = pd.DataFrame(Pred, index=test.ID, columns=['pred0', 'Pred'])
    data3.drop('pred0', axis=1, inplace=True)
    data3.to_csv('result0.csv')
    
    data4 = pd.read_csv('result0.csv')
    
    data4.head()
    

    在这里插入图片描述

    展开全文
  • 电影文本情感分类

    千次阅读 2018-05-11 10:17:23
    电影文本情感分类Github地址Kaggle地址这个任务主要是对电影评论文本进行情感分类,主要分为正面评论和负面评论,所以是一个二分类问题,二分类模型我们可以选取一些常见的模型比如贝叶斯、逻辑回归等,这里挑战之一...

    电影文本情感分类

    Github地址
    Kaggle地址

    这个任务主要是对电影评论文本进行情感分类,主要分为正面评论和负面评论,所以是一个二分类问题,二分类模型我们可以选取一些常见的模型比如贝叶斯、逻辑回归等,这里挑战之一是文本内容的向量化,因此,我们首先尝试基于TF-IDF的向量化方法,然后尝试word2vec。

    # -*- coding: UTF-8 -*-
    import pandas as pd
    import numpy as np
    import re
    from bs4 import BeautifulSoup
    
    def review_to_wordlist(review):
        '''
        把IMDB的评论转成词序列
        参考:http://blog.csdn.net/longxinchen_ml/article/details/50629613
        '''
        # 去掉HTML标签,拿到内容
        review_text = BeautifulSoup(review, "html.parser").get_text()
        # 用正则表达式取出符合规范的部分
        review_text = re.sub("[^a-zA-Z]"," ", review_text)
        # 小写化所有的词,并转成词list
        words = review_text.lower().split()
        # 返回words
        return words

    载入数据集

    # 载入数据集
    train = pd.read_csv('/Users/frank/Documents/workspace/kaggle/dataset/Bag_of_Words_Meets_Bags_of_Popcorn/labeledTrainData.tsv', header=0, delimiter="\t", quoting=3)
    test = pd.read_csv('/Users/frank/Documents/workspace/kaggle/dataset/Bag_of_Words_Meets_Bags_of_Popcorn/testData.tsv', header=0, delimiter="\t", quoting=3)
    print train.head()
    print test.head()
             id  sentiment                                             review
    0  "5814_8"          1  "With all this stuff going down at the moment ...
    1  "2381_9"          1  "\"The Classic War of the Worlds\" by Timothy ...
    2  "7759_3"          0  "The film starts with a manager (Nicholas Bell...
    3  "3630_4"          0  "It must be assumed that those who praised thi...
    4  "9495_8"          1  "Superbly trashy and wondrously unpretentious ...
               id                                             review
    0  "12311_10"  "Naturally in a film who's main themes are of ...
    1    "8348_2"  "This movie is a disaster within a disaster fi...
    2    "5828_4"  "All in all, this is a movie for kids. We saw ...
    3    "7186_2"  "Afraid of the Dark left me with the impressio...
    4   "12128_7"  "A very accurate depiction of small time mob l...

    预处理数据

    # 预处理数据
    label = train['sentiment']
    train_data = []
    for i in range(len(train['review'])):
        train_data.append(' '.join(review_to_wordlist(train['review'][i])))
    test_data = []
    for i in range(len(test['review'])):
        test_data.append(' '.join(review_to_wordlist(test['review'][i])))
    
    # 预览数据
    print train_data[0], '\n'
    print test_data[0]
    with all this stuff going down at the moment with mj i ve started listening to his music watching the odd documentary here and there watched the wiz and watched moonwalker again maybe i just want to get a certain insight into this guy who i thought was really cool in the eighties just to maybe make up my mind whether he is guilty or innocent moonwalker is part biography part feature film which i remember going to see at the cinema when it was originally released some of it has subtle messages about mj s feeling towards the press and also the obvious message of drugs are bad m kay visually impressive but of course this is all about michael jackson so unless you remotely like mj in anyway then you are going to hate this and find it boring some may call mj an egotist for consenting to the making of this movie but mj and most of his fans would say that he made it for the fans which if true is really nice of him the actual feature film bit when it finally starts is only on for minutes or so excluding the smooth criminal sequence and joe pesci is convincing as a psychopathic all powerful drug lord why he wants mj dead so bad is beyond me because mj overheard his plans nah joe pesci s character ranted that he wanted people to know it is he who is supplying drugs etc so i dunno maybe he just hates mj s music lots of cool things in this like mj turning into a car and a robot and the whole speed demon sequence also the director must have had the patience of a saint when it came to filming the kiddy bad sequence as usually directors hate working with one kid let alone a whole bunch of them performing a complex dance scene bottom line this movie is for people who like mj on one level or another which i think is most people if not then stay away it does try and give off a wholesome message and ironically mj s bestest buddy in this movie is a girl michael jackson is truly one of the most talented people ever to grace this planet but is he guilty well with all the attention i ve gave this subject hmmm well i don t know because people can be different behind closed doors i know this for a fact he is either an extremely nice but stupid guy or one of the most sickest liars i hope he is not the latter
    
    naturally in a film who s main themes are of mortality nostalgia and loss of innocence it is perhaps not surprising that it is rated more highly by older viewers than younger ones however there is a craftsmanship and completeness to the film which anyone can enjoy the pace is steady and constant the characters full and engaging the relationships and interactions natural showing that you do not need floods of tears to show emotion screams to show fear shouting to show dispute or violence to show anger naturally joyce s short story lends the film a ready made structure as perfect as a polished diamond but the small changes huston makes such as the inclusion of the poem fit in neatly it is truly a masterpiece of tact subtlety and overwhelming beauty

    特征处理

    直接丢给计算机这些词文本,计算机是无法计算的,因此我们需要把文本转换为向量,有几种常见的文本向量处理方法,比如:

    1. 单词计数
    2. TF-IDF向量
    3. Word2vec向量
      我们先使用TF-IDF来试一下。
    from sklearn.feature_extraction.text import TfidfVectorizer as TFIDF
    # 参考:http://blog.csdn.net/longxinchen_ml/article/details/50629613
    tfidf = TFIDF(min_df=2, # 最小支持度为2
               max_features=None,
               strip_accents='unicode',
               analyzer='word',
               token_pattern=r'\w{1,}',
               ngram_range=(1, 3),  # 二元文法模型
               use_idf=1,
               smooth_idf=1,
               sublinear_tf=1,
               stop_words = 'english') # 去掉英文停用词
    
    # 合并训练和测试集以便进行TFIDF向量化操作
    data_all = train_data + test_data
    len_train = len(train_data)
    
    tfidf.fit(data_all)
    data_all = tfidf.transform(data_all)
    # 恢复成训练集和测试集部分
    train_x = data_all[:len_train]
    test_x = data_all[len_train:]
    print 'TF-IDF处理结束.'
    TF-IDF处理结束.

    朴素贝叶斯训练

    from sklearn.naive_bayes import MultinomialNB as MNB
    
    model_NB = MNB()
    model_NB.fit(train_x, label)
    MNB(alpha=1.0, class_prior=None, fit_prior=True)
    
    from sklearn.cross_validation import cross_val_score
    import numpy as np
    
    print "多项式贝叶斯分类器10折交叉验证得分: ", np.mean(cross_val_score(model_NB, train_x, label, cv=10, scoring='roc_auc'))
    多项式贝叶斯分类器10折交叉验证得分:  0.94983968
    test_predicted = np.array(model_NB.predict(test_x))
    print '保存结果...'
    nb_output = pd.DataFrame(data=test_predicted, columns=['sentiment'])
    nb_output['id'] = test['id']
    nb_output = nb_output[['id', 'sentiment']]
    nb_output.to_csv('nb_output.csv', index=False)
    print '结束.'
    保存结果...
    结束.
    1. 提交最终的结果到kaggle,AUC为:0.85728,排名300左右,50%的水平
    2. ngram_range = 3, 三元文法,AUC为0.85924

    逻辑回归

    from sklearn.linear_model import LogisticRegression as LR
    from sklearn.grid_search import GridSearchCV
    
    # 设定grid search的参数
    grid_values = {'C':[30]}  
    # 设定打分为roc_auc
    model_LR = GridSearchCV(LR(penalty = 'L2', dual = True, random_state = 0), grid_values, scoring = 'roc_auc', cv = 20)
    model_LR.fit(train_x, label)
    # 20折交叉验证
    GridSearchCV(cv=20, estimator=LR(C=1.0, class_weight=None, dual=True,
                 fit_intercept=True, intercept_scaling=1, penalty='L2', random_state=0, tol=0.0001),
            fit_params={}, iid=True, n_jobs=1,
            param_grid={'C': [30]}, pre_dispatch='2*n_jobs', refit=True,
            scoring='roc_auc', verbose=0)
    #输出结果
    print model_LR.grid_scores_
    [mean: 0.96497, std: 0.00476, params: {'C': 30}]
    test_predicted = np.array(model_LR.predict(test_x))
    print '保存结果...'
    lr_output = pd.DataFrame(data=test_predicted, columns=['sentiment'])
    lr_output['id'] = test['id']
    lr_output = lr_output[['id', 'sentiment']]
    lr_output.to_csv('lr_output.csv', index=False)
    print '结束.'
    保存结果...
    结束.
    1. 提交最终的结果到kaggle,AUC为:0.88956,排名260左右,比之前贝叶斯模型有所提高
    2. 三元文法,AUC为0.89076

    Word2vec

    神经网络语言模型L = SUM[log(p(w|contect(w))],即在w的上下文下计算当前词w的概率,由公式可以看到,我们的核心是计算p(w|contect(w), Word2vec给出了构造这个概率的一个方法。

    import gensim
    import nltk
    from nltk.corpus import stopwords
    
    tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
    
    def review_to_wordlist( review, remove_stopwords=False ):
        review_text = BeautifulSoup(review, "html.parser").get_text()
        review_text = re.sub("[^a-zA-Z]"," ", review_text)
    
        words = review_text.lower().split()
    
        if remove_stopwords:
            stops = set(stopwords.words("english"))
            words = [w for w in words if not w in stops]
    
        return(words)
    
    def review_to_sentences( review, tokenizer, remove_stopwords=False ):
        '''
        将评论段落转换为句子,返回句子列表,每个句子由一堆词组成
        '''
        raw_sentences = tokenizer.tokenize(review.strip().decode('utf8'))
    
        sentences = []
        for raw_sentence in raw_sentences:
            if len(raw_sentence) > 0:
                # 获取句子中的词列表
                sentences.append( review_to_wordlist( raw_sentence, remove_stopwords ))
        return sentences
    sentences = []
    for i, review in enumerate(train["review"]):
        sentences += review_to_sentences(review, tokenizer)
    unlabeled_train = pd.read_csv("/Users/frank/Documents/workspace/kaggle/dataset/Bag_of_Words_Meets_Bags_of_Popcorn/unlabeledTrainData.tsv", header=0, delimiter="\t", quoting=3 )
    for review in unlabeled_train["review"]:
        sentences += review_to_sentences(review, tokenizer)
    print '预处理unlabeled_train data...'
    print len(train_data)
    print len(sentences)
        预处理unlabeled_train data...
        25000
        795538

    构建word2vec模型

    import time
    from gensim.models import Word2Vec
    # 模型参数
    num_features = 300    # Word vector dimensionality                      
    min_word_count = 40   # Minimum word count                        
    num_workers = 4       # Number of threads to run in parallel
    context = 10          # Context window size                                                                                    
    downsampling = 1e-3   # Downsample setting for frequent words
    %%time
    # 训练模型
    print("训练模型中...")
    model = Word2Vec(sentences, workers=num_workers, \
                size=num_features, min_count = min_word_count, \
                window = context, sample = downsampling)
    训练模型中...
    CPU times: user 6min 16s, sys: 8.34 s, total: 6min 24s
    Wall time: 2min 27s
    print '保存模型...'
    model.init_sims(replace=True)
    model_name = "300features_40minwords_10context"
    model.save(model_name)
    保存模型...

    预览模型

    model.doesnt_match("man woman child kitchen".split())
    'kitchen'
    model.doesnt_match("france england germany berlin".split())
    'berlin'
    model.doesnt_match("paris berlin london austria".split())
    'london'
    model.most_similar("man")
    [(u'woman', 0.6246455907821655),
     (u'lady', 0.6008599400520325),
     (u'lad', 0.5698915719985962),
     (u'businessman', 0.5431989431381226),
     (u'chap', 0.53116375207901),
     (u'monk', 0.5250570774078369),
     (u'men', 0.5177899599075317),
     (u'guy', 0.517480731010437),
     (u'farmer', 0.5114585757255554),
     (u'person', 0.5109285116195679)]
    model.most_similar("queen")
    [(u'princess', 0.6759523153305054),
     (u'bride', 0.6207793951034546),
     (u'belle', 0.6001157760620117),
     (u'shearer', 0.5995810031890869),
     (u'stepmother', 0.596365749835968),
     (u'victoria', 0.5917614698410034),
     (u'dame', 0.589063286781311),
     (u'latifah', 0.5790275931358337),
     (u'countess', 0.5776904821395874),
     (u'widow', 0.5727116465568542)]
    model.most_similar("awful")
    [(u'terrible', 0.7642339468002319),
     (u'atrocious', 0.7405279874801636),
     (u'horrible', 0.7376815676689148),
     (u'abysmal', 0.7010303139686584),
     (u'dreadful', 0.6942194104194641),
     (u'appalling', 0.6887971758842468),
     (u'lousy', 0.6646767854690552),
     (u'horrid', 0.6554058194160461),
     (u'horrendous', 0.6533403992652893),
     (u'amateurish', 0.6079087853431702)]

    使用Word2vec特征

    def makeFeatureVec(words, model, num_features):
        '''
        对段落中的所有词向量进行取平均操作
        '''
        featureVec = np.zeros((num_features,), dtype="float32")
        nwords = 0.
    
        # Index2word包含了词表中的所有词,为了检索速度,保存到set中
        index2word_set = set(model.index2word)
        for word in words:
            if word in index2word_set:
                nwords = nwords + 1.
                featureVec = np.add(featureVec, model[word])
    
        # 取平均
        featureVec = np.divide(featureVec, nwords)
        return featureVec
    
    
    def getAvgFeatureVecs(reviews, model, num_features):
        '''
        给定一个文本列表,每个文本由一个词列表组成,返回每个文本的词向量平均值
        '''
        counter = 0.
    
        reviewFeatureVecs = np.zeros((len(reviews), num_features), dtype="float32")
    
        for review in reviews:
           if counter % 5000. == 0.:
               print("Review %d of %d" % (counter, len(reviews)))
    
           reviewFeatureVecs[counter] = makeFeatureVec(review, model, \
               num_features)
    
           counter = counter + 1.
        return reviewFeatureVecs
    %time trainDataVecs = getAvgFeatureVecs( train_data, model, num_features )
    Review 0 of 25000
    Review 5000 of 25000
    Review 10000 of 25000
    Review 15000 of 25000
    Review 20000 of 25000
    CPU times: user 1min 49s, sys: 1.9 s, total: 1min 51s
    Wall time: 1min 54s
    %time testDataVecs = getAvgFeatureVecs(test_data, model, num_features)
    Review 0 of 25000
    Review 5000 of 25000
    Review 10000 of 25000
    Review 15000 of 25000
    Review 20000 of 25000
    CPU times: user 1min 44s, sys: 1.56 s, total: 1min 46s
    Wall time: 1min 48s

    高斯贝叶斯+Word2vec训练

    from sklearn.naive_bayes import GaussianNB as GNB
    
    model_GNB = GNB()
    model_GNB.fit(trainDataVecs, label)
    
    from sklearn.cross_validation import cross_val_score
    import numpy as np
    
    print "高斯贝叶斯分类器10折交叉验证得分: ", np.mean(cross_val_score(model_GNB, trainDataVecs, label, cv=10, scoring='roc_auc'))
    
    result = forest.predict( testDataVecs )
    
    output = pd.DataFrame( data={"id":test["id"], "sentiment":result} )
    output.to_csv( "gnb_word2vec.csv", index=False, quoting=3 )
    多项式贝叶斯分类器10折交叉验证得分:  0.625579296

    从验证结果来看,没有超过基于TF-IDF多项式贝叶斯模型

    随机森林+Word2vec训练

    from sklearn.ensemble import RandomForestClassifier
    
    forest = RandomForestClassifier( n_estimators = 100, n_jobs=2)
    
    print("Fitting a random forest to labeled training data...")
    %time forest = forest.fit( trainDataVecs, label )
    print "随机森林分类器10折交叉验证得分: ", np.mean(cross_val_score(forest, trainDataVecs, label, cv=10, scoring='roc_auc'))
    
    # 测试集
    result = forest.predict( testDataVecs )
    
    output = pd.DataFrame( data={"id":test["id"], "sentiment":result} )
    output.to_csv( "rf_word2vec.csv", index=False, quoting=3 )
    Fitting a random forest to labeled training data...
    CPU times: user 45 s, sys: 460 ms, total: 45.5 s
    Wall time: 24.2 s
    随机森林分类器10折交叉验证得分:  0.648426368

    改用随机森林之后,效果有提升,但是依然没有超过基于TF-IDF多项式贝叶斯模型

    展开全文
  • 作者:刘顺祥个人微信公众号:每天进步一点点2015前言 2017年12月9日,参加了天善组织的线下沙龙活动,在沙龙中自己分享了如何借助于R语言完成情感分析的案例,考虑的其他网友没能够参与到活动现场,这里通过微信...
        

    0?wx_fmt=gif&wxfrom=5&wx_lazy=1


    作者:刘顺祥

    个人微信公众号:每天进步一点点2015

    前言


          2017年12月9日,参加了天善组织的线下沙龙活动,在沙龙中自己分享了如何借助于R语言完成情感分析的案例,考虑的其他网友没能够参与到活动现场,这里通过微信公众号作一个简单的分享。

          在文本分析中,最基础的工作就是如何完成句子、段落或文章的分词,当然这一步也是非常重要的,因为这会直接影响后面文档词条矩阵的构造和模型的有效性。一般而言,在做分词和清洗时需要完成如下三个步骤

    • 创建一个自定义词库,并根据这个词库实现正确的分词;

    • 删除分词中的停止词(无用词);

    • 删除其他无用词(如字母、数字等);

          首先我们以电视剧《猎场》中的一句台词为例,完成上面三个步骤的任务:

    # 加载第三方包
    library(jiebaR)

    # 台词
    sentence <- '滚出去!我没有时间听一个牢里混出来的人渣,在这里跟我讲该怎么样不该怎么样!你以为西装往身上一套,我就看不到你骨子里的寒酸,剪剪头、吹吹风,就能掩藏住心里的猥琐?你差得还远,你这种人我见得多了,但还没有见到过敢对我指手画脚的。消失,快从我面前消失!'

    # 设置动力和引擎
    engine <- worker()
    # 查看引擎配置
    engine

          在分词之前,需要跟大家介绍两个函数,它们分别是:

    • worker()—为分词提供动力和引擎

    • segment()—为分词提供战斗机

    首先来看一下默认的分词引擎【worker()】都有哪些配置:

    0?wx_fmt=jpeg

          从上图的结果中,我们可知引擎所选择的分词方法是混合法(即最大概率法和隐马尔科夫方法);中文编码为UTF-8;分词最大长度为20个词;一次性可以读取最大10W行记录;同时也提供了超过58W的词库。通过这些默认的配置就可以完成句子的分词,下面我们来看看这段台词的分词效果:

    # 分词
    cuts <- segment(sentence, engine) cuts

    0?wx_fmt=jpeg     分词结果如上所示,但是你会发现有一些词是切得不正确的,例如“剪剪头”切成了“剪剪”和“头”、“吹吹风”切成了“吹吹”和“风”。按理来说,这些应该作为一个整体被切割,但却被切分开了了。为了避免这种错误的产生,需要用户提供正确切词的词库,然后通过修改worker()函数或使用new_user_word()函数来完成自定义词库的调用:

    # 自定义词库--方法一
    engine2 <- worker(user = 'C:/Program Files/R/R-3.3.1/library/jiebaRD/dict/my_dict.txt') segment(sentence, engine2)

    # 自定义词库--方法二
    new_user_word(engine, c('剪剪头','吹吹风','见到过')) cuts2 <- segment(sentence, engine) cuts2

    第一种方法就是创建词库my_dict文件,并将这个文件路径传递给worker函数;第二种方法使用new_user_word,指定几个自定义词。通过这两种方法,都可以实现正确的切词操作,如下图所示:

    0?wx_fmt=jpeg

          词已经按照我们预期的效果完成切割了,但是分词结果中还是存在一些没有意义的停用词(如“的”、“我”、“他”等),为了避免这些停用词对后面建模的影响,需要将这些词删除。这里也通过两种方法实现,具体见下方的代码:

    # 停止词的处理--方法一
    engine3 <- worker(user = 'C:/Program Files/R/R-3.3.1/library/jiebaRD/dict/my_dict.txt',            stop_word = 'C:/Program Files/R/R-3.3.1/library/jiebaRD/dict/stop_words.txt') segment(sentence, engine3)

    # 停止词的处理--方法二
    cuts3 <- filter_segment(cuts2, filter_words = c('我','的','听','在','你','就','能','还','对',
                                   '人','从','但','讲','跟','这种','一个','身上'))
    cuts3

          第一种方法就是创建停止词词库stop_words文件,并将这个文件路径传递给worker函数;第二种方法使用filter_segment函数,过滤掉指定的那些停止词。通过这两种方法,都可以实现停止词的删除,如下图所示。

    0?wx_fmt=jpeg

          由于台词中不包含数字、字母等字符,这里就不说明如何删除这些内容了,但后面的评论数据例子中是含有这些字符的,那边会有代码说明。接下来需要说一说如何构造文档-词条矩阵了,先来看下面这个图:

    0?wx_fmt=jpeg

          图中的行就代表一个个文档,列就代表一个个词,矩阵中的值就代表每一个词在某个文档中出现的频数。由于不同文档的长度不一致,如果使用简单的频数作为矩阵的值是不理想的。故考虑使用词频-逆文档频率(TFIDF)作为矩阵中的值,其公式如下图所示:

    0?wx_fmt=jpeg

    具体计算的结果,可以查看下面的这个文档-词条矩阵图:

    0?wx_fmt=jpeg

          在R语言中,构建这个矩阵就太简单了,只需调用tm包中的DocumentTermMatrix()函数即可。下面我们就以某酒店的评论数据为例,来构建这个文档-词条矩阵。

    # 导入所需的开发包
    library(readxl)
    library(jiebaR)
    library(plyr)
    library(stringr)
    library(tm)l
    ibrary
    (pROC)
    library(ggplot2)
    library(klaR)
    library(randomForest)

    # 读取评论数据
    evaluation <- read_excel(path = file.choose(),sheet = 2)
    # 查看数据类型
    str(evaluation)
    # 转换数据类型
    evaluation$Emotion <- factor(evaluation$Emotion)

    # 分词(自定义词和停止词的处理)
    engine <- worker(user = 'C:\\Users\\Administrator\\Desktop\\HelloBI\\all_words.txt',                 stop_word = 'C:\\Users\\Administrator\\Desktop\\HelloBI\\mystopwords.txt') cuts <- llply(evaluation$Content, segment, engine)

    #剔除文本中的数字和字母
    Content <- lapply(cuts,str_replace_all,'[0-9a-zA-Z]','')

    # 检查是否有空字符创,如有则删除
    idx <- which(Content == '') Content2 <- Content[-idx]

    # 删除含空字符的元素结果
    Content3 <- llply(Content2, function(x) x[!x == ''])

    # 将切词的评论转换为语料
    content_corpus <- Corpus(VectorSource(Content3))
    # 创建文档-词条矩阵
    dtm <- DocumentTermMatrix(x = content_corpus,                          control = list(weighting = weightTfIdf,                                         wordLengths = c(2, Inf))) dtm

    # 控制稀疏度
    dtm_remove <- removeSparseTerms(x = dtm, sparse = 0.95) dtm_remove
    # 查看变量名 dtm_remove$dimnames$Terms
    # 转换为数据框
    df_dtm <- as.data.frame(as.matrix(dtm_remove)) head(df_dtm)

    0?wx_fmt=jpeg

    这张图反映的是最初的文档-词条矩阵,显示713个文档,1264个词条,而且这个矩阵的稀疏度为100%。为了降低矩阵的系数度,通过removeSparseTerms()函数设定稀疏度,如下图所示,此时的词条数就压缩到了13个,即13个变量。

    0?wx_fmt=jpeg

          接下来,还需要将这个矩阵转换为数据框,因为分类算法(如贝叶斯、随机森林等)不接受上面生成的矩阵类型。有了下面这个数据框,我们就可以将数据集拆分为两部分,一部分用于分类器的构造,另一部分用于验证分类器的效果好坏。

          在构建贝叶斯模型之前,还需要简单介绍一下朴素贝叶斯的理论知识,这样有助于对算法的理解。贝叶斯算法核心是计算条件概率,而此处条件概率的计算又依赖于两个前提假设,即连续变量服从正态分布和各解释变量之间是互相独立的。首先来看一下这个条件概率公式,其可以写成下面这个形式:

    0?wx_fmt=png

          很显然,要求得每个样本下的条件概率最大值,只需求解分子的最大化即可。根据解释变量之间互相独立的假设,还可以将分子转换为下面这个公式:

    0?wx_fmt=jpeg

          而下面这个公式的概率是很好求的,在已知某分类的情况下,计算每个变量取值的概率(当X变量离散时,用变量值的频率代替条件概率;当X变量连续时,用变量的正态概率密度值代替条件概率)。OK,原理很简单,在R语言中,通过调用klaR包中的NaiveBayes()函数就可以实现贝叶斯分类器的构建了。函数语法如下:

    NaiveBayes(x, grouping, prior, usekernel = FALSE, fL = 0, …)

    • x指定需要处理的数据,可以是数据框形式,也可以是矩阵形式;

    • grouping为每个观测样本指定所属类别;

    • prior可为各个类别指定先验概率,默认情况下用各个类别的样本比例作为先验概率;

    • usekernel指定密度估计的方法(在无法判断数据的分布时,采用密度密度估计方法),默认情况下使用标准的密度估计,设为TRUE时,则使用核密度估计方法;

    • fL指定是否进行拉普拉斯修正,默认情况下不对数据进行修正,当数据量较小时,可以设置该参数为1,即进行拉普拉斯修正。

          接下来,进入贝叶斯分类器的实战部分,包含模型的构建、测试集的预测和模型的验证,具体代码如下:

    # 拆分为训练集和测试集
    set.seed(1) index <- sample(1:nrow(df_dtm), size = 0.75*nrow(df_dtm)) train <- df_dtm[index,] test <- df_dtm[-index,]

    # 贝叶斯分类器
    bayes <- NaiveBayes(x = train, grouping = evaluation$Emotion[-idx][index], fL = 1)

    # 预测
    pred_bayes <- predict(bayes, newdata = test) Freq_bayes <- table(pred_bayes$class, evaluation$Emotion[-idx][-index])

    # 混淆矩阵
    Freq_bayes
    # 准确率
    sum(diag(Freq_bayes))/sum(Freq_bayes)

    #ROC曲线
    roc_bayes <- roc(evaluation$Emotion[-idx][-index],factor(pred_bayes$class,ordered = T)) Specificity <- roc_bayes$specificities Sensitivity <- roc_bayes$sensitivities

    # 绘制ROC曲线
    p <- ggplot(data = NULL, mapping = aes(x= 1-Specificity, y = Sensitivity)) p + geom_line(colour = 'red', size = 1) +  coord_cartesian(xlim = c(0,1), ylim = c(0,1)) +  geom_abline(intercept = 0, slope = 1)+  annotate('text', x = 0.5, y = 0.25, label=paste('AUC=',round(roc_curve$auc,2)))+  labs(x = '1-Specificity',y = 'Sensitivity', title = 'ROC Curve') +  theme(plot.title = element_text(hjust = 0.5, face = 'bold', colour = 'brown'))

    0?wx_fmt=png

    0?wx_fmt=png

    结果如上图所示,模型的准确率为77%(即混淆矩阵中主对角线数值之和除以4个元素之和);ROC曲线下的面积也达到了0.79(理想的AUC在0.8以上)。相对来说,模型的效果还是比较理想的。为了比较,我们再使用一个集成算法(随机森林),看看集成算法是否比单一的贝叶斯算法要好一些

    # 随机森林
    rf <- randomForest(x = train, y = evaluation$Emotion[-idx][index]) pred_rf <- predict(rf, newdata = test)

    # 混淆矩阵
    Freq_rf <- table(pred_rf,evaluation$Emotion[-idx][-index]) Freq_rf
    # 准确率
    sum(diag(Freq_rf))/sum(Freq_rf)

    #ROC曲线
    roc_rf <- roc(evaluation$Emotion[-idx][-index],factor(pred_rf,ordered = T)) Specificity <- roc_rf$specificities Sensitivity <- roc_rf$sensitivities

    # 绘制ROC曲线
    p <- ggplot(data = NULL, mapping = aes(x= 1-Specificity, y = Sensitivity)) p + geom_line(colour = 'red', size = 1) +  coord_cartesian(xlim = c(0,1), ylim = c(0,1)) +  geom_abline(intercept = 0, slope = 1)+  annotate('text', x = 0.5, y = 0.25, label=paste('AUC=',round(roc_rf$auc,2)))+  labs(x = '1-Specificity',y = 'Sensitivity', title = 'ROC Curve') +  theme(plot.title = element_text(hjust = 0.5, face = 'bold', colour = 'brown'))

    0?wx_fmt=png

    0?wx_fmt=png

    很显然,集成算法要比贝叶斯算法要优秀一些,模型的准确率超过80%,而且AUC值也达到了0.82。

    结语


          OK,关于使用R语言完成文本情感分类的实战我们就分享到这里,下一期,我将使用Python做一个对比。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。


    往期精彩内容整理合集:

    R语言中文社区历史文章整理(作者篇)

    R语言中文社区历史文章整理(类型篇)

    640?

    公众号后台回复关键字即可学习

    回复 R              R语言快速入门免费视频 
    回复 统计          统计方法及其在R中的实现
    回复 用户画像   民生银行客户画像搭建与应用 
    回复 大数据      大数据系列免费视频教程
    回复 可视化      利用R语言做数据可视化
    回复 数据挖掘   数据挖掘算法原理解释与应用
    回复 机器学习   R&Python机器学习入门 

    展开全文
  • 中文文本情感分类及情感分析资源大全

    万次阅读 多人点赞 2018-10-03 22:43:49
    本文主要是基于机器学习方法的中文文本情感分类,主要包括:使用开源的Markup处理程序对XML文件进行分析处理、中科院计算所开源的中文分词处理程序ICTCLAS对文本进行分词处理、去除停用词等文本预处理,在基于向量...
  • 文本情感分类

    千次阅读 2017-06-26 20:05:02
    电影文本情感分类 Github地址 Kaggle地址 这个任务主要是对电影评论文本进行情感分类,主要分为正面评论和负面评论,所以是一个二分类问题,二分类模型我们可以选取一些常见的模型比如贝叶斯、逻辑回归等,...
  • NLP:文本情感分析快速入门

    万次阅读 多人点赞 2018-08-03 17:59:47
    最近由中国计算机学会(CCF)主办,雷锋网,香港中文大学(深圳)承办的2018全球人工智能与机器人峰会...哈工大秦兵老师,秦老师多年从事自然语言处理的研究,获得国内第一个关于文本情感分析方面的自然科学基金重点...
  • NLP ---文本情感分析

    万次阅读 多人点赞 2019-01-03 10:34:46
    前面几节我们详细的研究了文本分析的相关算法,本节将简单介绍一下基于文本的情感分析方面的内容,本节更多是论述方面的内容,这个方向的算法基本都是我们前面...文本情感分析(Sentiment Analysis)是指利用自然语言...
  • 文本情感分类(一):传统模型

    万次阅读 2017-04-03 08:15:15
    基于传统的思路实现了一个简单的文本情感分类模型。随着学习的深入,并用深度学习的算法实现了文本情感分类模型。
  • 文本情感分类(一)

    千次阅读 2019-03-04 00:39:31
    基于情感词典的文本情感分类 古典文本分类的流程: 根据上图,我们可以通过以下几个步骤实现基于情感词典的文本情感分类: 1:预处理 2:分词 3:训练情感词典 4:判断。 以下主要分几个不追将上述...
  • pytorch-文本情感分类

    2020-02-25 10:28:42
    文本情感分类 文本分类是自然语言处理的一个常见任务,它把一段不定长的文本序列变换为文本的类别。本节关注它的一个子问题:使用文本情感分类来分析文本作者的情绪。这个问题也叫情感分析,并有着广泛的应用。 同...
  • 基于情感词典的文本情感分类

    千次阅读 2019-10-01 17:31:48
    基于情感词典的文本情感分类 传统的基于情感词典的文本情感分类,是对人的记忆和判断思维的最简单的模拟,如上图。我们首先通过学习来记忆一些基本词汇,如否定词语有“不”,积极词语有“喜欢”、“爱”,消极...
  • 基于情感词典的文本情感分类 传统的基于情感词典的文本情感分类,是对人的记忆和判断思维的最简单的模拟,如上图。我们首先通过学习来记忆一些基本词汇,如否定词语有“不”,积极词语有“喜欢”、“爱”,消极...
  • python 文本情感分类

    千次阅读 2017-06-21 21:07:03
    对于一个简单的文本情感分类来说,其实就是一个二分类,这篇博客主要讲述的是使用scikit-learn来做文本情感分类。分类主要分为两步:1)训练,主要根据训练集来学习分类模型的规则。2)分类,先用已知的测试集评估...
  • Pytorch深度学习(6) -- 文本情感分类 RNN1. 文本情感分类:使用循环神经网络1.1 文本情感分类数据1.1.1 读取数据1.1.2 预处理数据1.1.3 创建数据迭代器1.2 使用循环神经网络的模型1.2.1 加载预训练的词向量1.2.2 ...
  • 【干货】--基于Python的文本情感分类

    千次阅读 2018-01-15 09:37:20
    作者:刘顺祥个人微信公众号:每天进步一点点2015往期回顾:【干货】--手把手教你完成文本情感分类聊聊我的R语言学习路径和感受前言 在上一期《【干货】--手把手教你完成文本情感分类》中我们使用了R语言对酒店评论...
  • 在《文本情感分类(一):传统模型》一文中,笔者简单介绍了进行文本情感分类的传统思路。传统的思路简单易懂,而且稳定性也比较强,然而存在着两个难以克服的局限性:一、精度问题,传统思路差强人意,当然一般的...
  • Bert文本情感分类项目

    2020-07-15 21:20:20
    利用BERT进行中文文本情感分类,训练,测试和验证语句分别为5356,1000,1000条. 直接运行run_classifier.sh文件( --do_train=true \ --do_eval=true\ --do_predict=false \ ) 报错没找到数据包 解决:...
  • 基于朴素贝叶斯理论提出了一种新的中文文本情感分类方法。这种方法利用情感词典对文本进行处理和表示,基于朴素贝叶斯理论构建文本情感分类器,并以互联网上宾馆中文评论作为分类研究的对象。实验表明,使用提出的...
  • 本文主要是基于机器学习方法的中文文本情感分类,主要包括:使用开源的Markup处理程序对XML文件进行分析处理、中科院计算所开源的中文分词处理程序ICTCLAS对文本进行分词处理、去除停用词等文本预处理,在基于向量...
1 2 3 4 5 ... 20
收藏数 14,778
精华内容 5,911
热门标签
关键字:

文本情感分类