python predictabel_Python3《机器学习实战》学习笔记(五):朴素贝叶斯实战篇之新浪新闻分类...

)

p1Vect = np.log(p1Num/p1Denom) #取对数,防止下溢出 p0Vect = np.log(p0Num/p0Denom) return p0Vect,p1Vect,pAbusive #返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率 """

函数说明:接收一个大字符串并将其解析为字符串列表

Parameters:

Returns:

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-14

""" def textParse(bigString): #将字符串转换为字符列表 listOfTokens = re.split(r'\W*', bigString) #将特殊符号作为切分标志进行字符串切分,即非字母、非数字 return [tok.lower() for tok in listOfTokens if len(tok) > 2] #除了单个字母,例如大写的I,其它单词变成小写 """

函数说明:测试朴素贝叶斯分类器

Parameters:

Returns:

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-14

""" def spamTest(): docList = []; classList = []; fullText = [] for i in range(1, 26): #遍历25个txt文件 wordList = textParse(open('email/spam/%d.txt' % i, 'r').read()) #读取每个垃圾邮件,并字符串转换成字符串列表 docList.append(wordList)

fullText.append(wordList)

classList.append(1) #标记垃圾邮件,1表示垃圾文件 wordList = textParse(open('email/ham/%d.txt' % i, 'r').read()) #读取每个非垃圾邮件,并字符串转换成字符串列表 docList.append(wordList)

fullText.append(wordList)

classList.append(0) #标记非垃圾邮件,1表示垃圾文件 vocabList = createVocabList(docList) #创建词汇表,不重复 trainingSet = list(range(50)); testSet = [] #创建存储训练集的索引值的列表和测试集的索引值的列表 for i in range(10): #从50个邮件中,随机挑选出40个作为训练集,10个做测试集 randIndex = int(random.uniform(0, len(trainingSet))) #随机选取索索引值 testSet.append(trainingSet[randIndex]) #添加测试集的索引值 del(trainingSet[randIndex]) #在训练集列表中删除添加到测试集的索引值 trainMat = []; trainClasses = [] #创建训练集矩阵和训练集类别标签系向量 for docIndex in trainingSet: #遍历训练集 trainMat.append(setOfWords2Vec(vocabList, docList[docIndex])) #将生成的词集模型添加到训练矩阵中 trainClasses.append(classList[docIndex]) #将类别添加到训练集类别标签系向量中 p0V, p1V, pSpam = trainNB0(np.array(trainMat), np.array(trainClasses)) #训练朴素贝叶斯模型 errorCount = 0 #错误分类计数 for docIndex in testSet: #遍历测试集 wordVector = setOfWords2Vec(vocabList, docList[docIndex]) #测试集的词集模型 if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]: #如果分类错误 errorCount += 1 #错误计数加1 print("分类错误的测试集:",docList[docIndex])

print('错误率:%.2f%%' % (float(errorCount) / len(testSet) * 100)) if __name__ == '__main__':

spamTest()

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

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

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

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

运行结果如下:

函数spamTest()会输出在10封随机选择的电子邮件上的分类错误概率。既然这些电子邮件是随机选择的,所以每次的输出结果可能有些差别。如果发现错误的话,函数会输出错误的文档的此表,这样就可以了解到底是哪篇文档发生了错误。如果想要更好地估计错误率,那么就应该将上述过程重复多次,比如说10次,然后求平均值。相比之下,将垃圾邮件误判为正常邮件要比将正常邮件归为垃圾邮件好。为了避免错误,有多种方式可以用来修正分类器,这些内容会在后续文章中进行讨论。

四 朴素贝叶斯之新浪新闻分类(Sklearn)

1 中文语句切分

考虑一个问题,英文的语句可以通过非字母和非数字进行切分,但是汉语句子呢?就比如我打的这一堆字,该如何进行切分呢?我们自己写个规则?

幸运地是,这部分的工作不需要我们自己做了,可以直接使用第三方分词组件,即jieba,没错就是”结巴”。

jieba已经兼容Python2和Python3,使用如下指令直接安装即可:

pip3 install jieba

1

1

python中文分词组件使用简单:

数据集已经做好分类,分文件夹保存,分类结果如下:

数据集已经准备好,接下来,让我们直接进入正题。切分中文语句,编写如下代码:

# -*- coding: UTF-8 -*- import os import jieba def TextProcessing(folder_path): folder_list = os.listdir(folder_path) #查看folder_path下的文件 data_list = [] #训练集 class_list = [] #遍历每个子文件夹 for folder in folder_list:

new_folder_path = os.path.join(folder_path, folder) #根据子文件夹,生成新的路径 files = os.listdir(new_folder_path) #存放子文件夹下的txt文件的列表 j = 1 #遍历每个txt文件 for file in files: if j > 100: #每类txt样本数最多100个 break with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f: #打开txt文件 raw = f.read()

word_cut = jieba.cut(raw, cut_all = False) #精简模式,返回一个可迭代的generator word_list = list(word_cut) #generator转换为list data_list.append(word_list)

class_list.append(folder)

j += 1 print(data_list)

print(class_list) if __name__ == '__main__': #文本预处理 folder_path = './SogouC/Sample' #训练集存放地址 TextProcessing(folder_path)

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

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

代码运行结果如下所示,可以看到,我们已经顺利将每个文本进行切分,并进行了类别标记。

2 文本特征选择

我们将所有文本分成训练集和测试集,并对训练集中的所有单词进行词频统计,并按降序排序。也就是将出现次数多的词语在前,出现次数少的词语在后进行排序。编写代码如下:

# -*- coding: UTF-8 -*- import os import random import jieba """

