0%

Kaggle比赛 NLP with Disaster Tweets

Kaggle比赛 NLP with Disaster Tweets

这个算是nlp比赛的第一次尝试,是个基础入门类型的比赛,也当是先熟悉一下nlp的一些基础方法。这个比赛主要也就是通过tweet的文本内容来判断他是否是在描述一场灾难。

如何从零开始

首先呢,最好的开始kaggle比赛的方法是找一个baseline了解一下, 我这里就是先找了一个General Introduction了解一下nlp相关的预处理和模型。Getting started with NLP - A general Introduction

导入数据

进入比赛,我们首先就要做的就是读取数据文件并查看一下基本的数据类型

我们可以看见这里面一共包含了五列,id, keyword, location, text, target。这里面text就是tweet的主要内容了, keyword是关键词描述,location是发生的地点,target就是给予的标签,1代表是在描述灾难,0表示不是。

查看数据缺失值

在数据分析中,数据有缺失是不可避免的,因此我们要先来查看一下缺失的数据值

1
train.isnull().sum()


我们可以看到只有keyword和location这两列是包含缺失值的,但是在这次基础的尝试中,我们暂时用不到这些数据,因此影响并不是很大。

数据预处理

首先,我们应该对数据进行处理,以便模型进行更好的训练。
这一步的目的主要是规范化文本,去除一些噪声值,将一些词根还原等

文本清洗(Text Clean)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def clean_text(text):
'''Make text lowercase, remove text in square brackets,remove links,remove punctuation
and remove words containing numbers.'''
# make text lowercase
text = text.lower()
# remove square brackets
text = re.sub('\[.*?\]', '', text)
# remove links
text = re.sub('https?://\S+|www\.\S+', '', text)
# remove <>
text = re.sub('<.*?>+', '', text)
# remove punctuation
text = re.sub('[%s]' % re.escape(string.punctuation), '', text)
# remove \n
text = re.sub('\n', '', text)
# remove numbers
text = re.sub('\w*\d\w*', '', text)
return text

我们可以看到,在这里他的主要作用就是利用正则表达式来消除一些特殊的文本项,例如括号,网址链接,标点符号等。在这里由于我也对正则表达式忘记了不少,所以推荐一个正则表达式测试器正则表达式测试器

我们可以看到我们的文本已经比较规范了

令牌化(Tokenization)

令牌化这个翻译我也不知道准不准确,但大概意思是没错的,就是将文本转化为一个一个的令牌,令牌可以是单词,句子,段落等。基于我们想要的令牌的类型,令牌化可以是各种类型。在notebook里面,他举了一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
text = "Are you coming , aren't you"
tokenizer1 = nltk.tokenize.WhitespaceTokenizer()
tokenizer2 = nltk.tokenize.TreebankWordTokenizer()
tokenizer3 = nltk.tokenize.WordPunctTokenizer()
tokenizer4 = nltk.tokenize.RegexpTokenizer(r'\w+')

print("Example Text: ",text)
print("------------------------------------------------------------------------------------------------")
print("Tokenization by whitespace:- ",tokenizer1.tokenize(text))
print("Tokenization by words using Treebank Word Tokenizer:- ",tokenizer2.tokenize(text))
print("Tokenization by punctuation:- ",tokenizer3.tokenize(text))
print("Tokenization by regular expression:- ",tokenizer4.tokenize(text))

这里我们可以看见他用了四种不同的方式来分割文本,第一种是单纯的用空格来分割,第二种是用了Treebank Word Tokenizer(应该是一种词库分类器)来分割,第三种是空格分隔加上标点符号分割。第四种是自定义的正则表达式分割,我们可以看到他是用了字母数字匹配,所以在这个例子中会以空格和标点来分割,与第三种不同的是他在令牌中不保留标点。

在这里我觉得第四种的方式比较好,还可以去除标点,因此对文本用第四种方法进行令牌化。

去除停用词(Stopwords Removal)

停用词就是一些频率非常高但没有什么实际意义的词,像a, an, the, is, are等, 我们用nltk.corpus里的stopwords来去除停用词

1
2
3
4
5
6
7
def remove_stopwords(text):
"""
Removing stopwords belonging to english language

"""
words = [w for w in text if w not in stopwords.words('english')]
return words

令牌标准化(Token normalization)

  1. 词干提取(Stemming)
    Stemming是通过删除并替换后缀来获取单词的词根形式的方法
  2. 词型还原(Lemmatization)
    Lemmatization是返回单词的基数或字典形式,基本上是还原单复数之类的
    下面我们来看一下他的这个例子

首先将文本令牌化

1
2
3
text = "feet cats wolves talked"
tokenizer = nltk.tokenize.TreebankWordTokenizer()
tokens = tokenizer.tokenize(text)

先试一下Stemming

1
2
3
# Stemmer
stemmer = nltk.stem.PorterStemmer()
print("Stemming the sentence: ", " ".join(stemmer.stem(token) for token in tokens))

我们看一下stemming的结果

我们可以看见这个结果能够把一般的单复数形式还原,还可以将动词还原为基本形态,但是像feet就不能还原

再试一下Lemmatization

1
2
3
# Lemmatizer
lemmatizer=nltk.stem.WordNetLemmatizer()
print("Lemmatizing the sentence: ", " ".join(lemmatizer.lemmatize(token) for token in tokens))

结果如下

我们可以看见这个还原单复数的效果非常好,但是没法还原动词形态,所以我尝试了一下先Lemmatization再Stemming,效果如下

我们可以看见这个效果还是挺不错的,比以上两个单独用都要好
这里notebook中并没有用到这两个方法,我试了一下,准确率稍有下降,所以这两个technique应该会在以后更好的方法中用到。

将令牌转化为向量

这里介绍了两种方法,一种是bag of words, 一种是TFIDF Features

词袋模型(Bag of Words)

词袋模型表示的意思是把字词处理成向量或矩阵,以便计算机能进行处理。例如,He is a good boy. 在这里就会将句子拆分成一个一个的单词,每一个单词代表向量的一个维度。如果只有这一句话的话,这句话就有5个维度,向量表示为[1,1,1,1,1]。如果还有一个单词向量not,放在最后一个维度,那么向量表示为[1,1,1,1,1,0]。

Countvectorizer Features

Countvectorizer将文本的集合转换为令牌计数矩阵。CountVectorizer带有很多选项来自动进行预处理,令牌化和停止单词删除。

词频-逆文件频率(TFIDF)

用一句话总结就是一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章.
词频 (term frequency, TF) 指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。

逆向文件频率 (inverse document frequency, IDF) IDF的主要思想是:如果包含词条t的文档越少, IDF越大,则说明词条具有很好的类别区分能力。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。

搭建分类模型

notebook里面主要列了三种模型,逻辑回归,朴素贝叶斯和XGBoost,通过五折交叉检验比较F1-score的值发现朴素贝叶斯搭配TFIDF效果最好,这时候我们已经得到一个相对还行的模型,第一次提交尝试一下

1
2
3
4
5
6
7
def submission(submission_file_path,model,test_vectors):
sample_submission = pd.read_csv(submission_file_path)
sample_submission["target"] = model.predict(test_vectors)
sample_submission.to_csv("submission.csv", index=False)
submission_file_path = "../input/nlp-getting-started/sample_submission.csv"
test_vectors=test_tfidf
submission(submission_file_path,clf_NB_TFIDF,test_vectors)


最后大概得了0.79左右,大概能排六百多名,还不是很好。不过,这只是初次尝试,后面有机会可以使用一些其他方法来提高得分。

-------------本文结束感谢您的阅读-------------