综合设计——多源异构数据采集与融合应用综合实践

发布时间 2023-12-14 22:52:30作者: showha
这个项目属于哪个课程 2023数据采集与融合技术
作业要求 综合设计——多源异构数据采集与融合应用综合实践
组名 汪汪队
项目主题 微博评论情感分析
项目简介 项目需求:1. 情绪监测、2. 品牌声誉管理、3. 市场分析、4. 舆论引导、5. 个性化推荐、6. 社交网络分析

项目目标: 1. 情绪识别、2. 情感分类、3. 观点提取、4. 情绪监测、5. 市场趋势预测、6. 个性化推荐、7. 社交网络分析

项目开展技术路线:1. 数据收集、2. 数据预处理、3. 模型选择与训练、4. 情感分析、5. 结果分析与可视化、6. 搭建网页
团队成员学号 组长:
102102130张明康

组员:
102102131张铭玮
102102128汪伟杰
102102129张昊
102102133陈灿铭
这个项目的目标 1、构建网页
2、爬取指定网页动态的评论和图片
3、进行模型训练
4、将爬取后的数据放入模型进行情感分析
5、对结果进行可视化
参考文献 【深度学习】详解TextCNN
[NLP] 文本分类之TextCNN模型原理和实现(超详细)
Python数据可视化:折线图、柱状图、饼图代码
【干货】Python:wordcloud库绘制词云图
python绘制雷达图(详细)

项目介绍

微博评论情感分析项目是基于自然语言处理(NLP)技术,对微博平台上的用户评论进行情感倾向性判定的研究与应用。项目的主要目标是通过对微博评论的情感分析,了解广大用户的情绪状态、观点倾向,从而为情绪监测、品牌声誉管理、市场分析等领域提供有价值的数据支持。
具体而言,微博评论情感分析项目通常包括以下几个阶段:

  1. 数据收集:通过爬虫技术或API接口从微博平台获取评论数据。考虑到数据的多样性和真实性,往往会选取带有用户图片和文本双重信息的评论数据。
  2. 数据预处理:清洗数据,去除噪声,如HTML标签、特殊字符等;然后进行分词处理,把文本分解为更易分析的单元,如词、短语等。
  3. 特征工程:从预处理后的文本中提取特征,如词频、词向量、语法结构等,为机器学习模型准备输入。
  4. 模型训练:使用机器学习算法(如SVM、XGBoost、LSTM、Attention机制等)训练模型。深度学习框架如PyTorch常被用于构建复杂的网络模型,如基于LSTM的长短时记忆网络,以及基于BERT的预训练语言模型。
  5. 模型评估:在测试集上评估模型的性能,确保模型具有良好的泛化能力。
  6. 情感分析:将训练好的模型应用于新的数据集上,输出情感分析结果,如正面情绪、负面情绪或中性情绪。
  7. 结果分析与应用:根据模型输出的情感分析结果,进行数据可视化、趋势分析等,为情绪监测、品牌管理、市场分析等领域提供依据。
    微博评论情感分析项目在实施过程中可能会遇到数据量大、语言多样、情感表达复杂等挑战。因此,项目往往需要结合最新的NLP技术,如深度学习、迁移学习等,以及领域专业知识,才能达到较好的分析效果。

项目需求

微博评论情感分析的需求主要来源于以下几个方面:

  1. 情绪监测:通过分析微博评论的情感倾向,可以了解公众对于某一事件、话题或产品的情绪态度,为情绪监测提供数据支持。
  2. 品牌声誉管理:企业可以通过微博评论情感分析了解消费者对其产品或服务的满意度和不满意度,以及消费者对品牌形象的评价,从而更好地进行品牌声誉管理。
  3. 市场分析:通过对微博评论的情感分析,可以了解消费者对某一产品或服务的需求、喜好和期望,为企业市场策略的制定提供参考。
  4. 舆论引导:政府和媒体可以通过微博评论情感分析了解公众对某一事件或政策的看法和态度,从而进行舆论引导和舆情管理。
  5. 个性化推荐:微博平台可以根据用户的评论情感倾向,为用户推荐更符合其兴趣和需求的内容,提高用户体验。
  6. 社交网络分析:通过分析微博评论的情感倾向,可以了解社交网络中用户之间的关系和影响力,为社交网络分析提供数据支持。
    为了满足上述需求,微博评论情感分析项目需要具备以下特点:
  • 准确性:能够准确识别微博评论的情感倾向,避免误判和漏判。
  • 实时性:能够快速处理大量评论数据,实时反馈情感分析结果。
  • 鲁棒性:能够应对不同语言风格、语境和噪声环境的干扰,保持稳定的数据分析效果。
  • 可扩展性:能够适应不同领域的需求,灵活扩展情感分析的应用范围。
  • 隐私保护:在数据收集和分析过程中,确保用户隐私得到保护,遵守相关法律法规。