函数说明:中文文本处理

Parameters:

folder_path - 文本存放的路径

test_size - 测试集占比,默认占所有数据集的百分之20

Returns:

all_words_list - 按词频降序排序的训练集列表

train_data_list - 训练集列表

test_data_list - 测试集列表

train_class_list - 训练集标签列表

test_class_list - 测试集标签列表

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-22

""" def TextProcessing(folder_path, test_size = 0.2): folder_list = os.listdir(folder_path) #查看folder_path下的文件 data_list = [] #数据集数据 class_list = [] #数据集类别 #遍历每个子文件夹 for folder in folder_list:

new_folder_path = os.path.join(folder_path, folder) #根据子文件夹,生成新的路径 files = os.listdir(new_folder_path) #存放子文件夹下的txt文件的列表 j = 1 #遍历每个txt文件 for file in files: if j > 100: #每类txt样本数最多100个 break with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f: #打开txt文件 raw = f.read()

word_cut = jieba.cut(raw, cut_all = False) #精简模式,返回一个可迭代的generator word_list = list(word_cut) #generator转换为list data_list.append(word_list) #添加数据集数据 class_list.append(folder) #添加数据集类别 j += 1 data_class_list = list(zip(data_list, class_list)) #zip压缩合并,将数据与标签对应压缩 random.shuffle(data_class_list) #将data_class_list乱序 index = int(len(data_class_list) * test_size) + 1 #训练集和测试集切分的索引值 train_list = data_class_list[index:] #训练集 test_list = data_class_list[:index] #测试集 train_data_list, train_class_list = zip(*train_list) #训练集解压缩 test_data_list, test_class_list = zip(*test_list) #测试集解压缩 all_words_dict = {} #统计训练集词频 for word_list in train_data_list: for word in word_list: if word in all_words_dict.keys():

all_words_dict[word] += 1 else:

all_words_dict[word] = 1 #根据键的值倒序排序 all_words_tuple_list = sorted(all_words_dict.items(), key = lambda f:f[1], reverse = True)

all_words_list, all_words_nums = zip(*all_words_tuple_list) #解压缩 all_words_list = list(all_words_list) #转换成列表 return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list if __name__ == '__main__': #文本预处理 folder_path = './SogouC/Sample' #训练集存放地址 all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)

print(all_words_list)

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

74

75

76

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

74

75

76

all_words_list就是将所有训练集的切分结果通过词频降序排列构成的单词合集。观察一下打印结果,不难发现,这里包含了很多标点符号,很显然,这些标点符号是不能作为新闻分类的特征的。总不能说,应为这个文章逗号多,所以它是xx类新闻吧?为了降低这些高频的符号对分类结果的影响,我们应该怎么做呢?答曰:抛弃他们! 除了这些,还有”在”,”了”这样对新闻分类无关痛痒的词。并且还有一些数字,数字显然也不能作为分类新闻的特征。所以要消除它们对分类结果的影响,我们可以定制一个规则。

一个简单的规则可以这样制定:首先去掉高频词,至于去掉多少个高频词,我们可以通过观察去掉高频词个数和最终检测准确率的关系来确定。除此之外,去除数字,不把数字作为分类特征。同时,去除一些特定的词语,比如:”的”,”一”,”在”,”不”,”当然”,”怎么”这类的对新闻分类无影响的介词、代词、连词。怎么去除这些词呢?可以使用已经整理好的stopwords_cn.txt文本。下载地址:https://github.com/Jack-Cherish/Machine-Learning/blob/master/Naive%20Bayes/stopwords_cn.txt

这个文件是这个样子的:

所以我们可以根据这个文档,将这些单词去除,不作为分类的特征。我们先去除前100个高频词汇,然后编写代码如下:

# -*- coding: UTF-8 -*- import os import random import jieba """

