Kaggle竞赛 Real or Not? NLP with Disaster Tweets 文本分类

2023-10-18 17:40

本文主要是介绍Kaggle竞赛 Real or Not? NLP with Disaster Tweets 文本分类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 前言
  • 一、比赛介绍
  • 二、解决方案(探索式资料分析&清洗数据)
    • 2-1、介绍和引言
    • 2-2、对于特征keyword(关键字)和location(地点)的处理
    • 2-3、组成新特征
    • 2-4、target分布
    • 2-5、文本清理
    • 2-6、错误标签样本处理
  • 三、训练模型
    • 3-1、加载所需包
    • 3-2、数据的进一步处理
    • 3-3、添加特征并绘图
    • 3-4、训练模型
  • 总结


前言

在这场竞赛中,你面临的挑战是建立一个机器学习模型,预测哪些推文是关于真实灾难的,哪些不是。你将有权访问由 10,000 条手动分类的推文组成的数据集。

一、比赛介绍

来源:kaggle竞赛- Natural Language Processing with Disaster Tweets
任务:我们需要根据文章的location、keyword以及文本text来判断这篇推文是否和灾难有关,相关部门可以据此来第一时间发现可能存在的灾难并且迅速做出反应,将损失降低到最低。
在这里插入图片描述

二、解决方案(探索式资料分析&清洗数据)

2-1、介绍和引言

导入库、读取数据、分析

import re
import string
import operator
from collections import defaultdictimport matplotlib.pyplot as plt
import seaborn as snsfrom sklearn.model_selection import StratifiedKFold, StratifiedShuffleSplit
from sklearn.metrics import precision_score, recall_score, f1_scoredf_train = pd.read_csv('/kaggle/input/nlp-getting-started/train.csv')
df_test = pd.read_csv('/kaggle/input/nlp-getting-started/test.csv')print(f'Training Set Shape: {df_train.shape}')
print(f'Test Set Shape: {df_test.shape}')

数据规模:Training Set Shape: (7613, 5); Test Set Shape: (3263, 4)

训练集
在这里插入图片描述
验证集
在这里插入图片描述

2-2、对于特征keyword(关键字)和location(地点)的处理

一、探索空值的数量

print(df_train['location'].isnull().sum())
print(df_train['keyword'].isnull().sum())

输出
2533 61

二、缺失值的处理: 使用空字符串 ‘’ 来替代缺失值,将缺失值用空字符串填充。

missing_cols = ['keyword', 'location']fig, axes = plt.subplots(ncols=2, figsize=(17, 4), dpi=100)sns.barplot(x=df_train[missing_cols].isnull().sum().index, y=df_train[missing_cols].isnull().sum().values, ax=axes[0])
sns.barplot(x=df_test[missing_cols].isnull().sum().index, y=df_test[missing_cols].isnull().sum().values, ax=axes[1])axes[0].set_ylabel('Missing Value Count')
axes[0].set_title('Training Set')
axes[1].set_title('Test Set')plt.show()for df in [df_train, df_test]:for col in ['keyword', 'location']:# df[col] = df[col].fillna(f'no_{col}')# 在该方法中,使用空字符串 '' 来替代缺失值,将缺失值用空字符串填充。df[col] = df[col].fillna('')

输出:如图输出所示,训练集和测试集的loaction字段缺失较多。
在这里插入图片描述

三、分布探索: 输出其唯一的值的数量;

print(f"Number of unique values in keyword = {df_train['keyword'].nunique()} (Training) - {df_test['keyword'].nunique()} (Test)")
print(f"Number of unique values in location = {df_train['location'].nunique()} (Training) - {df_test['location'].nunique()} (Test)")

输出
Number of unique values in keyword = 221 (Training) - 221 (Test)
Number of unique values in location = 3341 (Training) - 1602 (Test)

四、关键字分布探索

# 以keyword来分组抽取target的平均值
df_train['target_mean'] = df_train.groupby('keyword')['target'].transform('mean')fig = plt.figure(figsize=(8,72), dpi=100)# 绘制图形,根据关键字keyword,并且根据target_mean降序排列
sns.countplot(y=df_train.sort_values(by='target_mean', ascending=False)['keyword'], hue=df_train.sort_values(by='target_mean', ascending=False)['target'])plt.legend(loc=1)
plt.title('Target Distribution in Keywords')plt.show()# 删除掉列
df_train.drop(columns=['target_mean'], inplace=True)

