《学术小白的实战之路》01 LDA-Word2Vec-TF-IDF组合特征的机器学习情感分类模型研究

书山有路勤为径,学海无涯苦作舟

三更灯火五更鸡,正是男儿读书时

一、传统的机器学习分类模型

1.1 对文本的数据进行分词

数据样式
《学术小白的实战之路》01 LDA-Word2Vec-TF-IDF组合特征的机器学习情感分类模型研究_第1张图片

自定义分词词典、去除停用词,分词

#--------------------------------------------------已经分好词就不需要这个----------------------------------------

# -*- coding:utf-8 -*-
import csv
import pandas as pd
import numpy as np
import jieba
import jieba.analyse

#添加自定义词典和停用词典
jieba.load_userdict("user_dict.txt")
stop_list = pd.read_csv('stop_words.txt',
                        engine='python',
                        encoding='utf-8',
                        delimiter="\n",
                        names=['t'])['t'].tolist()

#中文分词函数
def txt_cut(juzi):
    return [w for w in jieba.lcut(juzi) if w not in stop_list and len(w) >1]

写入分词结果到新的文件

#写入分词结果到新的文件
fw = open('hotel_fenci_data.csv', "a+", newline = '',encoding = 'gb18030')
writer = csv.writer(fw)  
writer.writerow(['content','label'])

读取原始文件

# 使用csv.DictReader读取文件中的信息
labels = []
contents = []
file = r"C:\Users\N\Desktop\hotel_data.csv"
with open(file, "r", encoding="UTF-8") as f:
    reader = csv.DictReader(f)
    for row in reader:
        # 数据元素获取
        content = row['content']
        seglist = txt_cut(content)
        output = ' '.join(list(seglist))            #空格拼接
        contents.append(output)
        
        #文件写入
        tlist = []
        tlist.append(row['label'])
        tlist.append(output)
        writer.writerow(tlist)

fw.close()

1.2 构建文本矩阵

读取文件

# -*- coding:utf-8 -*-
import csv
import pandas as pd
import numpy as np
import jieba
import jieba.analyse
from scipy.sparse import coo_matrix
from sklearn import feature_extraction  
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

#----------------------------------第一步 读取文件--------------------------------
with open('hotel_fenci_data.csv', 'r', encoding='UTF-8-sig') as f:
    reader = csv.DictReader(f)
    labels = []
    contents = []
    for row in reader:
        labels.append(row['label']) #0-好评 1-差评
        contents.append(row['content'])

print(labels[:5])
print(contents[:5])