函数说明:中文文本处理

Parameters:

folder_path - 文本存放的路径

test_size - 测试集占比,默认占所有数据集的百分之20

Returns:

all_words_list - 按词频降序排序的训练集列表

train_data_list - 训练集列表

test_data_list - 测试集列表

train_class_list - 训练集标签列表

test_class_list - 测试集标签列表

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-22

""" def TextProcessing(folder_path, test_size = 0.2): folder_list = os.listdir(folder_path) #查看folder_path下的文件 data_list = [] #数据集数据 class_list = [] #数据集类别 #遍历每个子文件夹 for folder in folder_list:

new_folder_path = os.path.join(folder_path, folder) #根据子文件夹,生成新的路径 files = os.listdir(new_folder_path) #存放子文件夹下的txt文件的列表 j = 1 #遍历每个txt文件 for file in files: if j > 100: #每类txt样本数最多100个 break with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f: #打开txt文件 raw = f.read()

word_cut = jieba.cut(raw, cut_all = False) #精简模式,返回一个可迭代的generator word_list = list(word_cut) #generator转换为list data_list.append(word_list) #添加数据集数据 class_list.append(folder) #添加数据集类别 j += 1 data_class_list = list(zip(data_list, class_list)) #zip压缩合并,将数据与标签对应压缩 random.shuffle(data_class_list) #将data_class_list乱序 index = int(len(data_class_list) * test_size) + 1 #训练集和测试集切分的索引值 train_list = data_class_list[index:] #训练集 test_list = data_class_list[:index] #测试集 train_data_list, train_class_list = zip(*train_list) #训练集解压缩 test_data_list, test_class_list = zip(*test_list) #测试集解压缩 all_words_dict = {} #统计训练集词频 for word_list in train_data_list: for word in word_list: if word in all_words_dict.keys():

all_words_dict[word] += 1 else:

all_words_dict[word] = 1 #根据键的值倒序排序 all_words_tuple_list = sorted(all_words_dict.items(), key = lambda f:f[1], reverse = True)

all_words_list, all_words_nums = zip(*all_words_tuple_list) #解压缩 all_words_list = list(all_words_list) #转换成列表 return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list """

函数说明:读取文件里的内容,并去重

Parameters:

words_file - 文件路径

Returns:

words_set - 读取的内容的set集合

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-22

""" def MakeWordsSet(words_file): words_set = set() #创建set集合 with open(words_file, 'r', encoding = 'utf-8') as f: #打开文件 for line in f.readlines(): #一行一行读取 word = line.strip() #去回车 if len(word) > 0: #有文本,则添加到words_set中 words_set.add(word) return words_set #返回处理结果 """

函数说明:文本特征选取

Parameters:

all_words_list - 训练集所有文本列表

deleteN - 删除词频最高的deleteN个词

stopwords_set - 指定的结束语

Returns:

feature_words - 特征集

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-22

