Kaggle关于IMDB情感分类

作者: 我的昵称违规了 | 来源:发表于2019-06-24 20:11 被阅读3次

    过去了17天,按照学习计划来说,已经严重超时了。
    主要的问题是在数据预处理部分。
    Kaggle的IMDB情感分析任务其实很简单,train文件用于训练,test文件用于测试。

    步骤

    1. 整合train和test(就是说所有语料库)生成词袋或词向量模型。也可以下载已有的word2vec或是glove词向量模型。
    2. 生成的词向量模型就是将每一个词向量化,方便后面的计算。依据生成的词向量模型对train和test语料进行向量化。
    3. 把向量化的train数据和标签输入分类模型中进行预测,完成模型训练。
    4. 评估模型,并对test进行预测。

    具体实现

    1. 数据集

    数据集是tsv格式数据,说白了是分成了5类:

    0 - negative
    1 - somewhat negative
    2 - neutral
    3 - somewhat positive
    4 - positive

    我们先读取一下看看。TSV文件和CSV的文件的区别是:前者使用\t作为分隔符,后者使用,作为分隔符。

    可以看到总共156060条记录,其中打2分的数据最多,说明大家都还是很中庸啊。

    import pandas as pd
    train_data=pd.read_csv(r'C:\Users\jwc19\Desktop\sentiment-analysis-on-movie-reviews\train.tsv',sep='\t',header=0)
    test_data=pd.read_csv(r'C:\Users\jwc19\Desktop\sentiment-analysis-on-movie-reviews\test.tsv',sep='\t',header=0)
    
    train_data.head()
    
    image.png
    train_data.info()
    
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 156060 entries, 0 to 156059
    Data columns (total 4 columns):
    PhraseId      156060 non-null int64
    SentenceId    156060 non-null int64
    Phrase        156060 non-null object
    Sentiment     156060 non-null int64
    dtypes: int64(3), object(1)
    memory usage: 4.8+ MB
    
    train_data.describe()
    
    image.png

    以上是数据的描述性统计结果,当然,还可以做一下可视化,这些参考kaggle的泰坦尼克号任务操作。

    2. 构建word2vec

    接下来是要对语料库向量化,这其实就是一种对文本特征的抽取。
    文中提到了两种方式:BOW(词袋)和Word2Vec,相比而言,Word2Vec所包含的信息更多,而且gensim库已经打包好了,在这里使用word2vec。

    在2017年新的特征抽取算法transformer将会横扫一切……

    在完成词向量抽取后,将进行分类器的训练。
    在这里,我们将train和test数据集进行合并,构造出一个维度为200的词向量模型,使用gensim库进行构建。

    # 合并test和train的数据,用于训练词向量模型
    newDf = pd.concat([test_data["Phrase"], train_data["Phrase"]], axis=0) 
    newDf.describe()
    newDf.to_csv(r"C:\Users\jwc19\Desktop\sentiment-analysis-on-movie-reviews\wordEmbdiing.txt", index=False)
    

    在这里使用gensim的word2vec api来训练模型

    主要参数介绍如下:

    1. sentences:我们要分析的语料,可以是一个列表,或者从文件中遍历读出(word2vec.LineSentence(filename) )。

    2. size:词向量的维度,默认值是100。这个维度的取值一般与我们的语料的大小相关,如果是不大的语料,比如小于100M的文本语料,则使用默认值一般就可以了。如果是超大的语料,建议增大维度。

    3. window:即词向量上下文最大距离,window越大,则和某一词较远的词也会产生上下文关系。默认值为5,在实际使用中,可以根据实际的需求来动态调整这个window的大小。如果是小语料则这个值可以设的更小。对于一般的语料这个值推荐在[5;10]之间。

    4. sg:即我们的word2vec两个模型的选择了。如果是0, 则是CBOW模型;是1则是Skip-Gram模型;默认是0即CBOW模型。

    5. hs:即我们的word2vec两个解法的选择了。如果是0, 则是Negative Sampling;是1的话并且负采样个数negative大于0, 则是Hierarchical Softmax。默认是0即Negative Sampling。

    6. negative:即使用Negative Sampling时负采样的个数,默认是5。推荐在[3,10]之间。这个参数在我们的算法原理篇中标记为neg。

    7. cbow_mean:仅用于CBOW在做投影的时候,为0,则算法中的xw为上下文的词向量之和,为1则为上下文的词向量的平均值。在我们的原理篇中,是按照词向量的平均值来描述的。个人比较喜欢用平均值来表示xw,默认值也是1,不推荐修改默认值。

    8. min_count:需要计算词向量的最小词频。这个值可以去掉一些很生僻的低频词,默认是5。如果是小语料,可以调低这个值。

    9. iter:随机梯度下降法中迭代的最大次数,默认是5。对于大语料,可以增大这个值。

    10. alpha:在随机梯度下降法中迭代的初始步长。算法原理篇中标记为η,默认是0.025。

    11. min_alpha: 由于算法支持在迭代的过程中逐渐减小步长,min_alpha给出了最小的迭代步。

    from nltk.corpus import stopwords
    StopWords = stopwords.words('english')
    
    import logging
    import gensim
    from gensim.models import word2vec
    # 设置输出日志
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    sentences=word2vec.LineSentence(r"C:\Users\jwc19\Desktop\sentiment-analysis-on-movie-reviews\wordEmbdiing.txt")
    sentences=list(sentences)
    for idx,sentence in enumerate(sentences):
        sentence = [w for w in sentence if w not in StopWords]
        sentences[idx]=sentence
    
    print(type(sentences))
    model=gensim.models.Word2Vec(sentences,size=200, min_count=2,sg=1,iter=2)
    model.wv.save_word2vec_format("./word2Vec02" + ".bin", binary=True) 
    

    搞定之后运行模型,还可以看看效果

    model=gensim.models.KeyedVectors.load_word2vec_format("word2Vec.bin",binary=True)
    model["flower"]
    
    array([-0.2378106 , -0.00272736,  0.31298155,  0.03572753, -0.32978794,
            0.5877859 ,  0.24954697,  0.10183911,  0.30661255,  0.280979  ,
            0.04722883, -0.01303975,  0.08539272,  0.04781984, -0.17838825,
            0.13571365, -0.07219279,  0.04345001, -0.10493791,  0.05438785,
            0.33817822,  0.15342301, -0.01376961,  0.5400121 ,  0.41749138,
            0.0906916 ,  0.04341062, -0.15571249, -0.17380357, -0.1934123 ,
           -0.02405222, -0.22066571, -0.14180358, -0.09150579, -0.2944634 ,
            0.07576216, -0.1660684 ,  0.20156585,  0.1215609 ,  0.5412449 ,
           -0.1711439 ,  0.3214155 , -0.3667486 , -0.18460636, -0.15220495,
           -0.07949002,  0.22074243, -0.04971108, -0.09505122,  0.29928744,
            0.03575212, -0.13769385,  0.18068919,  0.31546128,  0.10954601,
            0.18582347, -0.04675937, -0.03966061,  0.20546672, -0.04146346,
           -0.0196472 ,  0.0578943 ,  0.20681728, -0.04692319, -0.1698708 ,
           -0.09567603, -0.11117092,  0.30465436, -0.04794674, -0.06839596,
           -0.02868674, -0.20524485,  0.0295146 , -0.01159863, -0.15453497,
            0.48093846, -0.3897168 ,  0.02332748,  0.0439175 ,  0.23415217,
           -0.06639539, -0.03457333, -0.2735414 ,  0.03905383,  0.038656  ,
            0.23679397, -0.33047786,  0.31122783,  0.00199052, -0.30952674,
           -0.10884447, -0.40330866,  0.25768963, -0.16997696,  0.12618165,
           -0.08964632, -0.01782297,  0.12821278,  0.00424662, -0.11926408,
            0.04985361, -0.16177899, -0.06548072, -0.018849  ,  0.07923622,
           -0.00496559, -0.0372107 ,  0.05142358, -0.3297481 ,  0.23669559,
            0.16632096,  0.12055472,  0.36679494,  0.11643603,  0.05669545,
           -0.26389235, -0.06538889,  0.09600764, -0.15645082, -0.00284773,
            0.12941402,  0.08277974,  0.09082151, -0.12873018,  0.13429202,
           -0.00188877, -0.10478543,  0.20682792, -0.18579291, -0.18376978,
           -0.15438502,  0.6078415 , -0.05618986, -0.00372298, -0.34480548,
           -0.00986845,  0.20730568, -0.28601113,  0.08377945,  0.2517998 ,
            0.08157796,  0.24523894, -0.34019017,  0.10557748,  0.02105924,
            0.03729287, -0.52203006,  0.1191924 , -0.32391408, -0.25671792,
           -0.24574052,  0.21722569,  0.05409996, -0.1944298 ,  0.05195828,
           -0.30965397,  0.31671712,  0.23532335,  0.34292328, -0.04460131,
           -0.24952726,  0.1692848 , -0.2680034 , -0.20551267,  0.31070685,
           -0.01980814,  0.24538256,  0.11438795, -0.52290195, -0.25548056,
           -0.12335302, -0.32273138, -0.15207022,  0.03945559, -0.02261233,
           -0.11034735, -0.27235347, -0.17029978, -0.37533283, -0.0962036 ,
           -0.21412134, -0.04120854,  0.12733105, -0.22446166, -0.26129523,
           -0.01468701,  0.24803281,  0.0242933 ,  0.12278723, -0.06079411,
            0.14851114,  0.04741063, -0.16954847, -0.1654084 ,  0.3050954 ,
            0.0125294 , -0.03766926,  0.06326802, -0.11463621, -0.02890763],
          dtype=float32)
    

    到这里,word2vec的生成就已经搞定了。要感谢google的colab,替我节省了大量的时间,我用笔记本跑了4个小时的模型,在colab上只用了几分钟……
    接下来是将语料库进行向量化。我在这里卡了有一周,因为在生成word2vec的时候,会将频率低于2的低频词干掉,但是在语料库数据向量化的时候会遇到低频词未登记(UNK)的情况,怎么解决,查了很多材料。后来才发现,我特么傻了,在转换的时候直接写判断过滤掉不就行了……

    import logging
    import gensim
    from gensim.models import word2vec
    model=gensim.models.KeyedVectors.load_word2vec_format("./sample_data/word2Vec03.bin",binary=True)
    
    index2word=model.index2word
    print(len(index2word))
    index2word_set=set(model.index2word)
    print(len(index2word_set))
    print(model)
    
    # text是输入的已经分好词的语料库文本
    # model是之前生成的word2vec模型
    # num_features是word2vec模型中每个词维度大小,这里是200
    def word2vec(text,model,num_features):
        featureVec = np.zeros((200,),dtype="float32")
        nwords=0
        for word in text:
            if word in index2word_set:
                nwords+=1
                featureVec=np.add(featureVec,model[word])
        featureVec = np.divide(featureVec,nwords)
        return featureVec
    # print(word2vec(token))
    def getAvgFeatureVecs(phrases,model,num_features):
        counter=0
        phraseFeatureVecs = np.zeros((len(phrases),num_features),dtype="float32")
        for phrase in phrases:
            if counter % 2000==0:
                print("Phrase %d of %d" % (counter, len(phrases)))
            phraseFeatureVecs[counter]=word2vec(phrase, model, num_features)
            counter = counter+1
        return phraseFeatureVecs
    
    from nltk.corpus import stopwords
    import re
    def phrase_to_wordlist(phrase, remove_stopwords=False):
        phrase_text = re.sub("[^a-zA-Z]"," ", phrase)
        words = phrase_text.lower().split()
        if remove_stopwords:
            stops = set(stopwords.words("english"))
            words = [w for w in words if not w in stops]
        return(words)
    
    clean_train_phrases = []
    for phrase in train_data["Phrase"]:
        clean_train_phrases.append( phrase_to_wordlist( phrase, remove_stopwords=True ))
        
    num_features=200
    trainDataVecs = getAvgFeatureVecs( clean_train_phrases, model, num_features )
    
    
    clean_test_phrases = []
    for phrase in test_data["Phrase"]:
        clean_test_phrases.append( phrase_to_wordlist( phrase, remove_stopwords=True ))
        
    num_features=200
    testDataVecs = getAvgFeatureVecs( clean_test_phrases, model, num_features )
    

    现在好了吧,可以送进去训练了吧。
    但是……又遇到问题了,在使用sklearn训练的时候报错

    ValueError: Input contains NaN, infinity or a value too large for dtype('float32').

    原因是我们在做语料库向量化处理的时候有一些无意义的评论,所包含的内容都在停用词之中,向量化之后就变成了空值,所以,向量化之后还需要对数据值进行空值检验,将其中为空的向量指定一个缺省值。我在这里省事就指定为0了

    trainDataVecs[np.isnan(trainDataVecs)] = 0
    testDataVecs[np.isnan(testDataVecs)] = 0
    
    from sklearn.ensemble import RandomForestClassifier
    forest = RandomForestClassifier( n_estimators = 100 )
    
    print ("Fitting a random forest to labeled training data...")
    forest = forest.fit( trainDataVecs, train["Sentiment"] )
    

    训练后进行预测,输出预测结果

    # Test & extract results 
    result = forest.predict( testDataVecs )
    
    # Write the test results 
    output = pd.DataFrame( data={"id":test["PhraseId"], "sentiment":result} )
    output.to_csv( "Word2Vec_AverageVectors.csv", index=False, quoting=3 )
    

    到这里大致就完成了,但是,我们希望使用RNN来处理,接下来就是构建LSTM作为分类器。

    相关文章

      网友评论

        本文标题:Kaggle关于IMDB情感分类

        本文链接:https://www.haomeiwen.com/subject/rthaqctx.html