[‘0’, ‘0’, ‘0’, ‘0’, ‘0’]
['21 提交 订单 26 朋友 先行 到达 酒店 人中 一位 未带 有效证件 前台 足足 小时 解决 前台 7.25 接到 公安局 通知 每位 住店 客人 提供 证件 奥运 期间 公安部门 提出 中国 公民 配合 无可厚非 酒店 几个 作法 实在 无法忍受 25 日晚 致电 酒店 酒店 提醒 提交 订单 近一 星期 未有 酒店 携程 事前 通知 朋友 足足 小时 赶到 酒店 小时 只顾 客人 办理手续 提供 解决 方法 号称 星级 酒店 事件 自始至终 前台 人员 笑脸 错全 客人 号称 国际 接轨 星级 酒店 培训 员工 酒店 提供 公安部门 下发 相关 文件 前台 人员 回答 公安部门 电话 下达 酒店 文件 一名 常识 公民 当今 信息化 时代 政府部门 信息 公开 原则 若真 诸如此类 文件 下达 正规 操作 怀疑 酒店 说法 酒店 交涉 酒店 人员 蛮横 回答 接待 实在 半岛 品牌 规范 信誉度 感到 震惊 室外 高达 40 多度 高温 驱车 半小时 到达 酒店 半岛 集团 酒店 客人 得知 半岛 盗用 香港 半岛 名称 香港 半岛 酒店 管理 集团 得知 李鬼 兄弟会 做何 感想 工商管理 部门 水准 团队 享有盛名 半岛 品牌 期间 一位 身着 经理 服装 女士 接待 号称 请示 上级 请示 15 20 分钟 这位 经理 级别 更有甚者 此位 经理 出言不逊 出门 证件 常识 斗胆 一句 信息 提前 公开 告知 常识 常识 常识 客人 不配 入住 高贵 酒店 客人 尊重 客人 人格 侮辱 息事宁人 态度 提出 上海 证件 传真 酒店 酒店 先行 办理 checkin 手续 前台 出尔反尔 一会 一会 不行 态度强硬 情况 足足 小时 这群 饥肠辘辘 客人 checkin 手续 办完 只能 房间 房间 打扫 时间 中午 12 35 国际 管理 当天 客人 入住 最晚 12 实在 对此 酒店 服务水平 怀疑 预定 泳池 湖景房 看不到 湖景 从何而来 10 凌晨 45 男客人 泳池 游泳 影响 根本无法 入睡 酒店 竟无一人 前去 劝阻 归于 种种 细节 叙述 真诚 携程网 提出 建议 此种 水准 酒店 推荐 客人 遭受 折磨 有损 网站 声誉 补充 点评 2008 酒店 不负责任 缺乏 诚意 反馈 实在 有愧 挂出 六星 标志 赞同 楼上 朋友 点评 对不起 这六星 这家 酒店 管理 希望 下次 新面貌 酒店 承认 25 接到 公安部门 通知 给予 携程网 客服 人员 26 上午 收到 通知 信息 欺骗 公众 酒店 生存 酒店 调出 当日 录像 资料 公司 高层 好好 学学 微笑 好好 培训 前台 前台 脸上 笑容 明明 朋友 提出 传真 身份证件 前台 一会 一会 证件 酒店 接待 酒店 总经理 事情 只好 感谢 酒店 总经理 真诚 服务 酒店 尊重 公安部门 公安部门 国家 执法机关 规范 严谨 承认 接到 指示 入住 酒店 客人 出示 身份证 登记 酒店 相关 工作人员 住店 当事人 做出 特别 时期 严肃 处罚 书名号 公安部门 发文 酒店 自圆其说 自始至终 那位 前台 小姐 接待 酒店 前台 员工 从何而来 承认 1881 半岛 半岛 加个 1881 香港 九龙 半岛 酒店 一脉

清洗数据

# 清洗数据
import  re

pattern = re.compile('[0-9a-zA-Z’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+')
clearn_data = []
for content in contents:
    temp_data = re.sub(pattern,'',content)
    print(temp_data)
    clearn_data.append(temp_data)

提交 订单 朋友 先行 到达 酒店 人中 一位 未带 有效证件 前台 足足 小时 解决 前台 接到 公安局 通知 每位 住店 客人 提供 证件 奥运 期间 公安部门 提出 中国 公民 配合 无可厚非 酒店 几个 作法 实在 无法忍受 日晚 致电 酒店 酒店 提醒 提交 订单 近一 星期 未有 酒店 携程 事前 通知 朋友 足足 小时 赶到 酒店 小时 只顾 客人 办理手续 提供 解决 方法 号称 星级 酒店 事件 自始至终 前台 人员 笑脸 错全 客人 号称 国际 接轨 星级 酒店 培训 员工 酒店 提供 公安部门 下发 相关 文件 前台 人员 回答 公安部门 电话 下达 酒店 文件 一名 常识 公民 当今 信息化 时代 政府部门 信息 公开 原则 若真 诸如此类 文件 下达 正规 操作 怀疑 酒店 说法 酒店 交涉 酒店 人员 蛮横 回答 接待 实在 半岛 品牌 规范 信誉度 感到 震惊 室外 高达 多度 高温 驱车 半小时 到达 酒店 半岛 集团 酒店 客人 得知 半岛 盗用 香港 半岛 名称 香港 半岛 酒店 管理 集团 得知 李鬼 兄弟会 做何 感想 工商管理 部门 水准 团队 享有盛名 半岛 品牌 期间 一位 身着 经理 服装 女士 接待 号称 请示 上级 请示 分钟 这位 经理 级别 更有甚者 此位 经理 出言不逊 出门 证件 常识 斗胆 一句 信息 提前 公开 告知 常识 常识 常识 客人 不配 入住 高贵 酒店 客人 尊重 客人 人格 侮辱 息事宁人 态度 提出 上海 证件 传真 酒店 酒店 先行 办理 手续 前台 出尔反尔 一会 一会 不行 态度强硬 情况 足足 小时 这群 饥肠辘辘 客人 手续 办完 只能 房间 房间 打扫 时间 中午 国际 管理 当天 客人 入住 最晚 实在 对此 酒店 服务水平 怀疑 预定 泳池 湖景房 看不到 湖景 从何而来 凌晨 男客人 泳池 游泳 影响 根本无法 入睡 酒店 竟无一人 前去 劝阻 归于 种种 细节 叙述 真诚 携程网 提出 建议 此种 水准 酒店 推荐 客人 遭受 折磨 有损 网站 声誉 补充 点评 酒店 不负责任 缺乏 诚意 反馈 实在 有愧 挂出 六星 标志 赞同 楼上 朋友 点评 对不起 这六星 这家 酒店 管理 希望 下次 新面貌 酒店 承认 接到 公安部门 通知 给予 携程网 客服 人员 上午 收到 通知 信息 欺骗 公众 酒店 生存 酒店 调出 当日 录像 资料 公司 高层 好好 学学 微笑 好好 培训 前台 前台 脸上 笑容 明明 朋友 提出 传真 身份证件 前台 一会 一会 证件 酒店 接待 酒店 总经理 事情 只好 感谢 酒店 总经理 真诚 服务 酒店 尊重 公安部门 公安部门 国家 执法机关 规范 严谨 承认 接到 指示 入住 酒店 客人 出示 身份证 登记 酒店 相关 工作人员 住店 当事人 做出 特别 时期 严肃 处罚 书名号 公安部门 发文 酒店 自圆其说 自始至终 那位 前台 小姐 接待 酒店 前台 员工 从何而来 承认 半岛 半岛 加个 香港 九龙 半岛 酒店 一脉相传 酒店 尊重 客人 指责 客人 尊重 酒店 酒店 真诚 反馈 只好 真诚 回复 酒店 再也不会 享用 酒店 六星 服务 奉劝 酒店 诚信 生存 切记 宾馆 反馈 入住 出示 身份证 登记 情况 酒店 查看 当日 录像 全过程 当事人 调查 奥运会 开幕 确保 奥运会 全国 平安 公安部门 紧急 指示 入住 酒店 客人 出示 身份证 登记 酒店 相关 工作人员 住店 当事人 做出 特别 时期 严肃 处罚 提出 意见 酒店 慎重 做出 答复 公安部门 出示 住店 客人 身份证 登记 紧急 指示 公民 入住 酒店 携带 身份证 这一 常识 公安部门 发文 希望 懂得 朋友 进店 手续 办好 分钟 等待 小时 不符 尊重 客人 朋友 大堂 吵闹 前台 员工 礼貌 地为 住店 客人 快速 办理 无锡 半岛 酒店 隶属 香港 半岛 酒店 集团公司 声明 半岛 酒店 极少 客人 尊重 目的 更好 尊重 服务 客人 客人 提供 更好 高品质 服务 环境 相关 经理 解决问题 协调 分钟 过程 解决 尊重 谈不上 出言不逊 酒店 零距离 泳池 入住 前一天 客满 预定 房间 前日 客人 退房 入住 半岛 酒店 客人 享有 住房 保留 退房 权利 提供 到来 提前 住店 客人 推至 门外 国际惯例 公开 公布 入住 时间 酒店 尊重 遵守 惯例 诽谤 诬蔑 不道德 半岛 酒店 零距离 泳池 透过 泳池 清晰 全湖景 特色 客房 游泳池 相连 国内 前卫 设计 理念 凌晨 客人 游泳 调查 位住 泳池 醉酒 客人 酒店 时间 游泳 不到 分钟 保安 劝慰 回房 深表遗憾 补充 点评 做出 反馈 酒店 实行 不卑不亢 微笑服务 标准 深知 微笑服务 重要性 微笑 只会 给予 值得尊重 客人 奥运会 期间 严格执行 公安部门 指示 希望 文字游戏 书名号 跟上 奥运 步伐 时期 出示 身份证 重要性 真诚 保护 一位 素质 品味 客人 提供 舒适 服务 环境

构建TFIDF文本矩阵

#----------------------------------第二步 数据预处理--------------------------------
#将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
vectorizer = CountVectorizer()

#该类会统计每个词语的tf-idf权值
transformer = TfidfTransformer()

#第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(vectorizer.fit_transform(clearn_data))
# for n in tfidf[:5]:
#     print(n)
# print(type(tfidf))

# 获取词袋模型中的所有词语  
word = vectorizer.get_feature_names()
for n in word[:10]:
    print(n)
print("单词数量:", len(set(word)))

#将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
#X = tfidf.toarray()
X = coo_matrix(tfidf, dtype=np.float32).toarray() #稀疏矩阵 注意float

一一列举
一丁点
一上
一下下
一下床
一下肚子
一不小心
一不留神
一丝
一两
单词数量: 23557

1.3 机器学习情感分类

数据划分(如果x和y没有一一对应会报错)

from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn import svm
from sklearn import neighbors
from sklearn.naive_bayes import MultinomialNB


#----------------------------------第三步 数据划分--------------------------------
#使用 train_test_split 分割 X y 列表
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, 
                                                    labels, 
                                                    test_size=0.3, 
                                                    )