部分输出:从图中我们可以得知,keyword与label之间有可见的相关性,有些词只在灾难推文中出现,而有些词只在非灾难推文中出现。
在这里插入图片描述

看一下上边输出添加了target_mean的df是什么样子: df_train.sort_values(by=‘target_mean’, ascending=False)

在这里插入图片描述

2-3、组成新特征

一、组成新特征:单词数量、唯一的单词数量、停用词数量、url数量、单词平均长度、字符串长度、标点符号数量、#数量、@数量。(#开头的一般是标签,即考虑标签数量,@一般是提及什么朋友,即提到的人数量。)

# word_count
df_train['word_count'] = df_train['text'].apply(lambda x:len(str(x).split()))
df_test['word_count'] = df_test['text'].apply(lambda x:len(str(x).split()))# unique_word_count
df_train['unique_word_count'] = df_train['text'].apply(lambda x:len(set(str(x).split())))
df_test['unique_word_count'] = df_test['text'].apply(lambda x:len(set(str(x).split())))# stop_word_count
from wordcloud import STOPWORDS
df_train['stop_word_count'] = df_train['text'].apply(lambda x: len([w for w in str(x).lower().split() if w in STOPWORDS]))
df_test['stop_word_count'] = df_test['text'].apply(lambda x: len([w for w in str(x).lower().split() if w in STOPWORDS]))# url_count
df_train['url_count'] = df_train['text'].apply(lambda x: len([w for w in str(x).lower().split() if 'http' in w or 'https' in w]))
df_test['url_count'] = df_test['text'].apply(lambda x: len([w for w in str(x).lower().split() if 'http' in w or 'https' in w]))# mean_word_length
df_train['mean_word_length'] = df_train['text'].apply(lambda x: np.mean([len(w) for w in str(x).split()]))
df_test['mean_word_length'] = df_test['text'].apply(lambda x: np.mean([len(w) for w in str(x).split()]))# char_count
df_train['char_count'] = df_train['text'].apply(lambda x: len(str(x)))
df_test['char_count'] = df_test['text'].apply(lambda x: len(str(x)))# punctuation_count
df_train['punctuation_count'] = df_train['text'].apply(lambda x:len([c for c in str(x) if c in string.punctuation]))
df_test['punctuation_count'] = df_test['text'].apply(lambda x:len([c for c in str(x) if c in string.punctuation]))# hashtag_count
df_train['hashtag_count'] = df_train['text'].apply(lambda x: len([c for c in str(x) if c == '#']))
df_test['hashtag_count'] = df_test['text'].apply(lambda x: len([c for c in str(x) if c == '#']))# mention_count
df_train['mention_count'] = df_train['text'].apply(lambda x: len([c for c in str(x) if c == '@']))
df_test['mention_count'] = df_test['text'].apply(lambda x: len([c for c in str(x) if c == '@']))
# 输出df_train

输出:看看添加了新特征的df_train什么样子。
在这里插入图片描述

二、观察新特征上灾难和不是灾难的分布情况、每个特征训练集和验证集上的分布情况

meta_features = ['word_count', 'unique_word_count', 'stop_word_count', 'url_count', 'mean_word_length', 'char_count', 'punctuation_count']
disaster_tweets = df_train['target'] == 1fig, axes = plt.subplots(ncols=2, nrows=len(meta_features), figsize=(20,40), dpi=100)for i, feature in enumerate(meta_features):sns.distplot(df_train.loc[~disaster_tweets][feature], label='Not Disaster', ax=axes[i][0], color='green')sns.distplot(df_train.loc[disaster_tweets][feature], label='Disaster', ax=axes[i][0], color='red')sns.distplot(df_train[feature], label='Training', ax=axes[i][1])sns.distplot(df_test[feature], label='Test', ax=axes[i][1])for j in range(2):axes[i][j].legend()axes[i][0].set_title(f'{feature} Target Distribution in Training Set')axes[i][1].set_title(f'{feature} Training & Test Set Distribution')plt.show()

输出:这里只展示部分图片,根据图片显示,分布大概一致,可以使用,如果出现一些偏差比较大的分布,可以考虑直接砍掉特征,如果是训练集和验证集分布不一致,可以考虑重新整理一下验证集,使得分布大概相同。
在这里插入图片描述

2-4、target分布

target: 画出图表观测一下分布情况。