项目目标

微博评论情感分析的目标主要包括以下几点:

  1. 情绪识别:准确识别评论表达的情绪倾向,如正面情绪、负面情绪或中性情绪。这是情感分析的基础任务,也是其他应用场景的前提。
  2. 情感分类:对评论进行细致的情感分类,如愤怒、喜悦、悲伤等,以便更深入地了解用户的情感状态。
  3. 观点提取:从评论中提取出用户对某一事件、话题或产品的观点和看法,为舆情分析、市场调查等领域提供有价值的信息。
  4. 情绪监测:通过对微博评论的情感分析,实时监测公众情绪的变化趋势,为情绪监测和舆情管理提供数据支持。
  5. 品牌声誉分析:分析用户对品牌的情感态度,帮助企业了解品牌形象和声誉状况,为品牌声誉管理提供依据。
  6. 市场趋势预测:通过分析用户对产品或服务的情感态度,预测市场趋势和消费者需求,为企业市场策略制定提供参考。
  7. 个性化推荐:根据用户的情感倾向,为用户推荐更符合其兴趣和需求的内容,提高用户体验。
  8. 社交网络分析:通过分析微博评论的情感倾向,研究社交网络中用户之间的关系和影响力,为社交网络分析提供数据支持。
    总之,微博评论情感分析的目标是通过对评论数据的情感分析,为情绪监测、品牌声誉管理、市场分析、个性化推荐等各个领域提供有价值的信息和数据支持。

项目开展技术路线

微博评论情感分析的项目开展技术路线可以分为以下几个阶段:

  1. 数据收集与预处理

    • 使用爬虫技术或微博API获取微博评论数据。
  2. 数据预处理

    • 对原始数据进行预处理
  3. 模型选择与训练

    • 使用TestCNN模型进行训练
  4. 情感分析

    • 将训练好的模型应用于新的数据集上,输出情感分析结果
  5. 结果分析与可视化

    • 对情感分析结果进行数据可视化、趋势分析等,以便更直观地展示和分析数据。
  6. 搭建网页:

    • 使用streamlit搭建网页,展示爬取的数据以及可视化结果

我负责的部分:模型训练(和张铭玮同学)

通过网络搜索,了解到使用TextCNN模型进行文本情感的分析会好一点,于是决定使用TextCNN模型进行情感分析

配置类:

class Config(object):
    """配置参数"""
    def __init__(self, dataset, embedding):#random
        self.train_path = '/datasets/weibo_senti_100k'             
        self.vocab_path = 'mydata/data/vocab3.pkl'                      # 词表的路径
        self.batch_size = 128                                           # mini-batch大小
        self.pad_size = 128                                             # 每句话处理成的长度(短填长切)
        self.embedding_pretrained = None
        self.n_vocab = 0                                                # 词表大小,在运行时赋值
        self.embed = 300                                                # 词向量维度
        self.filter_sizes = (1, 2, 3, 4)                                # 卷积核尺寸
        self.num_filters = 256                                          # 卷积核数量
        self.dropout = 0.4                                              # Dropout的比率
        self.class_list = [x.strip() for x in open(
            dataset + '/data/class3.txt', encoding='utf-8').readlines()]    # 情感类别列表
        self.num_classes = len(self.class_list)                             # 情感类别数量
        self.device = torch.device('cpu')
        self.learning_rate = 1e-3
        self.num_epochs = 30
        self.save_path = dataset + '/saved_dict/' + 'cnn6' +''+ '.ckpt' # 模型保存路径
        self.log_path = dataset + '/log/' + 'cnn'
        self.require_improvement = 1000
        self.cfggb = 0

首先定义一个基于卷积神经网络的情感分析模型,通过卷积和池化操作提取文本特征,并通过全连接层进行情感分类预测

#通过卷积和池化操作提取文本特征,并通过全连接层进行情感分类预测
class Model(nn.Module):
    def __init__(self, config):  #初始化模型,包括词嵌入层、卷积层、池化层和全连接层
        super(Model, self).__init__()

        self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)     #词嵌入层
        print((config.n_vocab, config.embed, config.n_vocab - 1))
        print(self.embedding)

        self.convs = nn.ModuleList(             #ModuleList可以将子模块添加到一个列表中
            [nn.Conv2d(1, config.num_filters, (k, config.embed)) for k in config.filter_sizes])
  
        self.dropout = nn.Dropout(config.dropout)   #dropout层用于防止过拟合
        self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes)

    def conv_and_pool(self, x, conv):  #进行卷积和池化操作
        z = conv(x)
        x = F.relu(conv(x)).squeeze(3)
        x = F.avg_pool1d(x, x.size(2)).squeeze(2)
        return x

    def forward(self, x):  #前向传播函数,定义了数据在网络中的传递流程

        out = self.embedding(x[0])
   
        out = out.unsqueeze(1)

        out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1)
        out = self.dropout(out)
        out = self.fc(out)
        return out

