Logistic Regression在文本分类中的应用

文章目录
  1. 1. Logistic Regression 文本二分类
    1. 1.1. 数据预处理
    2. 1.2. 构造用于二分类的模型
  2. 2. Logistic Regression 多类文本分类

在上一篇博客中讲到了Logistic Regression(逻辑回归)在图片识别上的应用,作为一只NLP小菜鸡肯定是要把这个算法在NLP相关上进行实现一下的。

Logistic Regression 文本二分类

使用到的数据集是aclIMBD数据集。

数据预处理

这个数据在很久之前就有过一次处理,如果我没记错那么这个数据集是分文件夹的,里面的影评是一条一个txt文件,上次处理之后有四个完整的文件,分别是训练集里面的postive和negtive以及测试集里面的postive和negtive。

个人的一点感觉,在已知算法模型的情况,文本数据的预处理是非常重要的一步。

这里首先通过文件预处理,将四个文件划分为两个文件,一个包含了标签的训练集和一个普通的测试集。
原数据集里面训练集和测试集各有12500条评论,但这里为了学习效率,所以只抽取了其中的100条进行训练和测试,标签为1表示postive,0表示negtive。
数据预处理代码如下:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python
#coding:utf-8

import re
import json
import pandas as pd

# 清理文章中的符号
def clean_str(string):
# 来自Yoon Kim 的论文复现
string = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", string)
string = re.sub(r"\'s", " \'s", string)
string = re.sub(r"\'ve", " \'ve", string)
string = re.sub(r"n\'t", " n\'t", string)
string = re.sub(r"\'re", " \'re", string)
string = re.sub(r"\'d", " \'d", string)
string = re.sub(r"\'ll", " \'ll", string)
string = re.sub(r",", " , ", string)
string = re.sub(r"!", " ! ", string)
string = re.sub(r"\(", " \( ", string)
string = re.sub(r"\)", " \) ", string)
string = re.sub(r"\?", " \? ", string)
string = re.sub(r"\s{2,}", " ", string)
return string.strip().lower()

# 获取对应的word2cev值
def getW2Vec(line):
row=[]
line=line.split(' ')
w2vec=json.loads(open('./data/word2vec.json').read())
for word in line:
if word not in w2vec:
row.append(len(word))
else:
row.append(w2vec[word])
return row

def TextManage(file_path):
data=[]
f=open(file_path)
line=f.readline()
iteration=100
# 为了运行速度,把单项pos/neg的评论压缩到500,原来是个12500
for i in range(iteration):
line = clean_str(line)
line_data = getW2Vec(line)
data.append(line_data)
line = f.readline()
# 返回一个包含所有word2vec化后的单词向量
return data

if __name__=="__main__":
# 训练文件路径
pos_orig = './data/aclIMBD.train.pos.txt'
neg_orig = './data/aclIMBD.train.neg.txt'

# 处理csv训练集文件
headers=['label','content']
pos_data=TextManage(pos_orig)
neg_data=TextManage(neg_orig)
save=pd.DataFrame({'label':[1]*100+[0]*100,'content':pos_data+neg_data})
save.to_csv('./data/IMBDtrain.csv',index=False,sep=',')

# 测试文件路径
pos = './data/aclIMBD.test.pos'
neg = './data/aclIMBD.test.neg'

# 处理csv测试文件
headers=['content']
pos_data = TextManage(pos)
neg_data = TextManage(neg)
save = pd.DataFrame({'label': [1] * 100 + [0] * 100, 'content': pos_data + neg_data})
save.to_csv('./data/IMBDtest.csv', index=False, sep=',')

最终生成的训练集文件展示如下(此处pycharm换成Github样式要稍微能看清楚一些):

构造用于二分类的模型

一开始这里我尝试用吴恩达老师图像分类里的公式来进行计算,但是文本和图片的数据格式存在差别,图片大小是固定的,然而文本大小是不固定的,暂时我没想到解决办法,所以这里使用了skit-learn这个库来解决了构造向量和LogisticRegression的问题。
代码的实现有参考深度之眼课程教学视频。
完整代码如下:

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
#!/usr/bin/env python
#coding:utf-8

import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import CountVectorizer

df_train=pd.read_csv('./data/IMBDtrain.csv')
df_test=pd.read_csv('./data/IMBDtest.csv')
vectorizer=CountVectorizer(ngram_range=(1,2),min_df=3,max_df=0.9,max_features=100000)
# 使用 ngram_range 来构建词表
vectorizer.fit(df_train['content'])
x_train=vectorizer.transform(df_train['content'])
x_test=vectorizer.transform(df_test['content'])
y_train=df_train['label']

lg=LogisticRegression(C=4,dual=True)
lg.fit(x_train,y_train)

y_test=lg.predict(x_test)
df_test['label']=y_test.tolist()
df_result=df_test.loc[:,['label','content']]
df_result.to_csv('./data/result.csv',index=False)

print('Done.')

Logistic Regression 多类文本分类

学习样例来源于“达观杯”文本智能处理赛,代码来源于深度之眼学习课程。
达观杯比赛地址

课程提供的学习代码如下:

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
27
28
29
#!/usr/bin/env python
#coding:utf-8

import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import CountVectorizer

df_train=pd.read_csv('./dataset/train_set.csv')
df_test=pd.read_csv('./dataset/test_set.csv')
df_train.drop(columns=['article','id'],inplace=True)
print(df_train.shape)
df_test.drop(columns=['article'],inplace=True)

vectorizer=CountVectorizer(ngram_range=(1,2),min_df=3,max_df=0.9,max_features=100000)
vectorizer.fit(df_train['word_seg'])
x_train=vectorizer.transform(df_train['word_seg'])
x_test=vectorizer.transform(df_test['word_seg'])
y_train=df_train['class']-1

lg=LogisticRegression(C=4,dual=True)
lg.fit(x_train,y_train)

y_test=lg.predict(x_test)
df_test['class']=y_test.tolist()
df_test['class']=df_test['class']+1
df_result=df_test.loc[:,['id','class']]
df_result.to_csv('./result/result1.csv',index=False)

print("Done.")

Logistic Regression得出结果的最终得分是:0.73262,第一名的得分是0.80598,差距大约在0.7左右,然而Logistic Regression结果的排名在1915名,并不是一个理想的名次。