fig, axes = plt.subplots(ncols=2, figsize=(17, 4), dpi=100)
plt.tight_layout()df_train.groupby('target').count()['id'].plot(kind='pie', ax=axes[0], labels=['Not Disaster (57%)', 'Disaster (43%)'])
sns.countplot(x=df_train['target'], hue=df_train['target'], ax=axes[1])axes[0].set_title('Target Distribution in Training Set')
axes[1].set_title('Target Count in Training Set')plt.show()

输出:根据图表可知,0、1标签的数量大致持平,没有相差太大。
在这里插入图片描述

2-5、文本清理

文本清理: 把一些奇奇怪怪的符号都去掉,适用于tweet评论。

2-6、错误标签样本处理

错误标签样本处理: 某些样本的标签是错误的,剔除掉。

df_mislabeled = df_train.groupby(['text_cleaned']).nunique().sort_values(by='target', ascending=False)
df_mislabeled = df_mislabeled[df_mislabeled['target'] > 1]['target']
df_mislabeled.index.tolist()

输出:各位爷,来瞅瞅标错的文本都是什么德行,让我们的标注人员迷失了自己。

在这里插入图片描述

把标记错误的老六都剔除掉。

df_train = df_train[~df_train['text_cleaned'].isin(df_mislabeled.index.tolist())]

三、训练模型

3-1、加载所需包

import random
import torch
from torch.utils.data import TensorDataset, DataLoader, random_split
from transformers import BertTokenizer
from transformers import BertForSequenceClassification, AdamW
from transformers import get_linear_schedule_with_warmup# 加载huggingface的transformers,编辑词向量。
# 设定随机种子,使得每次得到的结果一致。
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = Truedevice = torch.device('cuda')

3-2、数据的进一步处理

数据的进一步处理: 添加字段,加载预训练分词模型。

# 添加一个字段,final_text,由keyword和text_cleaned组成
df_train['final_text'] = df_train['keyword'] + ' ' + df_train['text_cleaned']
df_test['final_text'] = df_test['keyword'] + ' ' + df_test['text_cleaned']# Get text values and labels
text_values = df_train['final_text'].values
labels = df_train['target'].values# Load the pretrained Tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)# 查看编码后的text以及转换为ID的text
text = '[CLS]'
print('Original Text : ', text)
print('Tokenized Text: ', tokenizer.tokenize(text))
print('Token IDs     : ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(text)))
print('\n')text = '[SEP]'
print('Original Text : ', text)
print('Tokenized Text: ', tokenizer.tokenize(text))
print('Token IDs     : ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(text)))
print('\n')text = '[PAD]'
print('Original Text : ', text)
print('Tokenized Text: ', tokenizer.tokenize(text))
print('Token IDs     : ', tokenizer.convert_tokens_to_ids(tokenizer.tokenize(text)))# tokenizer的编码(encode)是两个操作步骤的合体
print(f'Adding Special Tokens Using Encode Func: {tokenizer.encode(text_values[1])}')

输出
在这里插入图片描述
在这里插入图片描述

3-3、添加特征并绘图

添加final_text这一列的长度特征并绘图

# Add a length column which contains the length of the tweet
# 添加final_text这一列的长度。
df_train['length'] = df_train['final_text'].apply(len)
df_test['length'] = df_test['final_text'].apply(len)# Plot
sns.set_style('whitegrid', {'axes.grid' : False})
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(18, 6)sns.distplot(df_train['length'], color='#20A387',ax=ax[0])
sns.distplot(df_test['length'], color='#440154',ax=ax[1])fig.suptitle("Length of Tweets", fontsize=14)
ax[0].set_title('Train')
ax[1].set_title('Test')plt.show()

在这里插入图片描述

添加final_text这一列的单词数量并绘图

# Add column for number of words
df_train['num_of_words'] = df_train['final_text'].apply(lambda x:len(str(x).split())) 
df_test['num_of_words'] = df_test['final_text'].apply(lambda x:len(str(x).split())) # Plot
sns.set_style('whitegrid', {'axes.grid' : False})
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(18, 6)sns.distplot(df_train['num_of_words'], color='#20A387',ax=ax[0])
sns.distplot(df_test['num_of_words'], color='#440154',ax=ax[1])fig.suptitle("Number of Words in Tweets", fontsize=14)
ax[0].set_title('Train')
ax[1].set_title('Test')plt.show()

在这里插入图片描述

3-4、训练模型

处理final_text,返回编码后的ID串。

def encode_fn(text_list):all_input_ids = []for text in text_values:input_ids = tokenizer.encode(text, add_special_tokens=True, max_length=180, pad_to_max_length=True, return_tensors='pt')all_input_ids.append(input_ids)all_input_ids = torch.cat(all_input_ids, dim=0)return all_input_ids

划分数据为训练集和验证集

epochs = 4
batch_size = 32# Split data into train and validation
# 将数据转化为输入模型需要的数据类型
all_input_ids = encode_fn(text_values)
labels = torch.tensor(labels)# TensorDataset是pytorch中的一个类,用于将多个张量打包成一个数据集,将输入数据张量和标签张量进行一一对应组合。
# 划分训练集和验证集
dataset = TensorDataset(all_input_ids, labels)
train_size = int(0.90 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])# Create train and validation dataloaders
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

加载bert模型

# Load the pretrained BERT model
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2, output_attentions=False, output_hidden_states=False)
model.cuda()# create optimizer and learning rate schedule
optimizer = AdamW(model.parameters(), lr=2e-5)
# len(train_dataloader),数据被分为N个批次,每个批次的数据长度是32
# total_steps 
total_steps = len(train_dataloader) * epochs
# get_linear_schedule_with_warmup: 创建学习率调度器函数,
# get_linear_schedule_with_warmup函数在训练初期使用一种称为"warm-up"的策略,即在初始几个epoch中逐步增加学习率,以帮助模型更快地收敛到一个相对合适的参数范围。然后,在warm-up之后,学习率线性地减少或保持恒定。
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=total_steps)

