-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
598 lines (502 loc) · 70.6 KB
/
Copy pathindex.html
File metadata and controls
598 lines (502 loc) · 70.6 KB
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
<!DOCTYPE html>
<html lang="en">
<head>
<!-- hexo-inject:begin --><!-- hexo-inject:end --><title>fyrhythm'blog</title>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
<link rel="shortcut icon" href="/favicon.ico" type="image/png" />
<meta property="og:type" content="website">
<meta property="og:title" content="fyrhythm'blog">
<meta property="og:url" content="http://github.com/fyering/fyering.github.io.git/index.html">
<meta property="og:site_name" content="fyrhythm'blog">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="fyrhythm">
<meta name="twitter:card" content="summary">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/combine/gh/nexmoe/nexmoe.github.io@latest/css/style.css,npm/highlight.js@9.15.8/styles/atom-one-dark.css,gh/nexmoe/nexmoe.github.io@latest/lib/mdui_043tiny/css/mdui.css,gh/nexmoe/nexmoe.github.io@latest/lib/iconfont/iconfont.css" crossorigin>
<!--<link rel="stylesheet" href="/css/style.css?v=1583906464370">-->
<meta name="generator" content="Hexo 4.2.0"><!-- hexo-inject:begin --><!-- hexo-inject:end --></head>
<body class="mdui-drawer-body-left">
<!-- hexo-inject:begin --><!-- hexo-inject:end --><div id="nexmoe-background">
<div class="nexmoe-bg" style="background-image: url(https://s2.ax1x.com/2020/02/24/38jY0U.jpg)"></div>
<div class="mdui-appbar mdui-shadow-0">
<div class="mdui-toolbar">
<a mdui-drawer="{target: '#drawer', swipe: true}" title="menu" class="mdui-btn mdui-btn-icon mdui-ripple"><i class="mdui-icon nexmoefont icon-menu"></i></a>
<div class="mdui-toolbar-spacer"></div>
<!--<a href="javascript:;" class="mdui-btn mdui-btn-icon"><i class="mdui-icon material-icons">search</i></a>-->
<a href="/" title="fyrhythm" class="mdui-btn mdui-btn-icon"><img src="http://www.weimeitupian.com/wp-content/uploads/2018/06/2018060808341930.jpg" alt="fyrhythm"></a>
</div>
</div>
</div>
<div id="nexmoe-header">
<div class="nexmoe-drawer mdui-drawer" id="drawer">
<div class="nexmoe-avatar mdui-ripple">
<a href="/" title="fyrhythm">
<img src="http://www.weimeitupian.com/wp-content/uploads/2018/06/2018060808341930.jpg" alt="fyrhythm" alt="fyrhythm">
</a>
</div>
<div class="nexmoe-count">
<div><span>Articles</span>5</div>
<div><span>Tags</span>2</div>
<div><span>Categories</span>1</div>
</div>
<div class="nexmoe-list mdui-list" mdui-collapse="{accordion: true}">
<a class="nexmoe-list-item mdui-list-item mdui-ripple" href="/" title="回到首页">
<i class="mdui-list-item-icon nexmoefont icon-home"></i>
<div class="mdui-list-item-content">
回到首页
</div>
</a>
<a class="nexmoe-list-item mdui-list-item mdui-ripple" href="/archives" title="文章归档">
<i class="mdui-list-item-icon nexmoefont icon-container"></i>
<div class="mdui-list-item-content">
文章归档
</div>
</a>
</div>
<aside id="nexmoe-sidebar">
<div class="nexmoe-widget-wrap">
<div class="nexmoe-widget nexmoe-search">
<form id="search_form" action_e="https://cn.bing.com/search?q=site:nexmoe.com" onsubmit="return search();">
<label><input id="search_value" name="q" type="search" placeholder="Search"></label>
</form>
</div>
</div>
<div class="nexmoe-widget-wrap">
<h3 class="nexmoe-widget-title">Social</h3>
<div class="nexmoe-widget nexmoe-social">
<a class="mdui-ripple" href="https://space.bilibili.com/133000099" target="_blank" mdui-tooltip="{content: '哔哩哔哩'}" style="color: rgb(231, 106, 141);background-color: rgba(231, 106, 141, .15);">
<i class="nexmoefont icon-bilibili"></i>
</a><a class="mdui-ripple" href="https://github.com/fyering" target="_blank" mdui-tooltip="{content: 'GitHub'}" style="color: rgb(25, 23, 23);background-color: rgba(25, 23, 23, .15);">
<i class="nexmoefont icon-github"></i>
</a>
</div>
</div>
<div class="nexmoe-widget-wrap">
<h3 class="nexmoe-widget-title">Categories</h3>
<div class="nexmoe-widget">
<ul class="category-list">
<li class="category-list-item">
<a class="category-list-link" href="/categories/数据挖掘与机器学习/">数据挖掘与机器学习</a>
<span class="category-list-count">4</span>
</li>
</ul>
</div>
</div>
<div class="nexmoe-widget-wrap">
<h3 class="nexmoe-widget-title">Tag Cloud</h3>
<div id="randomtagcloud" class="nexmoe-widget tagcloud">
<a href="/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/" style="font-size: 10px;">机器学习</a> <a href="/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%EF%BC%8C%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/" style="font-size: 20px;">机器学习,数据挖掘</a>
</div>
</div>
<div class="nexmoe-widget-wrap">
<h3 class="nexmoe-widget-title">Archive</h3>
<div class="nexmoe-widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/03/">March 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/02/">February 2020</a></li></ul>
</div>
</div>
</aside>
<div class="nexmoe-copyright">
© 2020 fyrhythm
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
& <a href="https://nexmoe.com/hexo-theme-nexmoe.html" target="_blank">Nexmoe</a>
</div>
</div><!-- .nexmoe-drawer -->
</div>
<div id="nexmoe-content">
<div class="nexmoe-primary">
<section class="nexmoe-posts">
<div class="nexmoe-post">
<a href="/2020/03/11/Pycharm-%E5%AE%89%E8%A3%85CV2/">
<div class="nexmoe-post-cover mdui-ripple" style="padding-bottom: 66.66666666666666%;">
<img data-src="https://s2.ax1x.com/2020/02/24/38jY0U.jpg" data-sizes="auto" alt="Pycharm 安装CV2" class="lazyload">
<h1>Pycharm 安装CV2</h1>
</div>
</a>
<div class="nexmoe-post-meta">
<a><i class="nexmoefont icon-calendar-fill"></i>2020年03月11日</a>
<a><i class="nexmoefont icon-areachart"></i>9 字</a>
<a><i class="nexmoefont icon-time-circle-fill"></i>大概 1 分钟</a>
</div>
<article>
<h1 id="Pycharm安装CV2"><a href="#Pycharm安装CV2" class="headerlink" title="Pycharm安装CV2"></a>Pycharm安装CV2</h1><p><a href="https://imgchr.com/i/8kTKkF" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/03/11/8kTKkF.md.png" alt="8kTKkF.md.png" class="lazyload"></a></p>
<p>直接安装opencv-python</p>
</article>
</div>
<div class="nexmoe-post">
<a href="/2020/03/04/%E5%9F%BA%E4%BA%8E%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF%E7%9A%84%E5%9E%83%E5%9C%BE%E9%82%AE%E4%BB%B6%E6%A3%80%E6%B5%8B/">
<div class="nexmoe-post-cover mdui-ripple" style="padding-bottom: 66.66666666666666%;">
<img data-src="https://s2.ax1x.com/2020/02/24/38jY0U.jpg" data-sizes="auto" alt="基于朴素贝叶斯的垃圾邮件检测" class="lazyload">
<h1>基于朴素贝叶斯的垃圾邮件检测</h1>
</div>
</a>
<div class="nexmoe-post-meta">
<a><i class="nexmoefont icon-calendar-fill"></i>2020年03月04日</a>
<a><i class="nexmoefont icon-areachart"></i>2.5k 字</a>
<a><i class="nexmoefont icon-time-circle-fill"></i>大概 11 分钟</a>
</div>
<article>
<h1 id="基于朴素贝叶斯的垃圾邮件检测"><a href="#基于朴素贝叶斯的垃圾邮件检测" class="headerlink" title="基于朴素贝叶斯的垃圾邮件检测"></a>基于朴素贝叶斯的垃圾邮件检测</h1><h2 id="一、词袋模型"><a href="#一、词袋模型" class="headerlink" title="一、词袋模型"></a>一、词袋模型</h2><p>文本分类需要寻找文本的特征,而词袋模型就是表示文本特征的一种方式。给定一篇文档,它会有很多特征,比如文档中每个单词出现的次数,某些单词出现的位置、单词的长度等,而词袋模型只考虑一篇文档中单词出现的频率(次数),用每个单词出现的频率作为文档的特征。</p>
<p>与词袋模型非常类似的一个模型是<strong>词集模型(Set of Words,简称SoW)</strong>,和词袋模型唯一的不同是它仅仅考虑词是否在文本中出现,而不考虑词频。也就是一个词在文本中出现1次和多次特征处理是一样的。在大多数时候,我们使用词袋模型,后面的讨论也是以词袋模型为主。</p>
<p>词袋模型有很大的局限性,因为它仅仅考虑了词频,没有考虑上下文的关系,因此会丢失一部分文本的语义。但是大多数时候,如果我们的目的是分类聚类,则词袋模型表现的很好。</p>
<p>词袋模型的三部曲:<strong>分词(tokenizing),统计修订词特征值(counting)与标准化(normalizing)。</strong></p>
<h2 id="1-1分词"><a href="#1-1分词" class="headerlink" title="1.1分词"></a>1.1分词</h2><p>使用正则表达式</p>
<p>\W<em>:表示匹配所有除字母数字下划线的所有字符即特殊字符,\</em>表示可以匹配0和多次</p>
<p>\d+:表示匹配0-9的数字,可匹配1到无数次</p>
<p>使用python 的re模块对文本进行分词,如下:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">file_object=open(filepath)</span><br><span class="line"> file_content=file_object.read()</span><br><span class="line"> str_nonnum=re.sub(<span class="string">r'\d+'</span>,<span class="string">''</span>,file_content)<span class="comment">#替换所有数字为空</span></span><br><span class="line"> token_list=re.split(<span class="string">r'\W'</span>,str_nonnum)<span class="comment">#使用特殊字符作为间隔划分单词</span></span><br><span class="line"> token_list=[token.lower() <span class="keyword">for</span> token <span class="keyword">in</span> token_list <span class="keyword">if</span> token!=<span class="string">''</span>]<span class="comment">#消除’‘空字符</span></span><br><span class="line"> print(token_list)</span><br></pre></td></tr></table></figure>
<h2 id="1-2-构造单词集合"><a href="#1-2-构造单词集合" class="headerlink" title="1.2 构造单词集合"></a>1.2 构造单词集合</h2><p>使用python的set集合,是一个不重复的元素集。对所有文档进行分词处理,构造无重复单词的单词库,单词库即训练集样本的所有特征。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#对所有邮件进行分词处理,并形成一个整体的词汇表</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">bagOfWord</span><span class="params">(doclist)</span>:</span></span><br><span class="line"> wordsList=set([])</span><br><span class="line"> <span class="keyword">for</span> wordlist <span class="keyword">in</span> doclist:</span><br><span class="line"> wordsList=wordsList|set(wordlist)<span class="comment">#求并集</span></span><br><span class="line"> print(wordsList)</span><br><span class="line"> <span class="keyword">return</span> list(wordsList)</span><br></pre></td></tr></table></figure>
<h2 id="1-3词袋模型"><a href="#1-3词袋模型" class="headerlink" title="1.3词袋模型"></a>1.3词袋模型</h2><p>为每个训练样本即邮件文本构造词袋模型,得到属于该样本文档的文档向量,向量长度即词袋中所有单词的数量。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">vecofwords</span><span class="params">(wordslist,inputset)</span>:</span></span><br><span class="line"> returnvec=np.zeros(len(wordslist)) <span class="comment">#创建一个长度和词汇表一样的向量,并置初值为0</span></span><br><span class="line"> <span class="keyword">for</span> word <span class="keyword">in</span> inputset:</span><br><span class="line"> <span class="keyword">if</span> word <span class="keyword">in</span> wordslist:</span><br><span class="line"> returnvec[wordslist.index(word)]+=<span class="number">1</span><span class="comment">#累加单词出现的次数</span></span><br><span class="line"> <span class="keyword">return</span> returnvec</span><br></pre></td></tr></table></figure>
<h2 id="1-4训练贝叶斯模型"><a href="#1-4训练贝叶斯模型" class="headerlink" title="1.4训练贝叶斯模型"></a>1.4训练贝叶斯模型</h2><p>将输入的训练样本构造成文档向量后,可以根据这些文档向量构造一个训练矩阵,矩阵的行数为训练样本数量,矩阵列数为特征属性数量。输入训练矩阵和训练样本的标签数组,就可以训练模型了。</p>
<p><strong>unknow words的情形</strong></p>
<p>假设只考虑文本二分类:将文档分成 positve类别,或者negative类别,C={positive, negative}</p>
<p>在训练数据集中,类别为positive的所有文档 都没有 包含 单词wi = fantastic(fantastic可能出现在类别为negative的文档中)那么 count(wi=fantastic,ci=positive)=0 。那么:</p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/03/04/3IHTQU.png" alt="3IHTQU.png" class="lazyload"></p>
<p>如果文档d中有个单词在类别为c的训练数据集文档中从未出现过,那文档d被分类到类别c的概率为0,尽管文档d中还有一些其他单词(特征),而这些单词所代表的特征认为文档d应该被分类 到 类别c中。</p>
<p>解决方法:拉普拉斯平滑</p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/03/04/3Ib8kn.png" alt="3Ib8kn.png" class="lazyload"></p>
<p>其中|V|是词库中所有单词的个数。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">NBtraining</span><span class="params">(trianMatrix,trianClasses)</span>:</span></span><br><span class="line"> <span class="comment">#得到训练样本的数量</span></span><br><span class="line"> trainNum=len(trianClasses)</span><br><span class="line"> <span class="comment">#得到样本的特征属性数量</span></span><br><span class="line"> wordsnum=len(trianMatrix[<span class="number">0</span>])</span><br><span class="line"> <span class="comment">#垃圾邮件的先验概率</span></span><br><span class="line"> plj=sum(trianClasses)/float(trainNum)</span><br><span class="line"> <span class="comment">#垃圾邮件的似然概率分子数组:P(W0|C1),P(W1|C1),P(W2|C1).....</span></span><br><span class="line"> pspam=np.ones(wordsnum)</span><br><span class="line"> <span class="comment">#非垃圾邮件的似然概率分子组:P(W0|C0),P(W1|C0),P(W2|C0).....</span></span><br><span class="line"> pham=np.ones(wordsnum)</span><br><span class="line"> <span class="comment">#似然概率的分母</span></span><br><span class="line"> totalsapm=wordsnum</span><br><span class="line"> totalham=wordsnum<span class="comment">#使用拉普拉斯平滑</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(trainNum):</span><br><span class="line"> <span class="keyword">if</span> trianClasses[i]==<span class="number">1</span>:<span class="comment">#如果该样本是垃圾邮件,则计算垃圾邮件的似然概率p(W0|C)...</span></span><br><span class="line"> pspam+=trianMatrix[i]</span><br><span class="line"> totalsapm+=sum(trianMatrix[i])</span><br><span class="line"> <span class="keyword">if</span> trianClasses[i]==<span class="number">0</span>:<span class="comment">#非垃圾邮件</span></span><br><span class="line"> pham+=trianMatrix[i]</span><br><span class="line"> totalham+=sum(trianMatrix[i])</span><br><span class="line"> <span class="comment">#为了避免溢出,使用log进行对数化</span></span><br><span class="line"> pspamvec=np.log(pspam/totalsapm)</span><br><span class="line"> phamvec=np.log(pham/totalham)</span><br><span class="line"> <span class="keyword">return</span> pspamvec,phamvec,plj</span><br></pre></td></tr></table></figure>
<h2 id="1-5测试集分类"><a href="#1-5测试集分类" class="headerlink" title="1.5测试集分类"></a>1.5测试集分类</h2><p>使用训练出来的模型对测试集进行分类:</p>
<p>testdata是一个测试样本的文档向量,将该文档向量与似然概率数组一一对应相乘</p>
<p>例如,如果testdata中某个单词出现次数为2,则乘以似然概率数组中对应的值,假如是log(P(Wi/C1)),则相乘的结果是2*log(P(Wi|C1))=log(P(Wi|C1)^2),此时假设某个单词出现在文档中不同位置时的概率时一样的,所以P(Wi|C1)的平方。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">ef classifier(testdata,pspamvec,phamvec,plj):</span><br><span class="line"> p1=sum(testdata*pspamvec)+np.log(plj)</span><br><span class="line"> p0=sum(testdata*phamvec)+np.log(<span class="number">1</span>-plj)</span><br><span class="line"> <span class="keyword">if</span> p1>p0:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span> :</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br></pre></td></tr></table></figure>
<h2 id="1-6-完整代码"><a href="#1-6-完整代码" class="headerlink" title="1.6 完整代码"></a>1.6 完整代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">splittxt</span><span class="params">(filepath)</span>:</span></span><br><span class="line"> file_object=open(filepath)</span><br><span class="line"> file_content=file_object.read()</span><br><span class="line"> str_nonnum=re.sub(<span class="string">r'\d+'</span>,<span class="string">''</span>,file_content)<span class="comment">#替换所有数字为空</span></span><br><span class="line"> token_list=re.split(<span class="string">r'\W'</span>,str_nonnum)<span class="comment">#使用特殊字符作为间隔划分单词</span></span><br><span class="line"> token_list=[token.lower() <span class="keyword">for</span> token <span class="keyword">in</span> token_list <span class="keyword">if</span> token!=<span class="string">''</span>]<span class="comment">#消除’‘空字符</span></span><br><span class="line"> print(token_list)</span><br><span class="line"> <span class="keyword">return</span> token_list</span><br><span class="line"></span><br><span class="line"><span class="comment">#对所有邮件进行分词处理,并形成一个整体的词汇表</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">bagOfWord</span><span class="params">(doclist)</span>:</span></span><br><span class="line"> wordsList=set([])</span><br><span class="line"> <span class="keyword">for</span> wordlist <span class="keyword">in</span> doclist:</span><br><span class="line"> wordsList=wordsList|set(wordlist)<span class="comment">#求并集</span></span><br><span class="line"> print(wordsList)</span><br><span class="line"> <span class="keyword">return</span> list(wordsList)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">vecofwords</span><span class="params">(wordslist,inputset)</span>:</span></span><br><span class="line"> returnvec=np.zeros(len(wordslist)) <span class="comment">#创建一个长度和词汇表一样的向量,并置初值为0</span></span><br><span class="line"> <span class="keyword">for</span> word <span class="keyword">in</span> inputset:</span><br><span class="line"> <span class="keyword">if</span> word <span class="keyword">in</span> wordslist:</span><br><span class="line"> returnvec[wordslist.index(word)]+=<span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> returnvec</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">NBtraining</span><span class="params">(trianMatrix,trianClasses)</span>:</span></span><br><span class="line"> <span class="comment">#得到训练样本的数量</span></span><br><span class="line"> trainNum=len(trianClasses)</span><br><span class="line"> <span class="comment">#得到样本的特征属性数量</span></span><br><span class="line"> wordsnum=len(trianMatrix[<span class="number">0</span>])</span><br><span class="line"> <span class="comment">#垃圾邮件的先验概率</span></span><br><span class="line"> plj=sum(trianClasses)/float(trainNum)</span><br><span class="line"> pspam=np.ones(wordsnum)</span><br><span class="line"> pham=np.ones(wordsnum)</span><br><span class="line"> totalsapm=wordsnum</span><br><span class="line"> totalham=wordsnum<span class="comment">#拉普拉斯平滑</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(trainNum):</span><br><span class="line"> <span class="keyword">if</span> trianClasses[i]==<span class="number">1</span>:<span class="comment">#如果该样本是垃圾邮件,则计算垃圾邮件的似然概率p(W0|C)...</span></span><br><span class="line"> pspam+=trianMatrix[i]</span><br><span class="line"> totalsapm+=sum(trianMatrix[i])</span><br><span class="line"> <span class="keyword">if</span> trianClasses[i]==<span class="number">0</span>:<span class="comment">#非垃圾邮件</span></span><br><span class="line"> pham+=trianMatrix[i]</span><br><span class="line"> totalham+=sum(trianMatrix[i])</span><br><span class="line"> <span class="comment">#w为了避免溢出,使用log进行对数化</span></span><br><span class="line"></span><br><span class="line"> pspamvec=np.log(pspam/totalsapm)</span><br><span class="line"> phamvec=np.log(pham/totalham)</span><br><span class="line"> <span class="keyword">return</span> pspamvec,phamvec,plj</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">classifier</span><span class="params">(testdata,pspamvec,phamvec,plj)</span>:</span></span><br><span class="line"> p1=sum(testdata*pspamvec)+np.log(plj)</span><br><span class="line"> p0=sum(testdata*phamvec)+np.log(<span class="number">1</span>-plj)</span><br><span class="line"> <span class="keyword">if</span> p1>p0:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span> :</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">testNBClassifier</span><span class="params">()</span>:</span></span><br><span class="line"> docList = []</span><br><span class="line"> classList = []</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, <span class="number">26</span>): <span class="comment"># 遍历25个txt文件</span></span><br><span class="line"> wordList = splittxt(<span class="string">'D:\\Course\\数据挖掘\\实验\\实验二\\email(1)\\email\\spam\\%d.txt'</span> % i) <span class="comment"># 读取每个垃圾邮件,并字符串转换成字符串列表</span></span><br><span class="line"> docList.append(wordList)</span><br><span class="line"> classList.append(<span class="number">1</span>) <span class="comment"># 标记垃圾邮件,1表示垃圾文件</span></span><br><span class="line"> wordList = splittxt(<span class="string">'D:\\Course\\数据挖掘\\实验\\实验二\\email(1)\\email\\ham\\%d.txt'</span> % i) <span class="comment"># 读取每个非垃圾邮件,并字符串转换成字符串列表</span></span><br><span class="line"> docList.append(wordList)</span><br><span class="line"> classList.append(<span class="number">0</span>) <span class="comment"># 标记正常邮件,0表示正常文件</span></span><br><span class="line"> vocabList = bagOfWord(docList) <span class="comment"># 创建词汇表,不重复</span></span><br><span class="line"> trainingSet = list(range(<span class="number">50</span>))<span class="comment">#0-49</span></span><br><span class="line"> testSet = [] <span class="comment"># 创建存储训练集的索引值的列表和测试集的索引值的列表</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">10</span>): <span class="comment"># 从50个邮件中,随机挑选出40个作为训练集,10个做测试集</span></span><br><span class="line"> randIndex = int(random.uniform(<span class="number">0</span>, len(trainingSet))) <span class="comment"># 随机选取索索引值</span></span><br><span class="line"> testSet.append(trainingSet[randIndex]) <span class="comment"># 添加测试集的索引值</span></span><br><span class="line"> <span class="keyword">del</span> (trainingSet[randIndex]) <span class="comment"># 在训练集列表中删除添加到测试集的索引值</span></span><br><span class="line"> trainMat = []</span><br><span class="line"> trainClasses = [] <span class="comment"># 创建训练集矩阵和训练集类别标签系向量</span></span><br><span class="line"> <span class="keyword">for</span> docIndex <span class="keyword">in</span> trainingSet: <span class="comment"># 遍历训练集</span></span><br><span class="line"> trainMat.append(vecofwords(vocabList, docList[docIndex])) <span class="comment"># 将生成的词集模型添加到训练矩阵中</span></span><br><span class="line"> trainClasses.append(classList[docIndex]) <span class="comment"># 将类别添加到训练集类别标签系向量中</span></span><br><span class="line"> p1V, p0V, pSpam = NBtraining(np.array(trainMat), np.array(trainClasses)) <span class="comment"># 训练朴素贝叶斯模型</span></span><br><span class="line"> errorCount = <span class="number">0</span> <span class="comment"># 错误分类计数</span></span><br><span class="line"> <span class="keyword">for</span> docIndex <span class="keyword">in</span> testSet: <span class="comment"># 遍历测试集</span></span><br><span class="line"> wordVector = vecofwords(vocabList, docList[docIndex]) <span class="comment"># 测试集的词集模型</span></span><br><span class="line"> <span class="keyword">if</span> classifier(np.array(wordVector), p1V, p0V, pSpam) != classList[docIndex]: <span class="comment"># 如果分类错误</span></span><br><span class="line"> errorCount += <span class="number">1</span> <span class="comment"># 错误计数加1</span></span><br><span class="line"> print(<span class="string">"分类错误的测试集:"</span>, docList[docIndex])</span><br><span class="line"> print(<span class="string">'错误率:%.2f%%'</span> % (float(errorCount) / len(testSet) * <span class="number">100</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> testNBClassifier()</span><br></pre></td></tr></table></figure>
<h2 id="1-7运行结果"><a href="#1-7运行结果" class="headerlink" title="1.7运行结果"></a>1.7运行结果</h2><p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/03/04/3ILZM8.png" alt="3ILZM8.png" class="lazyload"></p>
<h2 id="1-8-评价"><a href="#1-8-评价" class="headerlink" title="1.8 评价"></a>1.8 评价</h2><p>朴素贝叶斯的主要优点有:</p>
<p>1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。</p>
<p>2)对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。</p>
<p>3)对缺失数据不太敏感,算法也比较简单,常用于文本分类。</p>
<p>朴素贝叶斯的主要缺点有:</p>
<p>1) 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。</p>
<p>2)需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。</p>
<p>3)由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。</p>
<p>4)对输入数据的表达形式很敏感。</p>
</article>
</div>
<div class="nexmoe-post">
<a href="/2020/02/26/%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF%E4%B8%8E%E5%86%B3%E7%AD%96%E6%A0%91/">
<div class="nexmoe-post-cover mdui-ripple" style="padding-bottom: 66.66666666666666%;">
<img data-src="https://s2.ax1x.com/2020/02/24/38jY0U.jpg" data-sizes="auto" alt="朴素贝叶斯与决策树" class="lazyload">
<h1>朴素贝叶斯与决策树</h1>
</div>
</a>
<div class="nexmoe-post-meta">
<a><i class="nexmoefont icon-calendar-fill"></i>2020年02月26日</a>
<a><i class="nexmoefont icon-areachart"></i>5.2k 字</a>
<a><i class="nexmoefont icon-time-circle-fill"></i>大概 22 分钟</a>
</div>
<article>
<h1 id="贝叶斯分类和决策树模型"><a href="#贝叶斯分类和决策树模型" class="headerlink" title="贝叶斯分类和决策树模型"></a>贝叶斯分类和决策树模型</h1><h2 id="1-分类问题"><a href="#1-分类问题" class="headerlink" title="1.分类问题"></a>1.分类问题</h2><p>(1)分类是一种有监督的学习</p>
<p>input: a vector of features </p>
<p>output: a Boolean value(二分类) or integer(多类)</p>
<p>(2)有监督学习:需要给每个样本打标签</p>
<h2 id="2-贝叶斯定理"><a href="#2-贝叶斯定理" class="headerlink" title="2.贝叶斯定理"></a>2.贝叶斯定理</h2><script type="math/tex; mode=display">
P(A\cup B)=P(A)+P(B)-P(A\cap B)</script><script type="math/tex; mode=display">
P(A\cap B)=P(A|B)P(B)=P(B|A)P(A)</script><script type="math/tex; mode=display">
P(A|B)=\frac{P(B|A)P(A)}{P(B)}</script><p>例1:</p>
<p>A和B射击,击中靶心的概率如下:</p>
<p>P(A):0.6</p>
<p>P(B):0.5</p>
<p>A和B各自射击一次</p>
<p>已知靶心被命中,那么是A命中的概率是多少?</p>
<script type="math/tex; mode=display">
P(A|C)=\frac{P(C|A)P(A)}{P(C)}=\frac{1*0.6}{0.6*0.5+0.6*0.5+0.4*0.5}</script><p>即A中B不中,A不中B中,A和B都中</p>
<p>从事A命中的概率是75%,但是不代表B的概率为25%,因为A命中的概率和B命中的概率并不是互斥的事件。</p>
<p>例2:</p>
<p>H=头疼</p>
<p>F=得流感</p>
<p>P(H)=1/10,P(F)=1/40;P(H|F)=1/2</p>
<p>得流感的情况下50%的人头疼</p>
<p>问头疼有多少概率得流感?</p>
<p>使用贝叶斯定理:</p>
<script type="math/tex; mode=display">
P(F|H)=\frac{P(H|F)P(F)}{P(H)}=\frac{1/2*1/40}{1/10}=1/8</script><p>出现这种结果得原因是头疼和得流感得先验概率不同</p>
<p><a href="https://imgchr.com/i/3GkRSO" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/3GkRSO.png" alt="3GkRSO.png" class="lazyload"></a></p>
<p>如图所示,红色和蓝色交叉部分在得流感中占了1/2,在头疼中占比例很低。</p>
<h2 id="3-朴素贝叶斯分类器"><a href="#3-朴素贝叶斯分类器" class="headerlink" title="3.朴素贝叶斯分类器"></a>3.朴素贝叶斯分类器</h2><p>独立:</p>
<script type="math/tex; mode=display">
P(A\cap B)=P(A)P(B)</script><p>条件独立:</p>
<script type="math/tex; mode=display">
P(A,B|G)=P(A|G)P(B|G)</script><script type="math/tex; mode=display">
P(A|G,B)=P(A|G)</script><p>当G发生的时候,A和B是相互独立的,但是当G不发生的时候,A和B 不一定相互独立。</p>
<p>例:</p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/3Gu4oQ.jpg" alt="3Gu4oQ.jpg" class="lazyload"></p>
<p>当男性抽烟时得肺癌得概率和抽烟(不考虑性别)时得肺癌得概率是相同时,表明得得肺癌的概率只与抽烟有关(假设抽烟是得肺癌的唯一因素),与性别无关。</p>
<p> 朴素贝叶斯假设自变量之间是具有<strong>条件独立性</strong>的,并且在变量是连续情况下以正态分布为假设。</p>
<p><strong>朴素贝叶斯的思想</strong></p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/3GJpMd.png" alt="3GJpMd.png" class="lazyload"></p>
<p>朴素贝叶斯的思想就是根据先验概率计算某个变量属于某个类别的后验概率。</p>
<p>假如,上表中的信息反映的是某P2P企业判断其客户是否会流失(churn),而影响到该变量的因素包含年龄、性别、收入、教育水平、消费频次、支持。那根据这样一个信息,我该如何理解朴素贝叶斯的思想呢?再来看一下朴素贝叶斯公式:</p>
<script type="math/tex; mode=display">
P(Y|X)=\frac{P(X|Y)P(Y)}{P(X)}</script><p>从公式中可知,如果要计算X条件下Y发生的概率,<strong>只需要计算出后面等式的三个部分,X事件的概率(P(X)),是X的先验概率、Y属于某类的概率(P(Y)),是Y的先验概率、以及已知Y的某个分类下,事件X的概率(P(X|Y)),是后验概率</strong>。从上表中,是可以计算这三种概率值的。即:</p>
<p><strong>P(x)</strong>指在所有客户集中,某位22岁的本科女性客户,其月收入为7800元,在12次消费中合计支出4000元的概率;</p>
<p><strong>P(Y)</strong>指流失/不流失在所有客户集中的比例;</p>
<p><strong>P(X|Y)</strong>指在已知流失的情况下,一位22岁的本科女性客户,其月收入为7800元,在12次消费中合计支出4000元的概率。</p>
<p><strong>如果要确定某个样本归属于哪一类,则需要计算出归属不同类的概率,再从中挑选出最大的概率。</strong></p>
<p>我们把上面的贝叶斯公式写出这样,也许你能更好的理解:</p>
<script type="math/tex; mode=display">
max(P(Ci|X))=max(\frac{P(X|Ci)P(Ci)}{P(X)})</script><p>而这个公式告诉我们,<strong>需要计算最大的后验概率,只需要计算出分子的最大值即可</strong>,而不同水平的概率P(C)非常容易获得,故难点就在于P(X|C)的概率计算。而问题的解决,正是聪明之处,<strong>即贝叶斯假设变量X间是条件独立的</strong>,故而P(X|C)的概率就可以计算为:</p>
<script type="math/tex; mode=display">
P(X|Ci)=P(X1|Ci)*P(X 2|Ci)*\cdots *P(Xn|Ci)</script><p><strong>对于离散情况:</strong></p>
<p>假设<strong>已知某个客户流失</strong>的情况下,其性别为女,教育水平为本科的概率:</p>
<script type="math/tex; mode=display">
P(gender=F|churn=Y)=2/4=0.5</script><script type="math/tex; mode=display">
P(edu=BK|churn=Y)=2/4=0.5</script><script type="math/tex; mode=display">
P(gender=F,edu=BK|churn=Y)=0.5*0.5=0.25</script><p><strong>上式结果中的分母4为数据集中流失有4条观测,分子2分别是流失的前提下,女性2名,本科2名。</strong></p>
<p>假设<strong>已知某个客户未流失</strong>的情况下,其性别为女,教育水平为本科的概率</p>
<script type="math/tex; mode=display">
P(gender=F|churn=N)=2/3=0.67</script><script type="math/tex; mode=display">
P(edu=BK|churn=N)=2/3=0.67</script><script type="math/tex; mode=display">
P(gender=F,edu=BK|churn=N)=0.67*0.67=0.44</script><p><strong>上式结果中的分母3为数据集中未流失的观测数,分子2分别是未流失的前提下,女性2名,本科2名。</strong></p>
<p><strong>从而P(C|X)公式中的分子结果为:</strong></p>
<script type="math/tex; mode=display">
P(gender=F,edu=BK|churn=Y)*P(churn=Y)=0.14</script><script type="math/tex; mode=display">
P(gender=F,edu=BK|churn=N)*P(churn=N)=01.8</script><p>对于<strong>连续变量的情况就稍微复杂一点</strong>,并非计算频率这么简单,而是<strong>假设该连续变量服从正态分布(即使很多数据并不满足这个条件)</strong>,先来看一下正态分布的密度函数:</p>
<script type="math/tex; mode=display">
f(x)=\frac{1}{\sqrt(2\pi)}e^\frac{(x-u)^2}{2\sigma^2}</script><p>要计算连续变量中某个数值的概率,只需要已知该变量的均值和标准差,再将该数值带入到上面的公式即可。</p>
<h2 id="4-决策树"><a href="#4-决策树" class="headerlink" title="4.决策树"></a>4.决策树</h2><p>决策树模型:决策树由结点和分支构成,内结点是样本属性的一个切分点,叶子结点是样本被决策树划分之后的类或者类的分布(标签)。使用训练样本构建决策树时,通常采用自顶向下的递归方式。</p>
<p>决策树学习包括三个步骤:</p>
<ul>
<li>1.特征选择(即属性选择,又包括切分点选择)</li>
<li>2.决策树生成</li>
<li>3.决策树的修剪</li>
</ul>
<p>对目标样本,不是所有属性一次性就可以决定分类,而是要一步步的。先从一个特征属性的开始判断,如果能直接分类就ok了,如果不行再选一个特征属性再重复上面的判断。如果前几个特征属性可以直接决定类别,别的特征属性的值就会用不上。那么这时就得思考先从哪个特征属性开始?然后是哪个?再后来是哪个?<br>常用的决策树算法有ID3、C4.5、CART、SLIQ、SPRINT等。<br>要了解这些算法,先得了解一些基本概念:</p>
<p>1.信息熵</p>
<p>信息熵可以衡量事务的不确定性,这个事物不确定性越大,信息熵越大。</p>
<p>假如事件A的分类划分为(A1,A2,….,An)吗,每部分发生的概率是(P1,P2,…,Pn)</p>
<script type="math/tex; mode=display">
Ent(P1,P2,...Pn)=-P1\log_2P1-P2\log_2P2-\cdots-Pn\log_2Pn</script><p>那么对于分类来说,数据集类别越多,越不纯,越混乱,则熵越大。反之,熵越小。</p>
<p>2.信息增益</p>
<p>信息增益:在一个条件下,信息不确定性减小的程度。为总的熵减去某个分类标准对应的熵。在决策树分类问题中,就是决策树在进行属性选择划分前和划分后的信息差值。设D是样本集合,属性a有v个可能的值a1,a2,…av,Dv为D中所在属性上取值为av的样本。则用属性a对样本集D进行划分所得的信息增益为:</p>
<script type="math/tex; mode=display">
Gain(D,a)=Ent(D)-\sum^{V}_{v\to1}\frac{Dv}{D}Ent(Dv)</script><p>信息增益越大,意味着使用属性a来进行划分所获得的纯度提升越大。所以决策树在属性选择时,就会选择信息增益大的。信息增益准则对可取值数目较多的属性有所偏好。</p>
<p>3.增益率</p>
<script type="math/tex; mode=display">
Grainratio(D,a)=\frac{Grain(D,a)}{IV(a)}</script><script type="math/tex; mode=display">
IV(a)=-\sum^{V}_{v=1}\frac{Dv}{D}\log_2{\frac{Dv}{D}}</script><p>增益率准则对可取值数目较少的属性有所偏好。</p>
<p>4.基尼指数</p>
<p>数据集D的纯度可用基尼值来度量:</p>
<script type="math/tex; mode=display">
Gini(D)=\sum^{|Y|}_{k=1}\sum^{}_{k1\neq k}=1-\sum^{|Y|}_{k=1}Pk^2</script><p>基尼值GiniD反映了从数据集D中随机出去两个样本,其类别标记不一致的概率。GiniD越小,D的纯度越高。<br>属性a的基尼指数为:</p>
<script type="math/tex; mode=display">
Giniindex(D,a)=\sum^{V}_{v=1}\frac{|Dv|}{|D|}Gini(Dv)</script><p>面我们提到,在构建决策树时,采用的是递归方式。在决策树的基本算法中,递归结束的条件是:程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有相同的分类。如果数据集已经处理了所有属性,但是类别标签不是唯一的(即最后一个属性也无法帮助决定样本归属于哪个类),此时我们需要决定如何定义该叶子结点,在这种情况下,我们通常会采用多数表决的方法决定该叶子结点的分类。</p>
<p>ID3算法(鼻祖算法)<br>ID3算法是一种贪心算法,用来构造决策树。以信息熵和信息增益为衡量标准。在划分数据集时,每次划分选取信息增益最高的属性进行划分,重复这个过程,直到生成一个能完美分类训练样例的决策树。</p>
<p>步骤:</p>
<p>输入:样本集合S,属性集合A</p>
<p>输出:ID3决策树</p>
<p>遇到递归终止的条件,返回类别;否则执行(2)</p>
<p> 计算出信息增益最大的属性a,把a作为作为根节点。生成属性集合A1=A-a,执行(3)</p>
<p>对属性a的的每个可能的取值,执行:</p>
<ol>
<li><p>将所有属性a的值是v的样本作为S的一个子集Sv;</p>
</li>
<li><p>以样本集合Sv和属性集合A1为输入,递归执行ID3算法。<br>优点:实现比较简单,产生的规则如果用图表示出来的话,清晰易懂,分类效果好。</p>
</li>
</ol>
<p>缺点:只能处理<strong>标称型数据</strong>,容易形成过拟合,在选择最佳划分属性时容易选择那些属性值多的一些属性。</p>
<p>C4.5<br>C4.5算法继承了ID3算法的优点,并在以下几个方面对ID3算法进行了改进:</p>
<p>用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;</p>
<p>在树构造过程中进行了剪枝,避免了过拟合;</p>
<p>能够完成对连续属性的离散化处理;</p>
<p>能够对不完整数据进行处理。<br>优点:产生的分类规则易于理解,准确率较高。</p>
<p>缺点:在树的构造过程中,需要对数据集进行多次的顺序扫描和排序,耗时。</p>
<p>增益率准则对可取值数目较少的属性有所偏好。因此,C4.5算法并不是直接选择增益率最大的候选划分属性,而是使用了一个启发式:先从候选划分属性中找出信息增益高于平均水平的,再从中选择增益率最高的。</p>
<p>CART</p>
<p>CART决策树使用“基尼指数”来选择划分属性。</p>
<p>基尼指数最小的为最优划分属性。</p>
<p>剪枝是对付过拟合的主要手段。分为预剪枝和后剪枝。 主要当前结点的划分能不能使决策树的性能提升来判断要不要剪枝。</p>
<p>过拟合现象:模型从训练数据到新数据的泛化能力并不好</p>
<p>剪枝:</p>
<p>剪枝并非真的剪,而是合并(使用少数服从多数的方式)。原数据集在训练集上构造的决策树可能很深(与样本的属性相关),但是在使用校验集对决策树进行剪枝,使得决策树变得简单,因此能够校验集可以解决决策树过学习的问题,从而在对测试集进行分类时表现良好。</p>
<p><a href="https://imgchr.com/i/3U6jv4" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/26/3U6jv4.md.png" alt="3U6jv4.md.png" class="lazyload"></a></p>
<p>有些属性不适合做分类,比如根据人的生日来判断人的性别是不合理的,因为根据生日构造决策树时,ID3算法倾向于属性划分后的子集的熵为0,此时就会将每个样本作为一条规则,常常会将属性分的很零碎。这种会很容易导致过学习。</p>
<p>增益率解决了上述问题,根据增益率的公式可知,属性被划分的越细,增益率的值越大。相当于是属性的一个惩罚量,防止属性被划分的过多。</p>
<p>连续型属性:</p>
<p>例如温度,需要取一个阈值(threshold),将连续性属性变为离散型属性。</p>
<h2 id="信号与噪音"><a href="#信号与噪音" class="headerlink" title="信号与噪音"></a><strong>信号与噪音</strong></h2><p>您可能听说过Nate Silver著名的《信号与噪音》一书。在预测建模中,您可以将“信号”视为希望从数据中学习到的真正底层模式。另一方面,“噪音”指的是数据集中无关的信息或随机性。例如,假设您正在建模儿童身高与年龄的关系。如果您对大部分人口进行抽样,您会发现一个非常明确的关系:</p>
<p><a href="https://imgchr.com/i/3UVgMt" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/26/3UVgMt.md.jpg" alt="3UVgMt.md.jpg" class="lazyload"></a></p>
<p><strong>这就是是信号</strong>。然而,如果你只能对当地的一所学校进行抽样调查,这种关系可能会更加复杂。 它会受到异常值(比如,爸爸是NBA球员的孩子)和随机性(例如在不同年龄段进入青春期的孩子)的影响。</p>
<p><strong>“噪音干扰了信号”</strong></p>
<p>这成为机器学习的用武之地,一个运行良好的机器学习算法能将信号从噪声中分离出来。</p>
<p>如果算法过于复杂或灵活(例如,它有太多的输入特性或它没有适当的正则化),它最终可能“记住噪音”而不是找到信号。</p>
<p>这个过拟合模型将基于这些噪声进行预测。它将在训练数据上表现得异常出色……但在新的、未见过的数据上表现得非常糟糕。</p>
<h2 id="拟合优度"><a href="#拟合优度" class="headerlink" title="拟合优度"></a><strong>拟合优度</strong></h2><p>在统计学中,拟合优度是指模型的预测值与观测值(真实)的匹配程度。一个学习了噪声而不是信号的模型被认为是“过拟合”的,因为它适合训练数据集,但与新数据集的拟合度较差。</p>
<p><a href="https://imgchr.com/i/3UZpW9" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/26/3UZpW9.jpg" alt="3UZpW9.jpg" class="lazyload"></a></p>
<h2 id="过拟合和欠拟合"><a href="#过拟合和欠拟合" class="headerlink" title="过拟合和欠拟合"></a><strong>过拟合和欠拟合</strong></h2><p>通过观察相反的问题,我们可以更好地理解欠拟合。 当一个模型过于简单时,因为它的特性太少,或者过于正则化,就会出现欠拟合现象,这使得它在学习数据集时不够灵活。简单的模型在预测结果上往往有较小的方差和较大的偏差(见:偏差-方差权衡)。另一方面,复杂的模型往往在预测中有更大的方差。</p>
<p><strong>偏差和方差都是机器学习中预测误差的两种形式。</strong></p>
<p>通常,我们可以减少由偏差引起的误差,但同时可能会增加由方差带来的误差,反之亦然。太简单(高偏差)与过于复杂(高方差)之间的权衡是统计和机器学习中的关键概念,也是影响所有监督学习算法的关键概念。</p>
<h2 id="如何检查过拟合"><a href="#如何检查过拟合" class="headerlink" title="如何检查过拟合"></a><strong>如何检查过拟合</strong></h2><p>过拟合以及机器学习的一个关键挑战是,在我们实际测试之前,我们无法知道模型对新数据的执行情况。为了解决这个问题,我们可以将初始数据集拆分为单独的<em>训练</em>和<em>测试</em>子集。</p>
<p>这种方法可以估计出我们的模型在新数据上的表现。</p>
<p><strong>如果我们的模型在训练集上比在测试集中表现得好得多,那么我们很可能会过拟合。</strong></p>
<p>例如,如果我们的模型在训练集上有99%的准确率,但在测试集上只有55%的准确率,那将是一个很危险的信号。</p>
<p><strong>另一个建议是从一个非常简单的模型开始,以此作为基准。</strong></p>
<p>然后,当您尝试更复杂的算法时,您将有一个参考基准来查看额外的复杂性是否值得。这是奥卡姆剃刀试验。如果两个模型具有类似的性能,那么通常应该选择比较简单的一个。</p>
<h2 id="如何避免过拟合"><a href="#如何避免过拟合" class="headerlink" title="如何避免过拟合"></a><strong>如何避免过拟合</strong></h2><p>检查过拟合是有用的,但它不能解决问题。幸运的是,有几个方法您可以尝试。以下是一些最常用的过拟合解决方案:</p>
<p><strong>1.交叉验证</strong></p>
<p>交叉验证是预防过拟合的一个强有力措施。</p>
<p>将您的初始训练数据拆分成多个数据集(类似于迷你火车),使用这些拆分子集来调整模型,这是一个聪明的想法。在标准的K-fold交叉验证中,我们将数据划分为K个子集,称为“折叠(folds)”。然后我们迭代地在K-1个折叠上训练算法,同时使用剩余的折叠作为测试集。</p>
<p>交叉验证允许您仅使用原始训练集来调整超参数。这使您可以将测试集保存为真正“未见过”的数据集,以便选择最终模型。</p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/26/3UeqET.jpg" alt="3UeqET.jpg" class="lazyload"></p>
<p><strong>2.使用更多数据</strong></p>
<p>它不会每次都有效,但是使用更多数据进行训练可以帮助算法更好地检测到信号。</p>
<p>在早期的儿童身高与年龄建模的例子中,很明显如何抽样更多的学校将有助于您的模型。当然,情况并非总是如此。如果我们只是添加更多的噪声数据,这种技术将无济于事。这就是为什么您应该始终确保您的数据是干净和相关的。</p>
<p><strong>3.删除无用特征</strong></p>
<p>有些算法有内置的特征选择。 您可以通过删除不相关的输入特性来手动改进它们的通用性。</p>
<p>一种有趣的方法是通过描述每个特性是如何融入模型的。如果很难证明一些特性的存在合理性,说明这些特征是没必要的。</p>
<p><strong>4.及时中止</strong></p>
<p>当您迭代训练学习算法时,您可以度量模型的每次迭代的执行情况。</p>
<p>当迭代至一定次数之前,新的迭代会不断改进模型。然而,在那之后,模型的泛化能力会随着训练数据开始过拟合而减弱。</p>
<p><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/26/3UmoJe.jpg" alt="3UmoJe.jpg" class="lazyload"></p>
<p>现在,这种方法主要用于深度学习,而其他的方法(如正则化)更适合于经典的机器学习。</p>
<p><strong>5.正则化</strong></p>
<p>正则化是指人为地迫使模型变得更简单的一系列技术。这个方法将取决于你使用的模型类型。例如,您可以修剪决策树,在神经网络上使用dropout,或者在回归中向代价函数添加一个惩罚参数。</p>
<p>通常,正则化方法也是一个超参数,这意味着它可以通过交叉验证进行调优。</p>
<p><strong>6.集成学习</strong></p>
<p>集成(Ensembling)是一种机器学习方法,用于将多个不同模型的预测组合在一起。</p>
<p>集成有几种不同的方法,但最常见的两种是:</p>
<p><strong>Bagging</strong>:降低复杂模型过拟合的可能性。</p>
<ul>
<li>它同时训练大量“强大”的模型。</li>
<li>一个“强大”的模型是一个相对不受约束的模型。</li>
<li>然后将所有“强大”的模型结合在一起,以“平滑”他们的预测。</li>
</ul>
<p><strong>Boosting</strong>:改进简单模型的预测能力。</p>
<ul>
<li>它训练大量“弱”的模型。</li>
<li>一个“弱”模型是一个受约束的模型(例如,你可以限制每个决策树的最大深度)。</li>
<li>每个模型都专注于从之前的错误中学习。</li>
<li>然后把所有的弱学习者组合成一个强大的学习者。</li>
</ul>
<p>虽然Bagging和Boosting都是集成方法,但它们从相反的方向解决问题。Bagging使用复杂的基础模型,试图“平滑”他们的预测,而Boosting使用简单的基础模型,并试图“提高”他们的总复杂度。</p>
<p>原文见:</p>
<p><a href="https://zhuanlan.zhihu.com/p/40516287" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/40516287</a></p>
</article>
</div>
<div class="nexmoe-post">
<a href="/2020/02/23/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%88%86%E7%B1%BB%E6%80%A7%E8%83%BD%E5%BA%A6%E9%87%8F/">
<div class="nexmoe-post-cover mdui-ripple" style="padding-bottom: 66.66666666666666%;">
<img data-src="https://s2.ax1x.com/2020/02/24/38jY0U.jpg" data-sizes="auto" alt="myfirstBlog" class="lazyload">
<h1>myfirstBlog</h1>
</div>
</a>
<div class="nexmoe-post-meta">
<a><i class="nexmoefont icon-calendar-fill"></i>2020年02月23日</a>
<a><i class="nexmoefont icon-areachart"></i>1.2k 字</a>
<a><i class="nexmoefont icon-time-circle-fill"></i>大概 4 分钟</a>
</div>
<article>
<h1 id="分类性能度量指标-ROC曲线、AUC值、正确率、召回率"><a href="#分类性能度量指标-ROC曲线、AUC值、正确率、召回率" class="headerlink" title="分类性能度量指标 : ROC曲线、AUC值、正确率、召回率"></a><strong>分类性能度量指标 : ROC曲线、AUC值、正确率、召回率</strong></h1><h3 id="1-混淆矩阵:"><a href="#1-混淆矩阵:" class="headerlink" title="1.混淆矩阵:"></a>1.混淆矩阵:</h3><div class="table-container">
<table>
<thead>
<tr>
<th></th>
<th style="text-align:left">正类</th>
<th>反类</th>
</tr>
</thead>
<tbody>
<tr>
<td>预测为正类</td>
<td style="text-align:left">TP</td>
<td>FP</td>
</tr>
<tr>
<td>预测为反类</td>
<td style="text-align:left">FN</td>
<td>TN</td>
</tr>
</tbody>
</table>
</div>
<p>正确率(precision):</p>
<p> </p>
<script type="math/tex; mode=display">
precision=\frac{TP}{TP+FP}</script><p>理解:所有被预测为正类的结果中正确预测的概率,即查准率</p>
<p>召回率(recall):</p>
<script type="math/tex; mode=display">
Recall=\frac{TP}{TP+FN}</script><p>理解:对所有正类的预测中预测正确的概率,衡量的是分类的查全率</p>
<p>准确率(Accuracy):</p>
<script type="math/tex; mode=display">
Accuracy=\frac{TP+TN}{TP+FP+FN+TN}</script><p>F值(F Measure):</p>
<script type="math/tex; mode=display">
F1=\frac{1}{\frac{1}{2}\frac{1}{P}+\frac{1}{2}\frac{1}{R}}=\frac{2PR}{P+R}</script><p>F1允许在精确率和召回率之间达到某种均衡</p>
<p>也就是P和R的调和平均值:</p>
<script type="math/tex; mode=display">
\frac{1}{F}=\frac{1}{2}(\frac{1}{P}+\frac{1}{R})</script><p>•精确率和召回率是相互影响的,理想情况下肯定是两者都高。</p>
<p>•针对不同目的,如果是做搜索,那就是优先提高召回率,在保证召回率的情况下,提升准确率;如果做反垃圾,则是优先提高准确率,保准确率的条件下,提升召回率。</p>
<p>•在两者都要求高的情况下,如何综合衡量准确率和召回率呢?一般使用F值。F1综合了P和R的结果,可用于综合评价实验结果的质量。</p>
<h3 id="2-ROC曲线"><a href="#2-ROC曲线" class="headerlink" title="2.ROC曲线"></a>2.ROC曲线</h3><p><a href="https://imgchr.com/i/38s6PA" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/38s6PA.png" alt="38s6PA.png" class="lazyload"></a></p>
<p>如图为ROC曲线的一个例子。</p>
<p>横坐标为FPR(负类预测为正的样本占所有负类样本的比例)</p>
<p>纵坐标为TPR(正类预测为正的样本占所有正类样本的比例)</p>
<p>在一个二分类模型中,假设采用逻辑回归分类器,其给出针对每个实例为正类的概率,那么通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FPR,TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被划分为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FPR会同时增大。阈值最大时,对应坐标点为(0,0),阈值最小时,对应坐标点(1,1)。</p>
<p>如下面这幅图,(a)图中实线为ROC曲线,线上每个点对应一个阈值。</p>
<p><a href="https://imgchr.com/i/386CTg" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/386CTg.md.png" alt="386CTg.md.png" class="lazyload"></a></p>
<p>(a) 理想情况下,TPR应该接近1,FPR应该接近0。ROC曲线上的每一个点对应于一个threshold,对于一个分类器,每个threshold下会有一个TPR和FPR。比如Threshold最大时,TP=FP=0,对应于原点;Threshold最小时,TN=FN=1,对应于右上角的点(1,1)。<br>(b) P和N得分不作为特征间距离d的一个函数,随着阈值theta增加,TP和FP都增加。</p>
<p>横轴FPR:FPR越大,预测正类中的负类越多</p>
<p>纵轴TPR:TPR越大,预测正类中正类越多</p>
<p>理想目标:TPR=1,FPR=0,所以ROC曲线越靠拢(0,1)点越好,<strong>ROC曲线下的面积</strong>越大越好。</p>
<h3 id="3-AUC"><a href="#3-AUC" class="headerlink" title="3.AUC"></a>3.AUC</h3><p>AUC(Area Under Curve)被定义为ROC曲线下的面积,显然这个面积的数值不会大于1 。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围一般在0.5和1之间。使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。</p>
<p><strong>AUC值意味着什么</strong></p>
<p>首先AUC值是一个概率值,当你随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值。当然,AUC值越大,当前的分类算法越有可能将正样本排在负样本前面,即能够更好的分类。</p>
<p>从AUC判断分类器(预测模型)优劣的标准:</p>
<p>AUC = 1,是完美分类器,采用这个预测模型时,存在至少一个阈值能得出完美预测。绝大多数预测的场合,不存在完美分类器。<br>0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。<br>AUC = 0.5,跟随机猜测一样(例:丢铜板),模型没有预测价值。<br>AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测。<br>三种AUC值示例:</p>
<p><a href="https://imgchr.com/i/382V1A" target="_blank" rel="noopener"><img data-sizes="auto" data-src="https://s2.ax1x.com/2020/02/24/382V1A.md.png" alt="382V1A.md.png" class="lazyload"></a></p>
<p><strong>AUC值越大的分类器,正确率越高</strong></p>
</article>
</div>
<div class="nexmoe-post">
<a href="/2020/02/23/hello-world/">
<div class="nexmoe-post-cover mdui-ripple" style="padding-bottom: 66.66666666666666%;">
<img data-src="https://s2.ax1x.com/2020/02/24/38jY0U.jpg" data-sizes="auto" alt="Hello World" class="lazyload">
<h1>Hello World</h1>
</div>
</a>
<div class="nexmoe-post-meta">
<a><i class="nexmoefont icon-calendar-fill"></i>2020年02月23日</a>
<a><i class="nexmoefont icon-areachart"></i>73 字</a>
<a><i class="nexmoefont icon-time-circle-fill"></i>大概 1 分钟</a>
</div>
<article>
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html" target="_blank" rel="noopener">Deployment</a></p>
</article>
</div>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/combine/npm/lazysizes@5.1.0/lazysizes.min.js,gh/highlightjs/cdn-release@9.15.8/build/highlight.min.js,npm/mdui@0.4.3/dist/js/mdui.min.js,gh/nexmoe/nexmoe.github.io@latest/js/app.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<!--<script src="/js/app.js?v=1583906464373"></script>-->
<script src="https://cdn.jsdelivr.net/gh/xtaodada/xtaodada.github.io@0.0.2/copy.js"></script>
<script>
!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ["$","$"], ["\\(","\\)"] ],
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
processEscapes: true
}
});
MathJax.Hub.Queue(function() {
var all = MathJax.Hub.getAllJax();
for (var i = 0; i < all.length; ++i)
all[i].SourceElement().parentNode.className += ' has-jax';
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script><!-- hexo-inject:begin --><!-- hexo-inject:end -->
</body>
</html>