逻辑回归分类方法模型

#--------------------------------第四步 机器学习分类--------------------------------
# 逻辑回归分类方法模型
LR = LogisticRegression(solver='liblinear')
LR.fit(X_train, y_train)
print('模型的准确度:{}'.format(LR.score(X_test, y_test)))
pre = LR.predict(X_test)
print("逻辑回归分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
print("\n")

模型的准确度:0.86
逻辑回归分类
1200 1200
precision recall f1-score support

       0       0.83      0.89      0.86       579
       1       0.89      0.83      0.86       621
accuracy                           0.86      1200
macro avg       0.86      0.86      0.86      1200
weighted avg       0.86      0.86      0.86      1200

结果评价

#----------------------------------第五步 评价结果--------------------------------
def classification_pj(name, y_test, pre):
    print("算法评价:", name)
    
    # 正确率 Precision = 正确识别的个体总数 /  识别出的个体总数
    # 召回率 Recall = 正确识别的个体总数 /  测试集中存在的个体总数
    # F值 F-measure = 正确率 * 召回率 * 2 / (正确率 + 召回率)

    YC_B, YC_G = 0,0  #预测 bad good
    ZQ_B, ZQ_G = 0,0  #正确
    CZ_B, CZ_G = 0,0  #存在

    #0-good 1-bad 同时计算防止类标变化
    i = 0
    while i<len(pre):
        z = int(y_test[i])   #真实 
        y = int(pre[i])      #预测

        if z==0:
            CZ_G += 1
        else:
            CZ_B += 1
            
        if y==0:
            YC_G += 1
        else:
            YC_B += 1

        if z==y and z==0 and y==0:
            ZQ_G += 1
        elif z==y and z==1 and y==1:
            ZQ_B += 1
        i = i + 1

    print(ZQ_B, ZQ_G, YC_B, YC_G, CZ_B, CZ_G)
    print("")

    # 结果输出
    P_G = ZQ_G * 1.0 / YC_G
    P_B = ZQ_B * 1.0 / YC_B
    print("Precision Good 0:", P_G)
    print("Precision Bad 1:", P_B)

    R_G = ZQ_G * 1.0 / CZ_G
    R_B = ZQ_B * 1.0 / CZ_B
    print("Recall Good 0:", R_G)
    print("Recall Bad 1:", R_B)

    F_G = 2 * P_G * R_G / (P_G + R_G)
    F_B = 2 * P_B * R_B / (P_B + R_B)
    print("F-measure Good 0:", F_G)
    print("F-measure Bad 1:", F_B)

#函数调用
classification_pj("LogisticRegression", y_test, pre)

算法评价: LogisticRegression
495 549 556 644 590 610

Precision Good 0: 0.8524844720496895
Precision Bad 1: 0.8902877697841727
Recall Good 0: 0.9
Recall Bad 1: 0.8389830508474576
F-measure Good 0: 0.8755980861244019
F-measure Bad 1: 0.8638743455497382

随机森林

# 随机森林分类方法模型 n_estimators:森林中树的数量
clf = RandomForestClassifier(n_estimators=20)
clf.fit(X_train, y_train)
print('模型的准确度:{}'.format(clf.score(X_test, y_test)))
print("\n")
pre = clf.predict(X_test)
print('预测结果:', pre[:10])
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("RandomForest", y_test, pre)
print("\n")

SVM

# SVM分类方法模型
SVM = svm.LinearSVC() #支持向量机分类器LinearSVC
SVM.fit(X_train, y_train)
print('模型的准确度:{}'.format(SVM.score(X_test, y_test)))
pre = SVM.predict(X_test)
print("支持向量机分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("LinearSVC", y_test, pre)
print("\n")

朴素贝叶斯

#朴素贝叶斯模型
nb = MultinomialNB()
nb.fit(X_train, y_train)
print('模型的准确度:{}'.format(nb.score(X_test, y_test)))
pre = nb.predict(X_test)
print("朴素贝叶斯分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("MultinomialNB", y_test, pre)
print("\n")

KNN

#最近邻算法
knn = neighbors.KNeighborsClassifier(n_neighbors=7) 
knn.fit(X_train, y_train)
print('模型的准确度:{}'.format(knn.score(X_test, y_test)))
pre = knn.predict(X_test)
print("最近邻分类")
print(classification_report(y_test, pre))
classification_pj("KNeighbors", y_test, pre)
print("\n")

决策树

#决策树算法
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)
print('模型的准确度:{}'.format(dtc.score(X_test, y_test)))
pre = dtc.predict(X_test)
print("决策树分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("DecisionTreeClassifier", y_test, pre)
print("\n")

SGD

#SGD分类模型
from sklearn.linear_model.stochastic_gradient import SGDClassifier
sgd = SGDClassifier()
sgd.fit(X_train, y_train)
print('模型的准确度:{}'.format(sgd.score(X_test, y_test)))
pre = sgd.predict(X_test)
print("SGD分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("SGDClassifier", y_test, pre)
print("\n")

MLP分类模型

from sklearn.neural_network.multilayer_perceptron import MLPClassifier
mlp = MLPClassifier()
mlp.fit(X_train, y_train)
print('模型的准确度:{}'.format(mlp.score(X_test, y_test)))
pre = mlp.predict(X_test)
print("MLP分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("MLPClassifier", y_test, pre)
print("\n")

GradientBoosting分类模型

from sklearn.ensemble import GradientBoostingClassifier
gb = GradientBoostingClassifier()
gb.fit(X_train, y_train)
print('模型的准确度:{}'.format(gb.score(X_test, y_test)))
pre = gb.predict(X_test)
print("GradientBoosting分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("GradientBoostingClassifier", y_test, pre)
print("\n")

AdaBoost分类模型

from sklearn.ensemble import AdaBoostClassifier
AdaBoost = AdaBoostClassifier()
AdaBoost.fit(X_train, y_train)
print('模型的准确度:{}'.format(AdaBoost.score(X_test, y_test)))
pre = AdaBoost.predict(X_test)
print("AdaBoost分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
classification_pj("AdaBoostClassifier", y_test, pre)
print("\n")

二、LDA -TFIDF特征下文本选择

2.1 主题数目确定

from gensim import corpora, models
 
def ldamodel(num_topics):
    cop = open(r'hotel_fenci_data2 - content.csv',encoding='utf-8')
 
 
    train = []
    for line in cop.readlines():
        line = [word.strip() for word in line.split(' ')]
        train.append(line)  # list of list 格式
 
    dictionary = corpora.Dictionary(train)
    corpus = [dictionary.doc2bow(text) for text in
              train]  # corpus里面的存储格式(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1)
    corpora.MmCorpus.serialize('corpus.mm', corpus)
    lda = models.LdaModel(corpus=corpus, id2word=dictionary, random_state=1,
                          num_topics=num_topics)  # random_state 等价于随机种子的random.seed(),使每次产生的主题一致
 
    topic_list = lda.print_topics(num_topics, 10)
    # print("主题的单词分布为:\n")
    # for topic in topic_list:
    #     print(topic)
    return lda,dictionary

import math
def perplexity(ldamodel, testset, dictionary, size_dictionary, num_topics):
    print('the info of this ldamodel: \n')
    print('num of topics: %s' % num_topics)
    prep = 0.0
    prob_doc_sum = 0.0
    topic_word_list = [] 
    for topic_id in range(num_topics):
        topic_word = ldamodel.show_topic(topic_id, size_dictionary)
        dic = {}
        for word, probability in topic_word:
            dic[word] = probability
        topic_word_list.append(dic)  
    doc_topics_ist = []  
    for doc in testset:
        doc_topics_ist.append(ldamodel.get_document_topics(doc, minimum_probability=0))
    testset_word_num = 0
    for i in range(len(testset)):
        prob_doc = 0.0  # the probablity of the doc
        doc = testset[i]
        doc_word_num = 0  
        for word_id, num in dict(doc).items():
            prob_word = 0.0  
            doc_word_num += num
            word = dictionary[word_id]
            for topic_id in range(num_topics):
                # cal p(w) : p(w) = sumz(p(z)*p(w|z))
                prob_topic = doc_topics_ist[i][topic_id][1]
                prob_topic_word = topic_word_list[topic_id][word]
                prob_word += prob_topic * prob_topic_word
            prob_doc += math.log(prob_word)  # p(d) = sum(log(p(w)))
        prob_doc_sum += prob_doc
        testset_word_num += doc_word_num
    prep = math.exp(-prob_doc_sum / testset_word_num)  # perplexity = exp(-sum(p(d)/sum(Nd))
    print("模型困惑度的值为 : %s" % prep)
    return prep

from gensim import corpora, models
import matplotlib.pyplot as plt
from matplotlib.pyplot import MultipleLocator

 
def graph_draw(topic, perplexity):  # 做主题数与困惑度的折线图
    x = topic
    y = perplexity
    plt.plot(x, y,color='c', linestyle='-',  marker='+',linewidth=2)
    
    x_major_locator=MultipleLocator(1)
    ax=plt.gca()
    #ax为两条坐标轴的实例
    ax.xaxis.set_major_locator(x_major_locator)
    plt.xlabel("Number of Topic")
    plt.ylabel("Perplexity")
    plt.savefig("主题数目.png",dpi=600)
    plt.show()

if __name__ == '__main__':
   for i in range(20,300,1): # 多少文档中抽取一篇(这里只是为了调试最优结果,可以直接设定不循环)
        print("抽样为"+str(i)+"时的perplexity")
        a=range(1,21,1) # 主题个数
        p=[]
        for num_topics in a:
 
            lda,dictionary =ldamodel(num_topics)
            corpus = corpora.MmCorpus('corpus.mm')
            testset = []
            for c in range(int(corpus.num_docs/i)):
                testset.append(corpus[c*i])
            prep = perplexity(lda, testset, dictionary, len(dictionary.keys()), num_topics)
            p.append(prep)
 
        graph_draw(a,p)

抽样为20时的perplexity
the info of this ldamodel:

num of topics: 1
模型困惑度的值为 : 997.5535012674661
the info of this ldamodel:

num of topics: 2
模型困惑度的值为 : 914.3620715395527
the info of this ldamodel:
《学术小白的实战之路》01 LDA-Word2Vec-TF-IDF组合特征的机器学习情感分类模型研究_第2张图片

2.2 构建LDA模型

#-------------------  第三步 计算TF-IDF值  --------------------- 
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer

#设置特征数
# n_features = 2000

tf_vectorizer = TfidfVectorizer(strip_accents = 'unicode',
#                                 max_features=n_features,
                                stop_words=['的','或','等','是','有','之','与','可以','还是','比较','这里',
                                            '一个','和','也','被','吗','于','中','最','但是','图片','大家',
                                            '一下','几天','200','还有','一看','300','50','哈哈哈哈',
                                             '“','”','。',',','?','、',';','怎么','本来','发现',
                                             'and','in','of','the','我们','一直','真的','18','一次',
                                           '了','有些','已经','不是','这么','一一','一天','这个','这种',
                                           '一种','位于','之一','天空','没有','很多','有点','什么','五个',
                                           '特别'],
                                max_df = 0.99,
                                min_df = 0.002) #去除文档内出现几率过大或过小的词汇
tf = tf_vectorizer.fit_transform(clearn_data)


from sklearn.decomposition import LatentDirichletAllocation

#设置主题数
n_topics = 6

lda = LatentDirichletAllocation(n_components=n_topics,
                                max_iter=100,
                                learning_method='online',
                                learning_offset=50,
                                random_state=0)
lda.fit(tf)
print(lda)

LatentDirichletAllocation(batch_size=128, doc_topic_prior=None,
evaluate_every=-1, learning_decay=0.7,
learning_method=‘online’, learning_offset=50,
max_doc_update_iter=100, max_iter=100,
mean_change_tol=0.001, n_components=2, n_jobs=None,
perp_tol=0.1, random_state=0, topic_word_prior=None,
total_samples=1000000.0, verbose=0)

主题-关键词分布

# 主题-关键词分布
def print_top_words(model, tf_feature_names, n_top_words):
    for topic_idx, topic in enumerate(model.components_):  # lda.component相当于model.topic_word_
        print('Topic #%d:' % topic_idx)
        print(' '.join([tf_feature_names[i] for i in topic.argsort()[:-n_top_words - 1:-1]]))
        print("")


# 定义好函数之后 暂定每个主题输出前300个关键词
n_top_words = 7000
tf_feature_names = tf_vectorizer.get_feature_names()
# 调用函数
print_top_words(lda, tf_feature_names, n_top_words)

Topic #0:
酒店 不错 服务 房间 宾馆 很好 早餐 入住 免费 环境 设施 下次 价格 干净 交通 餐厅 选择 反馈 总体 位置 很大 热情 性价比 装修 地理位置 还可以 舒服 点评 满意 客人 提供 安静 大堂 豪华 地方 推荐 机场 喜欢 品种 打车 补充 这家 值得 服务员 分钟 还会 门口 饭店 朋友 缺点 卫生间 味道 感谢您 大床 希望 唯一 舒适 晚上 人员 光临 商务 上海 香港 水果 对面 一家 携程 客房 便宜 行政 步行 出门 火车站 确实 上网 适合 标准 建议 前台 算是 距离 改进 套房 吃饭 出租车 五星级 提出 宽敞 特色 自助 温馨 很快 很近 整体 态度 楼层 升级 旅游 行李 硬件 主动 期待 电脑 旁边 时间 非常感谢 地铁 市中心 周边 游泳池 员工 温泉 服务态度 不太 度假 楼下 周到 便利 好吃 工作 出差 司机 购物 阳台 速度 风景 海景 安排 标间 到位 陈旧 不到 机会 肯定 大酒店 市区 房价 享受 网站 城市 优点 齐全 自助餐 宾客 地点 合作 不远 介绍 宽带 面积 东西 评价 内部 用餐 意见 支持 房间内 五星 广场 设计 新装修 期间 挺好 价钱 不算 景色 宝贵意见 更好 空间 四星级 好多 导航 还好 地段 索引 注册 中餐厅 景点 海景房 尊敬 代理 没什么 英才 诚聘 整洁 广告业务 号楼 停车场 地铁站 第一次 超市 马路 别墅 感谢 正好 杭州 遗憾 设备 价位 太小 每

Topic #1:
酒店 房间 前台 携程 入住 服务员 晚上 不好 服务 客人 空调 实在 退房 电话 早餐 预定 太差 隔音 第二天 很差 价格 打电话 卫生间 态度 声音 建议 这家 只能 设施 早上 点评 结帐 毛巾 小时 电梯 经理 地毯 小姐 窗户 招待所 失望 补充 大床 告知 告诉 隔壁 宾馆 地方 时间 东西 洗澡 人员 收费 热水 服务态度 四星 大堂 最差 很小 标准 朋友 星级 电视 好像 一间 打扫 分钟 总台 半天 投诉 预订 信用卡 半夜 床单 一股 情况 效果 三星 味道 装修 上网 一张 客房 外面 走廊 客户 宽带 估计 打开 硬件 办法 几个 睡觉 取消 如家 希望 听到 房价 第一次 马桶 行李 下午 被子 有人 事情 陈旧 还可以 不住 房费 不到 四星级 浴室 郁闷 极差 设施陈旧 管理 淋浴 办理 只好 千万 卫生 霉味 商务 洗手间 饭店 服务生 当天 中午 开门 确认 干净 餐厅 回来 换房 这是 标准间 刷卡 蚊子 很脏 太小 浴缸 还好 不行 授权 同事 锦江 水平 凌晨 推荐 三星级 保安 不值 解决 登记 网络 评价 结账 原因 不爽 房卡 提前 便宜 点多 通知 没法 消费 糟糕 一晚 楼层 一家 找到 手续 暖气 旅馆 简陋 异味 床上 下次 厕所 两次 押金 单人间 回答 两天 早晨 网上 豪华 休息 发生 没想到 标间 到达 交涉 没什么 房间内 五星 顾客 解释 发票 反正 不想 半个 骚扰电话 旁边 接待 差点 安排 质量 电视机 说话 飞机 中央空调 影响 气味 条件 家具 工作人员 入睡 设备 半小时 提供 选择 一句 恶心 三个 样子 会员 噪音 舒服 离开 手机 肯定 超级 唯一 帮忙 衣服 放在 网线 那天 马路 早饭 意识 水龙头 明明 令人 桌子 号称 浴巾 门童 可怜 不推荐 信息 一楼 吵醒 几次 订单 沟通 提醒 奇怪 不敢恭维 也许 环境 接受 那种 询问 垃圾 怀疑 经历 天气 之星 老旧 房门

key_word = "酒店 不错 服务 房间 宾馆 (上面的关键词复制下来) "

过滤没有关键词的词汇

key_word_list = key_word.split(' ')
new_data = []
for words in clearn_data:
    tem_data = []
    for word in words.split():
        if word.strip() in key_word_list:
#             print(word)
            tem_data.append(word.strip('\n'))
    new_data.append(tem_data)
new_data

[[‘订单’,
‘朋友’,
‘到达’,
‘酒店’,
‘一位’,
‘前台’,
‘足足’,
‘小时’,
‘解决’,
‘前台’,
‘接到’,
‘通知’,
‘每位’,
‘住店’,
‘客人’,
‘提供’,等

new_data2 = []
for data in new_data:
    data_list = ' '.join(data)
    new_data2.append(data_list)
print(len(new_data2))
print(new_data2)

4000
['订单 朋友 到达 酒店 一位 前台 足足 小时 解决 前台 接到 通知 每位 住店 客人 提供 证件 奥运 期间 提出 中国 配合 酒店 几个 实在 无法忍受 日晚 致电 酒店 酒店 提醒 订单 星期 酒店 携程 通知 朋友 足足 小时 赶到 酒店 小时 客人 办理手续 提供 解决 号称 星级 酒店 事件 前台 人员 笑脸 客人 号称 国际 星级 酒店 培训 员工 酒店 提供 相关 文件 前台 人员 回答 电话 酒店 文件 一名 信息 文件 正规 操作 怀疑 酒店 说法 酒店 交涉 酒店 人员 蛮横 回答 接待 实在 品牌 规范 感到 室外 半小时 到达 酒店 集团 酒店 客人 得知 香港 香港 酒店 管理 集团 得知 部门 水准 团队 品牌 期间 一位 经理 女士 接待 号称 分钟 这位 经理 级别 经理 出门 证件 一句 信息 提前 告知 客人 入住 酒店 客人 尊重 客人 态度 提出 上海 证件 传真 酒店 酒店 办理 手续 前台 一会

保存LDA特征词

# 保存特征词
fw = open('LDA_data.csv', "a+", newline = '',encoding = 'gb18030')
writer = csv.writer(fw)  

for data in new_data2:
    writer.writerow([data])
fw.close()

2.3 LDA -TFIDF特征分类任务

#----------------------------------第二步 数据预处理--------------------------------
#将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
vectorizer = CountVectorizer()

#该类会统计每个词语的tf-idf权值
transformer = TfidfTransformer()

#第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
tfidf = transformer.fit_transform(vectorizer.fit_transform(new_data2))
# for n in tfidf[:5]:
#     print(n)
# print(type(tfidf))

# 获取词袋模型中的所有词语  
word = vectorizer.get_feature_names()
for n in word[:10]:
    print(n)
print("单词数量:", len(set(word)))
#将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
#X = tfidf.toarray()
X = coo_matrix(tfidf, dtype=np.float32).toarray() #稀疏矩阵 注意float
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn import svm
from sklearn import neighbors
from sklearn.naive_bayes import MultinomialNB


#----------------------------------第三步 数据划分--------------------------------
#使用 train_test_split 分割 X y 列表
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, 
                                                    labels, 
                                                    test_size=0.3, 
                                                    )
#--------------------------------第四步 机器学习分类--------------------------------
# 逻辑回归分类方法模型
LR = LogisticRegression(solver='liblinear')
LR.fit(X_train, y_train)
print('模型的准确度:{}'.format(LR.score(X_test, y_test)))
pre = LR.predict(X_test)
print("逻辑回归分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
print("\n")

模型的准确度:0.8716666666666667
逻辑回归分类
1200 1200
precision recall f1-score support
0 0.86 0.89 0.87 600
1 0.88 0.86 0.87 600
accuracy 0.87 1200
macro avg 0.87 0.87 0.87 1200
weighted avg 0.87 0.87 0.87 1200

三、LDA-Word的特征分类

3.1 训练模型

from gensim.models import Word2Vec

# 训练
model = Word2Vec(new_data)
print(model)

3.2 拿到词向量

词向量相加得到句子向量,再取得均值

import numpy as np


#先做第一行,再列合并
lda_vectors = np.zeros((1,100))
i = 0
for ls in new_data:
    i+= 1
    temp_data = np.zeros((1,100))
    n = 0
    for l in ls :
        n += 1
        vectors = model.wv[l.strip()]
        temp_data += vectors
    lda_vectors = np.vstack((lda_vectors,temp_data / n))
    print('#---------------------------{}------------------'.format(i))

词向量相加得到句子向量

import numpy as np


#先做第一行,再列合并
lda_vectors = np.zeros((1,100))
i = 0
for ls in new_data:
    i+= 1
    temp_data = np.zeros((1,100))
    for l in ls :
        n += 1
        vectors = model.wv[l.strip()]
        temp_data += vectors
    lda_vectors = np.vstack((lda_vectors,temp_data))
    print('#---------------------------{}------------------'.format(i))

词向量相乘得到句子向量

import numpy as np


#先做第一行,再列合并
lda_vectors = np.zeros((1,100))
i = 0
for ls in new_data:
    i+= 1
    temp_data = np.zeros((1,100))
    for l in ls :
        n += 1
        vectors = model.wv[l.strip()]
        temp_data *= vectors
    lda_vectors = np.vstack((lda_vectors,temp_data))
    print('#---------------------------{}------------------'.format(i))

上面的选择一个

lda_vectors

array([[ 0. , 0. , 0. , …, 0. ,
0. , 0. ],
[-0.19588671, -0.10217057, 0.11343548, …, -0.34674362,
0.14601047, -0.2223701 ],
[-0.17279944, 0.02061116, 0.19713818, …, -0.39348513,
-0.01913097, -0.06791256],
…,
[-0.18011493, 0.00626257, 0.22601405, …, -0.42249438,
-0.04171428, -0.12767173],
[-0.18232735, 0.16477492, 0.22199902, …, -0.4017048 ,
-0.01998795, 0.03262783],
[-0.19637735, -0.0591783 , 0.06737225, …, -0.31060817,
0.26222143, -0.21669391]])

删除第一行

lda_vector = np.delete(lda_vectors, 0, 0)
lda_vector.shape

(4000, 100)

3.3 LDA-Word2vec分类

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(lda_vector, 
                                                    labels, 
                                                    test_size=0.3, 
                                                    )
#--------------------------------第四步 机器学习分类--------------------------------
# 逻辑回归分类方法模型
LR = LogisticRegression(solver='liblinear')
LR.fit(X_train, y_train)
print('模型的准确度:{}'.format(LR.score(X_test, y_test)))
pre = LR.predict(X_test)
print("逻辑回归分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
print("\n")


模型的准确度:0.7308333333333333
逻辑回归分类
1200 1200
precision recall f1-score support
0 0.73 0.73 0.73 602
1 0.73 0.73 0.73 598
accuracy 0.73 1200
macro avg 0.73 0.73 0.73 1200
weighted avg 0.73 0.73 0.73 1200

四、LDA - tfidf-word2vec特征下文本选择

4.1 构建每个词的TFIDF值的函数案例

# -*- coding: utf-8 -*-
from collections import defaultdict
import math
import operator
 
"""
函数说明:创建数据样本
Returns:
    dataset - 实验样本切分的词条
    classVec - 类别标签向量
"""
def loadDataSet():
    dataset = [ ['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],    # 切分的词条
                   ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                   ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                   ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                   ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                   ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid'] ]
    classVec = [0, 1, 0, 1, 0, 1]  # 类别标签向量,1代表好,0代表不好
    return dataset, classVec
 
 
"""
函数说明:特征选择TF-IDF算法
Parameters:
     list_words:词列表
Returns:
     dict_feature_select:特征选择词字典
"""
def feature_select(list_words):
    #总词频统计
    doc_frequency=defaultdict(int)
    for word_list in list_words:
        for i in word_list:
            doc_frequency[i]+=1
 
    #计算每个词的TF值
    word_tf={}  #存储没个词的tf值
    for i in doc_frequency:
        word_tf[i]=doc_frequency[i]/sum(doc_frequency.values())
 
    #计算每个词的IDF值
    doc_num=len(list_words)
    word_idf={} #存储每个词的idf值
    word_doc=defaultdict(int) #存储包含该词的文档数
    for i in doc_frequency:
        for j in list_words:
            if i in j:
                word_doc[i]+=1
    for i in doc_frequency:
        word_idf[i]=math.log(doc_num/(word_doc[i]+1))
 
    #计算每个词的TF*IDF的值
    word_tf_idf={}
    for i in doc_frequency:
        word_tf_idf[i]=word_tf[i]*word_idf[i]
 
    # 对字典按值由大到小排序
    dict_feature_select=sorted(word_tf_idf.items(),key=operator.itemgetter(1),reverse=True)
    return dict_feature_select
 
if __name__=='__main__':
    data_list,label_list=loadDataSet() #加载数据
    features=feature_select(data_list) #所有词的TF-IDF值
    print(features)
    print(len(features))

[(‘to’, 0.0322394037469742), (‘stop’, 0.0322394037469742), (‘worthless’, 0.0322394037469742), (‘my’, 0.028288263356383563), (‘dog’, 0.028288263356383563), (‘him’, 0.028288263356383563), (‘stupid’, 0.028288263356383563), (‘has’, 0.025549122992281622), (‘flea’, 0.025549122992281622), (‘problems’, 0.025549122992281622), (‘help’, 0.025549122992281622), (‘please’, 0.025549122992281622), (‘maybe’, 0.025549122992281622), (‘not’, 0.025549122992281622), (‘take’, 0.025549122992281622), (‘park’, 0.025549122992281622), (‘dalmation’, 0.025549122992281622), (‘is’, 0.025549122992281622), (‘so’, 0.025549122992281622), (‘cute’, 0.025549122992281622), (‘I’, 0.025549122992281622), (‘love’, 0.025549122992281622), (‘posting’, 0.025549122992281622), (‘garbage’, 0.025549122992281622), (‘mr’, 0.025549122992281622), (‘licks’, 0.025549122992281622), (‘ate’, 0.025549122992281622), (‘steak’, 0.025549122992281622), (‘how’, 0.025549122992281622), (‘quit’, 0.025549122992281622), (‘buying’, 0.025549122992281622), (‘food’, 0.025549122992281622)]
32

TF_dict = dict(features)
TF_dict

{‘to’: 0.0322394037469742,
‘stop’: 0.0322394037469742,
‘worthless’: 0.0322394037469742,
‘my’: 0.028288263356383563,
‘dog’: 0.028288263356383563,
‘him’: 0.028288263356383563,
‘stupid’: 0.028288263356383563,
‘has’: 0.025549122992281622,
‘flea’: 0.025549122992281622,
‘problems’: 0.025549122992281622,
‘help’: 0.025549122992281622,
‘please’: 0.025549122992281622,
‘maybe’: 0.025549122992281622,
‘not’: 0.025549122992281622,
‘take’: 0.025549122992281622,
‘park’: 0.025549122992281622,
‘dalmation’: 0.025549122992281622,
‘is’: 0.025549122992281622,
‘so’: 0.025549122992281622,
‘cute’: 0.025549122992281622,
‘I’: 0.025549122992281622,
‘love’: 0.025549122992281622,
‘posting’: 0.025549122992281622,
‘garbage’: 0.025549122992281622,
‘mr’: 0.025549122992281622,
‘licks’: 0.025549122992281622,
‘ate’: 0.025549122992281622,
‘steak’: 0.025549122992281622,
‘how’: 0.025549122992281622,
‘quit’: 0.025549122992281622,
‘buying’: 0.025549122992281622,
‘food’: 0.025549122992281622}

TF_dict['to']

0.0322394037469742

4.2 LDA - tfidf-word2vec 实验

features=feature_select(new_data)
TF_dict = dict(features)

拿到tfidf-word2vec

import numpy as np


#先做第一行,再列合并
lda_vectors = np.zeros((1,100))
i = 0
for ls in new_data:
    i+= 1
    temp_data = np.zeros((1,100))
    n = 0
    for l in ls :
        vectors = model.wv[l] * TF_dict[l]
        temp_data += vectors
    lda_vectors = np.vstack((lda_vectors,temp_data))
    print('#---------------------------{}------------------'.format(i))

#---------------------------1------------------
#---------------------------2------------------
#---------------------------3------------------
#---------------------------4------------------
#---------------------------5------------------
#---------------------------6------------------
#---------------------------7------------------
#---------------------------8------------------
#---------------------------9------------------
#---------------------------10------------------
#---------------------------11------------------
#---------------------------12------------------
#---------------------------13------------------
#---------------------------14------------------
#---------------------------15------------------
#---------------------------16------------------
#---------------------------17------------------

4.3 LDA - tfidf-word2vec分类

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(lda_vector, 
                                                    labels, 
                                                    test_size=0.3, 
                                                    )
#--------------------------------第四步 机器学习分类--------------------------------
# 逻辑回归分类方法模型
LR = LogisticRegression(solver='liblinear')
LR.fit(X_train, y_train)
print('模型的准确度:{}'.format(LR.score(X_test, y_test)))
pre = LR.predict(X_test)
print("逻辑回归分类")
print(len(pre), len(y_test))
print(classification_report(y_test, pre))
print("\n")

模型的准确度:0.73
逻辑回归分类
1200 1200
precision recall f1-score support
0 0.73 0.74 0.73 603
1 0.73 0.72 0.73 597
accuracy 0.73 1200
macro avg 0.73 0.73 0.73 1200
weighted avg 0.73 0.73 0.73 1200

你可能感兴趣的