准确率计算
在这里插入图片描述

from sklearn.metrics import f1_score, accuracy_scoredef flat_accuracy(preds, labels):"""A function for calculating accuracy scores"""pred_flat = np.argmax(preds, axis=1).flatten()# 将真实标签数组labels进行展平,得到一维的真实标签数组。labels_flat = labels.flatten()# 计算展平后的真实标签数组与预测结果数组之间的准确率return accuracy_score(labels_flat, pred_flat)

训练和验证

for epoch in range(epochs):# 将模型设置为训练模式model.train()total_loss, total_val_loss = 0, 0total_eval_accuracy = 0# step:步数# batch : 每一个批次的数据for step, batch in enumerate(train_dataloader):model.zero_grad() loss, logits = model(batch[0].to(device), token_type_ids=None, attention_mask=(batch[0]>0).to(device), labels=batch[1].to(device))total_loss += loss.item()loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)optimizer.step() scheduler.step()# model.eval()是PyTorch中用于将模型设置为评估模式(evaluation mode)的方法。在深度学习中,模型通常有两种模式:训练模式(training mode)和评估模式(evaluation mode)。model.eval()for i, batch in enumerate(val_dataloader):with torch.no_grad():loss, logits = model(batch[0].to(device), token_type_ids=None, attention_mask=(batch[0]>0).to(device), labels=batch[1].to(device))total_val_loss += loss.item()logits = logits.detach().cpu().numpy()label_ids = batch[1].to('cpu').numpy()total_eval_accuracy += flat_accuracy(logits, label_ids)avg_train_loss = total_loss / len(train_dataloader)avg_val_loss = total_val_loss / len(val_dataloader)avg_val_accuracy = total_eval_accuracy / len(val_dataloader)print(f'Train loss     : {avg_train_loss}')print(f'Validation loss: {avg_val_loss}')print(f'Accuracy: {avg_val_accuracy:.2f}')print('\n')

Train loss : 0.441781023875452
Validation loss: 0.34831519580135745
Accuracy: 0.86
Train loss : 0.3275374324204257
Validation loss: 0.3286557973672946
Accuracy: 0.88
Train loss : 0.2503694619696874
Validation loss: 0.355623895690466
Accuracy: 0.86
Train loss : 0.19663514375973207
Validation loss: 0.3806843503067891
Accuracy: 0.86

预测

