背着锄头的互联网农民

0%

Kaggle:电影评论情感分析(Bag of Words Meets Bags of Popcorn)(1)

Kaggle的该题目是NLP入门的经典案列,本文也是出于这样的目的来学习NLP常用技术,主要参考Overview

数据预处理

训练数据中包含了电影的评论内容和情感标签,评论内容是英文的,里面有可能包含各种特殊字符,也有可能是网页内容。测试数据只包含了评论内容,要求预测该评论对应的情感标签。评论内容是自然语言,需要先对评论做预处理,包括去除Html标签、去除特殊字符、分词、去除停用词等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def review_to_words(raw_review):
#处理网页信息
review_text = BeautifulSoup(raw_review).get_text()
#替换非字母字符为空格
letters_only = re.sub("[^a-zA-Z]", " ", review_text)
words = letters_only.lower().split()
#移除其中的停用词
stops = set(stopwords.words("english"))
meaningful_words = [w for w in words if not w in stops]
return( " ".join( meaningful_words ))

train = pd.read_csv("data/labeledTrainData.tsv", header=0, delimiter="\t", quoting=3)
print(train.info())
print(train.head())

num_reviews = train["review"].size
clean_train_reviews = []
for i in range( 0, num_reviews ):
clean_train_reviews.append( review_to_words( train["review"][i] ))

test = pd.read_csv("data/testData.tsv", header=0, delimiter="\t", quoting=3 )
num_reviews = len(test["review"])
clean_test_reviews = []
for i in range(0,num_reviews):
clean_review = review_to_words( test["review"][i] )
clean_test_reviews.append( clean_review )
特征表示

现在我们已经把一条评论转换为word列表,但是模型训练时候需要是数值类型的,所以需要对评论进行特征表示。一种简单的想法是使用One-Hot编码。将评论转换为一个向量,向量长度为所有出现过的word的个数,如果某个word在该评论中出现过,则设置向量的该位置为1,这样就将一条评论转换为一个向量。

但是这种方法有个问题是向量长度可能会非常长,一种优化是只提取出现次数最多的n个word作为向量下标,向量的值在该条评论中该Word的出现次数,sklearn中CountVectorizer就是做了这样的事情。

1
2
3
4
5
6
7
#5000的含义向量最大长度为5000,选取次数最多的5000个单词作为向量下标
vectorizer = CountVectorizer(analyzer = "word", tokenizer = None, preprocessor = None, stop_words = None, max_features = 5000)
train_data_features = vectorizer.fit_transform(clean_train_reviews)
train_data_features = pd.DataFrame(train_data_features.toarray())

t_data_features = vectorizer.transform(clean_test_reviews)
test_data_features = test_data_features.toarray()

模型训练

这里简单的使用随机森林进行训练预测,得到0.84的精度。

1
2
3
4
5
forest = RandomForestClassifier(n_estimators = 100) 
forest = forest.fit( train_data_features, train["sentiment"] )
result = forest.predict(test_data_features)
output = pd.DataFrame( data={"id":test["id"], "sentiment":result} )
output.to_csv( "submission.csv", index=False, quoting=3 )

特征表示优化

除了上面的CountVectorizer可以做NLP编码,sklean还提供了TfidfVectorizer来做NLP编码。它同样会选取出现次数最多的n个word做为向量下标,但是向量的值为每个Word的TF-IDF。

1
2
3
4
5
6
torizer = TfidfVectorizer(analyzer = "word", tokenizer = None, preprocessor = None, stop_words = None, max_features = 5000)
train_data_features = vectorizer.fit_transform(clean_train_reviews)
train_data_features = pd.DataFrame(train_data_features.toarray())

test_data_features = vectorizer.transform(clean_test_reviews)
test_data_features = test_data_features.toarray()