对数据集进行处理合适地处理后,开始训练

def train(config, model, train_iter, dev_iter):
    # 设置模型为训练状态。
    # 定义优化器和损失函数。
    # 迭代训练集数据,计算损失并进行反向传播优化模型。
    # 在训练过程中,定期评估模型在验证集上的性能,并保存模型参数。

    start_time = time.time()
    model.train()
    optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate)

    # 学习率指数衰减,每次epoch:学习率 = gamma * 学习率
    # scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
    total_batch = 0  # 记录进行到多少batch
    dev_best_loss = float('inf')
    last_improve = 0  # 记录上次验证集loss下降的batch数
    flag = False  # 记录是否很久没有效果提升
    #writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))
    for epoch in range(config.num_epochs):
        print('Epoch [{}/{}]'.format(epoch + 1, config.num_epochs))


        # scheduler.step() # 学习率衰减
        for i, (trains, labels) in enumerate(train_iter):
            outputs = model(trains)

            model.zero_grad()
            loss = F.cross_entropy(outputs, labels)
            loss.backward()
            optimizer.step()
            if total_batch % 100 == 0:
                # 每多少轮输出在训练集和验证集上的效果
                true = labels.data.cpu()
                predic = torch.max(outputs.data, 1)[1].cpu()
                train_acc = metrics.accuracy_score(true, predic)
                dev_acc, dev_loss = evaluate(config, model, dev_iter)
                if dev_loss < dev_best_loss:
                    dev_best_loss = dev_loss
                    torch.save(model.state_dict(), config.save_path,_use_new_zipfile_serialization=False)
                    improve = '增长'
                    last_improve = total_batch
                else:
                    improve = ''
                time_dif = get_time_dif(start_time)
                msg = 'Iter: {0:>6},  Train Loss: {1:>5.2},  Train Acc: {2:>6.2%},  Val Loss: {3:>5.2},  Val Acc: {4:>6.2%},  Time: {5} {6}'
                print(msg.format(total_batch, loss.item(), train_acc, dev_loss, dev_acc, time_dif, improve))
                model.train()
      
            total_batch += 1
            if total_batch - last_improve > config.require_improvement:
                # 验证集loss超过1000batch没下降,结束训练
                print("No optimization for a long time, auto-stopping...")
                flag = True
                break
        if flag:
            break

预测(前端点击开始爬取到数据后会调用这个方法):

def predict2(model,text,cfggb):
    def ld_fun(data_list):
        tokenizer = lambda x: [y for y in x]
        pad_size = 32
        vocab_path= 'mydata/data/vocab3.pkl'
        vocab = pkl.load(open(vocab_path, 'rb'))
        contents = []
    
        for line in data_list:
            #lin = line.strip()
            try:
                content,label = line.split('\t')	#content 为前面的新闻,label为后面标签
            except:
                print(line)
                print("dfshiou")
                input()
            words_line = []
            token = tokenizer(content)	#tokenizer = lambda x: [y for y in x],拆成单字
            seq_len = len(token)
            if pad_size:	#短补长截,短的字符长度不变,长的截断为pad_size
                if len(token) < pad_size:
                    token.extend([PAD] * (pad_size - len(token)))
                else:
                    token = token[:pad_size]
                    seq_len = pad_size
            # word to id
            for word in token:
                words_line.append(vocab.get(word, vocab.get(UNK)))
            contents.append((words_line, int(label), seq_len))
        return contents  
    text = text.replace('\t','')
  
    content = text
    content = content+'\t'
    content = content+'0'
    sentences = []
    sentences.append(content)

    a = 'mydata'
    b = '123'
    config2 = Config(a,b)
    config2.n_vocab = cfggb

    mpd = ld_fun(sentences)
    mpd_iter = build_iterator(mpd, config2)

    labels = { 0:'like',1:'disgust',2:'happiness',3:'sadness',4:'anger',5:'surprise',6:'fear'}
    model.eval()
    with torch.no_grad():
        for a,b in mpd_iter:
            outputs = model(a)
            x = torch.max(outputs.data, 1)[1].cpu().numpy()

  
    return str(labels[x[0]])