# Create the test data loader
text_values = df_test['final_text'].values
# 将数据转化为输入模型需要的数据类型
all_input_ids = encode_fn(text_values)
pred_data = TensorDataset(all_input_ids)
# 
pred_dataloader = DataLoader(pred_data, batch_size=batch_size, shuffle=False)
# 设置模型为评估模式。
model.eval()
preds = []
for i, (batch,) in enumerate(pred_dataloader):with torch.no_grad():outputs = model(batch.to(device), token_type_ids=None, attention_mask=(batch>0).to(device))logits = outputs[0]logits = logits.detach().cpu().numpy()preds.append(logits)final_preds = np.concatenate(preds, axis=0)
final_preds = np.argmax(final_preds, axis=1)# Create submission file
submission = pd.DataFrame()
submission['id'] = df_test['id']
submission['target'] = final_preds
submission.to_csv('submission.csv', index=False)

参考
NLP with Disaster Tweets EDA

总结

🎵~ 出卖我的爱,你背了良心债,最后知道真相的我眼泪掉下来。

这篇关于Kaggle竞赛 Real or Not? NLP with Disaster Tweets 文本分类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/234162

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

Level3 — PART 3 — 自然语言处理与文本分析

目录 自然语言处理概要 分词与词性标注 N-Gram 分词 分词及词性标注的难点 法则式分词法 全切分 FMM和BMM Bi-direction MM 优缺点 统计式分词法 N-Gram概率模型 HMM概率模型 词性标注(Part-of-Speech Tagging) HMM 文本挖掘概要 信息检索(Information Retrieval) 全文扫描 关键词

用Pytho解决分类问题_DBSCAN聚类算法模板

一:DBSCAN聚类算法的介绍 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法,DBSCAN算法的核心思想是将具有足够高密度的区域划分为簇,并能够在具有噪声的空间数据库中发现任意形状的簇。 DBSCAN算法的主要特点包括: 1. 基于密度的聚类:DBSCAN算法通过识别被低密

UMI复现代码运行逻辑全流程(一)——eval_real.py(尚在更新)

一、文件夹功能解析 全文件夹如下 其中,核心文件作用为: diffusion_policy:扩散策略核心文件夹,包含了众多模型及基础库 example:标定及配置文件 scripts/scripts_real:测试脚本文件,区别在于前者倾向于单体运行,后者为整体运行 scripts_slam_pipeline:orb_slam3运行全部文件 umi:核心交互文件夹,作用在于构建真

2024年AMC10美国数学竞赛倒计时两个月:吃透1250道真题和知识点(持续)

根据通知,2024年AMC10美国数学竞赛的报名还有两周,正式比赛还有两个月就要开始了。计划参赛的孩子们要记好时间,认真备考,最后冲刺再提高成绩。 那么如何备考2024年AMC10美国数学竞赛呢?做真题,吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一。通过做真题,可以帮助孩子找到真实竞赛的感觉,而且更加贴近比赛的内容,可以通过真题查漏补缺,更有针对性的补齐知识的短板。

PMP–一、二、三模–分类–14.敏捷–技巧–看板面板与燃尽图燃起图

文章目录 技巧一模14.敏捷--方法--看板(类似卡片)1、 [单选] 根据项目的特点,项目经理建议选择一种敏捷方法,该方法限制团队成员在任何给定时间执行的任务数。此方法还允许团队提高工作过程中问题和瓶颈的可见性。项目经理建议采用以下哪种方法? 易错14.敏捷--精益、敏捷、看板(类似卡片)--敏捷、精益和看板方法共同的重点在于交付价值、尊重人、减少浪费、透明化、适应变更以及持续改善等方面。

【python计算机视觉编程——8.图像内容分类】

python计算机视觉编程——8.图像内容分类 8.图像内容分类8.1 K邻近分类法(KNN)8.1.1 一个简单的二维示例8.1.2 用稠密SIFT作为图像特征8.1.3 图像分类:手势识别 8.2贝叶斯分类器用PCA降维 8.3 支持向量机8.3.2 再论手势识别 8.4 光学字符识别8.4.2 选取特征8.4.3 多类支持向量机8.4.4 提取单元格并识别字符8.4.5 图像校正

PMP–一、二、三模–分类–14.敏捷–技巧–原型MVP

文章目录 技巧一模14.敏捷--原型法--项目生命周期--迭代型生命周期,通过连续的原型或概念验证来改进产品或成果。每个新的原型都能带来新的干系人新的反馈和团队见解。题目中明确提到需要反馈,因此原型法比较好用。23、 [单选] 一个敏捷团队的任务是开发一款机器人。项目经理希望确保在机器人被实际建造之前,团队能够收到关于需求的早期反馈并相应地调整设计。项目经理应该使用以下哪一项来实现这个目标?