美文网首页
使用kears分析中文酒店评论(肯定和否定),基于CNN和RNN

使用kears分析中文酒店评论(肯定和否定),基于CNN和RNN

作者: smallcui | 来源:发表于2018-12-15 23:54 被阅读0次

    下载清华大学的宾馆评论数据集

    from tensorflow import keras
    import os
    # 自动解压,新建review_sentiment目录
    path = keras.utils.get_file('review_sentiment.v1.tgz', origin='http://nlp.csai.tsinghua.edu.cn/~lj/review_sentiment.v1.tgz',cache_subdir='review_sentiment',extract='true')
    
    pre_path=os.path.split(path)[0] 
    # 得到上级目录
    print(pre_path)
    # 打印文件结构
    print(os.listdir(pre_path))
    
    /root/.keras/review_sentiment
    ['review_sentiment.v1.tgz', 'train2', 'test2', 'train2.list', 'train2.rlabelclass', 'test2.list', 'test2.rlabelclass', 'readme.txt', 'readme.cn.txt']
    

    处理数据文本文件

    import os
    import numpy as np
    thu1 = thulac.thulac(seg_only=True)
    
    max_lenth=0
    def get_data(dir,label_file):
        x=[]
        y=[]
        dir=os.path.join(pre_path,dir)
        label_file=os.path.join(pre_path,label_file)
    
        dic={}# 文件名所对应的label 词典
        f = open(label_file,'r+')
        for line in f:
            (key,value) = line.strip().split(' ')
            dic[key] = value
        f.close()
        
        for fname in os.listdir(dir):
            if fname[-4:]=='.txt':
                try:
                    with open(os.path.join(dir,fname), encoding='gbk') as f:
                        text = thu1.cut(f.read())  #因为中文和英文有区别,需要进行分词,我使用的是清华大学的thu1,可以使用pip install thu1 安装
                        text=' '.join(np.asarray(text)[:,0:1].reshape(-1))
                        x.append(text)
                        if dic[fname]=='+1':
                            y.append(1)
                        else:
                            y.append(0)
                        f.close()
                except:
                    print(fname,'有问题')
        return x,y
        
    train_x,train_y=get_data('train2','train2.rlabelclass')
    test_x,test_y=get_data('test2','test2.rlabelclass')  
    train_y=np.asarray(train_y)
    test_y=np.asarray(test_y)
    print('len(test_x)',len(test_x))
    print('len(train_x)',len(train_x))
    
    
                
    
    Model loaded succeed
    56958_helen1970_2005-7-22_1.3.txt 有问题
    51254_31801272_2006-9-15_1.5.txt 有问题
    78674_hupu1128_2005-6-2_1.5.txt 有问题
    23733_clcsandy_2006-10-7_1.8.txt 有问题
    len(test_x) 4000
    len(train_x) 11996
    

    查看分词过的数据

    print(train_x[100],train_y[100])
    print(train_x[6000],train_y[6000])
    
    
    我 觉得 大观园 挺 好 的 , 首先 是 房间 好 , 床 挺 舒适 的 。 最 好 的 就 是 可以 免费 游园 , 还 能 免费 游泳 , 不 过 游泳 时 一定 要 带 浴帽 不 太 符合 中国 国情 。 
                                       1
    我 带 外宾 入 住 , 外宾 说 脏 , 有 女人 头发 , 喷头 掉 地上 等 , 换 到 西苑饭店 
                                       0
    

    将数据转成向量

    from keras.preprocessing.text import Tokenizer
    from keras.preprocessing.sequence import pad_sequences
    maxlen=200# 200汉字后截断
    max_words=5000 # 只考虑前10000个汉字
    
    tokenizer=Tokenizer(num_words=max_words,filters=',!。!"#$%&()*+,-./:;<=>?@[\]^_`{|}~\t\n')
    tokenizer.fit_on_texts(train_x)
    train_sequences=tokenizer.texts_to_sequences(train_x)
    test_sequences=tokenizer.texts_to_sequences(test_x)
    
    train_xx=pad_sequences(train_sequences,maxlen=200)
    test_xx=pad_sequences(test_sequences,maxlen=200)
    
    

    查看向量数据

    print(train_xx[100],train_y[100])
    print(train_xx[6000],train_y[6000])
    
    
    [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    5  195  255   10
        1  740    3    8   10  102  255  283    1   56   10    1   15    3
       42  134   18   48  134 1813    2   37 1813   85  244   22  272 4587
        2   34 1028  698] 1
    [   0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    0    0    0    0    0    0    0    0    0    0    0    0    0
        0    5  272 1385   53    9 1385   26  214   14 1838 1325 2438  445
     1170  125  138   20] 0
    

    创建模型(使用CNN和RNN)

    from tensorflow.python.keras import Sequential
    from tensorflow.python.keras.preprocessing import sequence
    from tensorflow.keras.datasets import imdb
    from tensorflow.keras import layers
    from tensorflow import keras
    from tensorflow.python.keras.utils import multi_gpu_model
    
    model = Sequential([
       layers.Embedding(5000, 128, input_length=maxlen),
        layers.Conv1D(32, 7, activation='relu'),
        layers.MaxPool1D(5),
        layers.Conv1D(32, 7, activation='relu'),
        layers.GRU(32,dropout=0.1,recurrent_dropout=0.5),
        layers.Dense(1, activation='sigmoid')
    ])
    model.summary()
    
    
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    embedding_39 (Embedding)     (None, 200, 128)          640000    
    _________________________________________________________________
    conv1d_51 (Conv1D)           (None, 194, 32)           28704     
    _________________________________________________________________
    max_pooling1d_25 (MaxPooling (None, 38, 32)            0         
    _________________________________________________________________
    conv1d_52 (Conv1D)           (None, 32, 32)            7200      
    _________________________________________________________________
    gru_14 (GRU)                 (None, 32)                6240      
    _________________________________________________________________
    dense_41 (Dense)             (None, 1)                 33        
    =================================================================
    Total params: 682,177
    Trainable params: 682,177
    Non-trainable params: 0
    _________________________________________________________________
    

    训练模型

    
    model.compile(optimizer=keras.optimizers.Adam(), loss='binary_crossentropy', metrics=['acc'])
    history = model.fit(train_xx, train_y, epochs=20, batch_size=128, validation_data=(test_xx,test_y),shuffle=True)
    
    
    
    /usr/lib/python3.6/site-packages/tensorflow/python/ops/gradients_impl.py:100: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.
      "Converting sparse IndexedSlices to a dense Tensor of unknown shape. "
    
    
    Train on 11996 samples, validate on 4000 samples
    Epoch 1/20
    11996/11996 [==============================] - 10s 835us/step - loss: 0.6656 - acc: 0.6062 - val_loss: 0.6899 - val_acc: 0.5767
    Epoch 2/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.5150 - acc: 0.7519 - val_loss: 0.4344 - val_acc: 0.8015
    Epoch 3/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.2847 - acc: 0.8781 - val_loss: 0.3883 - val_acc: 0.8282
    Epoch 4/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.1947 - acc: 0.9231 - val_loss: 0.4066 - val_acc: 0.8323
    Epoch 5/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.1442 - acc: 0.9458 - val_loss: 0.3524 - val_acc: 0.8622
    Epoch 6/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.1225 - acc: 0.9520 - val_loss: 0.3714 - val_acc: 0.8587
    Epoch 7/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.1048 - acc: 0.9592 - val_loss: 0.3849 - val_acc: 0.8635
    Epoch 8/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0895 - acc: 0.9648 - val_loss: 0.4006 - val_acc: 0.8628
    Epoch 9/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0738 - acc: 0.9702 - val_loss: 0.4215 - val_acc: 0.8645
    Epoch 10/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0567 - acc: 0.9784 - val_loss: 0.4656 - val_acc: 0.8572
    Epoch 11/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.0487 - acc: 0.9802 - val_loss: 0.5072 - val_acc: 0.8605
    Epoch 12/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.1366 - acc: 0.9488 - val_loss: 0.4496 - val_acc: 0.8602
    Epoch 13/20
    11996/11996 [==============================] - 5s 385us/step - loss: 0.0462 - acc: 0.9813 - val_loss: 0.5016 - val_acc: 0.8587
    Epoch 14/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.0369 - acc: 0.9837 - val_loss: 0.5263 - val_acc: 0.8583
    Epoch 15/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.0326 - acc: 0.9852 - val_loss: 0.5504 - val_acc: 0.8622
    Epoch 16/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0304 - acc: 0.9864 - val_loss: 0.5893 - val_acc: 0.8568
    Epoch 17/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0401 - acc: 0.9810 - val_loss: 0.6242 - val_acc: 0.8480
    Epoch 18/20
    11996/11996 [==============================] - 5s 384us/step - loss: 0.0289 - acc: 0.9861 - val_loss: 0.6144 - val_acc: 0.8558
    Epoch 19/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.0266 - acc: 0.9872 - val_loss: 0.6810 - val_acc: 0.8525
    Epoch 20/20
    11996/11996 [==============================] - 5s 383us/step - loss: 0.0241 - acc: 0.9882 - val_loss: 0.6731 - val_acc: 0.8522
    

    查看错误的预测

    predict_y=np.max(model.predict_classes(test_xx),axis=1)
    
    
    result=np.equal(predict_y,test_y)
    
    index_wrong=np.where(result==False)
    
    wrong_text=np.asarray(test_x)[index_wrong]
    wrong_predict_y=predict_y[index_wrong]
    wrong_test_y=test_y[index_wrong]
    dict_label={0:'否定',1:'肯定'}
    
    for wt,wpy,wty in zip(wrong_text[0:10],wrong_predict_y[0:10],wrong_test_y[0:10]):
        print(wt.strip().replace(' ',''),'\t\t预测:'+dict_label[wpy],'实际:'+dict_label[wty])
    
    
    
    什么都好,就是凌晨5店多有骚扰电话吃不消。希望酒店加强管理。给客人一个清静的休息环境。顺便提一下,健身房一流!         预测:否定 实际:肯定
    有一点意见大堂总是有饭菜味道,五星级酒店不应该.        预测:否定 实际:肯定
    位置绝佳,房间再精雕细刻一些就更好了,大小合适,床也够大.       预测:否定 实际:肯定
    如果所有员工都面带微笑会更加理想.       预测:否定 实际:肯定
    房间还行,价格一般,早餐不错,希望提高服务质量         预测:否定 实际:肯定
    酒店不错,就是设施陈旧了点,服务还可以,房间很大~~      预测:否定 实际:肯定
    世界各地喜来登也住了不少,这所座落在苏州的具有园林特色的酒店让人耳目一新。酒店大堂里现场民乐show很有特色,唯有的两个小缺憾:1.挺有名气的自助餐厅吃的那叫啥?!完全和昂贵的价格不符。2.房间内设备略显陈旧。
    BTW:前台周小姐是我所入住过的世界各地所有酒店里态度最好,笑容最甜美的服务人员。       预测:否定 实际:肯定
    迎宾楼好像重新装修过了,环境不错。房间居然还有一台电脑,只不过屏幕是CRT的,不是液晶,相对瘦型的主机来讲,好像头大身子小的大头娃娃。网络速度还算是不错的,只是安装的软件全都太老了,无法直接使用,而且机器采用无盘工作站的方式,安装的是WINME操作系统,不算太好用,打游戏或者做做字处理工作,配合U盘还算不错了。至于酒店各部门服务人员的态度还算不错,够5星水准了。      预测:否定 实际:肯定
    可能是温州最好的酒店。服务比较规范。中餐厅不错。        预测:否定 实际:肯定
    前台小姑娘服务很好,会和客人小聊几句,不刻板很人性化。
    行李员服务到位,解释送地图很快捷,金钥匙水平;但是一次坐出租车晚上回来,司机停车不当上了逆行,一个门僮小伙子直接用力敲击前窗,让人恼火;客人坐在里面,不尊重出租车也要尊重客人。
    装潢显旧了(不知“2005装修”在哪里),电梯里面干净就是视觉乱七八糟。房间设施还可以。
    早餐92元,现优惠60元,基本可以。
    位置优势明显,海景、情侣大道。价格可以接收。
    补充点评2007年1月11日:补充:浴室卫生纸架太靠后,取用不方便。      预测:否定 实际:肯定
    

    后记

    1. 使用一维的卷积很快,笔者显卡gtx 750ti,运行起来也很快速
    2. 预测错误的数据,观察得知大部分,是因为评论中说了不好的,也说的好的,其实这些分类可以归为新的分类
    3. 如果不使用分词工具分词话,正确率不会很高,先分词,然后用空格分隔,这样就和英文单词一样了,就可以参考imdb数据了

    相关文章

      网友评论

          本文标题:使用kears分析中文酒店评论(肯定和否定),基于CNN和RNN

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