""" def words_dict(all_words_list, deleteN, stopwords_set = set()): feature_words = [] #特征列表 n = 1 for t in range(deleteN, len(all_words_list), 1): if n > 1000: #feature_words的维度为1000 break #如果这个词不是数字,并且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词 if not all_words_list[t].isdigit() and all_words_list[t] not in stopwords_set and 1 < len(all_words_list[t]) < 5:

feature_words.append(all_words_list[t]) return feature_words if __name__ == '__main__': #文本预处理 folder_path = './SogouC/Sample' #训练集存放地址 all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2) #生成stopwords_set stopwords_file = './stopwords_cn.txt' stopwords_set = MakeWordsSet(stopwords_file)

feature_words = words_dict(all_words_list, 100, stopwords_set)

print(feature_words)

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

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

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

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

运行结果如下:

可以看到,我们已经滤除了那些没有用的词组,这个feature_words就是我们最终选出的用于新闻分类的特征。随后,我们就可以根据feature_words,将文本向量化,然后用于训练朴素贝叶斯分类器。这个向量化的思想和第三章的思想一致,因此不再累述。

3 使用Sklearn构建朴素贝叶斯分类器

数据已经处理好了,接下来就可以使用sklearn构建朴素贝叶斯分类器了。

朴素贝叶斯是一类比较简单的算法,scikit-learn中朴素贝叶斯类库的使用也比较简单。相对于决策树,KNN之类的算法,朴素贝叶斯需要关注的参数是比较少的,这样也比较容易掌握。在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。上篇文章讲解的先验概率模型就是先验概率为多项式分布的朴素贝叶斯。

对于新闻分类,属于多分类问题。我们可以使用MultinamialNB()完成我们的新闻分类问题。另外两个函数的使用暂且不再进行扩展,可以自行学习。MultinomialNB假设特征的先验概率为多项式分布,即如下式:

其中,P(Xj = Xjl | Y = Ck)是第k个类别的第j维特征的第l个取值条件概率。mk是训练集中输出为第k类的样本个数。λ为一个大于0的常数,尝尝取值为1,即拉普拉斯平滑,也可以取其他值。

接下来,我们看下MultinamialNB这个函数,只有3个参数:

参数说明如下:

alpha:浮点型可选参数,默认为1.0,其实就是添加拉普拉斯平滑,即为上述公式中的λ ,如果这个参数设置为0,就是不添加平滑;

fit_prior:布尔型可选参数,默认为True。布尔参数fit_prior表示是否要考虑先验概率,如果是false,则所有的样本类别输出都有相同的类别先验概率。否则可以自己用第三个参数class_prior输入先验概率,或者不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率,此时的先验概率为P(Y=Ck)=mk/m。其中m为训练集样本总数量,mk为输出为第k类别的训练集样本数。

class_prior:可选参数,默认为None。总结如下:

fit_priorclass_prior最终先验概率

False填或不填没有意义P(Y = Ck) = 1 / k

True不填P(Y = Ck) = mk / m

True填P(Y = Ck) = class_prior除此之外,MultinamialNB也有一些方法供我们使用:

MultinomialNB一个重要的功能是有partial_fit方法,这个方法的一般用在如果训练集数据量非常大,一次不能全部载入内存的时候。这时我们可以把训练集分成若干等分,重复调用partial_fit来一步步的学习训练集,非常方便。GaussianNB和BernoulliNB也有类似的功能。 在使用MultinomialNB的fit方法或者partial_fit方法拟合数据后,我们可以进行预测。此时预测有三种方法,包括predict,predict_log_proba和predict_proba。predict方法就是我们最常用的预测方法,直接给出测试集的预测类别输出。predict_proba则不同,它会给出测试集样本在各个类别上预测的概率。容易理解,predict_proba预测出的各个类别概率里的最大值对应的类别,也就是predict方法得到类别。predict_log_proba和predict_proba类似,它会给出测试集样本在各个类别上预测的概率的一个对数转化。转化后predict_log_proba预测出的各个类别对数概率里的最大值对应的类别,也就是predict方法得到类别。具体细节不再讲解,可参照官网手册。

了解了这些,我们就可以编写代码,通过观察取不同的去掉前deleteN个高频词的个数与最终检测准确率的关系,确定deleteN的取值:

# -*- coding: UTF-8 -*- from sklearn.naive_bayes import MultinomialNB import matplotlib.pyplot as plt import os import random import jieba """

函数说明:中文文本处理

Parameters:

folder_path - 文本存放的路径

test_size - 测试集占比,默认占所有数据集的百分之20

Returns:

all_words_list - 按词频降序排序的训练集列表

train_data_list - 训练集列表

test_data_list - 测试集列表

train_class_list - 训练集标签列表

test_class_list - 测试集标签列表

Author:

Jack Cui

Blog:

https://blog.csdn.net/c406495762

Modify:

2017-08-22

""" def TextProcessing(folder_path, test_size = 0.2): folder_list = os.listdir(folder_path) #查看folder_path下的文件 data_list = [] #数据集数据 class_list = [] #数据集类别 #遍历每个子文件夹 for folder in folder_list:

new_folder_path = os.path.join(folder_path, folder) #根据子文件夹,生成新的路径 files = os.listdir(new_folder_path) #存放子文件夹下的txt文件的列表 j = 1 #遍历每个txt文件 for file in files: if j > 100: #每类txt样本数最多100个 break with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f: #打开txt文件 raw = f.read()

word_cut = jieba.cut(raw, cut_all = False) #精简模式,返回一个可迭代的generator word_list = list(word_cut) #generator转换为list data_list.append(word_list) #添加数据集数据 class_list.append(folder) #添加数据集类别 j += 1 data_class_list = list(zip(data_list, class_list)) #zip压缩合并,将数据与标签对应压缩 random.shuffle(data_class_list) #将data_class_list乱序 index = int(len(data_class_list) * test_size) + 1 #训练集和测试集切分的索引值 train_list = data_class_list[index:]

本文标题:Python3《机器学习实战》学习笔记(五):朴素贝叶斯实战篇之新浪新闻分类

本文作者:Mr丶苏泽

本文来自:蚁安黑客官网

转载请注明本文链接:http://www.mayidui.net/t908.html

你可能感兴趣的:(python,predictabel)