-
Notifications
You must be signed in to change notification settings - Fork 85
/
search.xml
643 lines (310 loc) · 388 KB
/
search.xml
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
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>EM算法及其推广</title>
<link href="/2019/03/26/EM%E7%AE%97%E6%B3%95%E5%8F%8A%E5%85%B6%E6%8E%A8%E5%B9%BF/"/>
<url>/2019/03/26/EM%E7%AE%97%E6%B3%95%E5%8F%8A%E5%85%B6%E6%8E%A8%E5%B9%BF/</url>
<content type="html"><![CDATA[<h4 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h4><p>EM算法是一种迭代算法,它的每次迭代由两步组成:E步,求期望;M步,求极大,所以称为期望极大算法(Expectation Maximization),简称EM算法。</p><p>在概率模型有时既含有观测变量,又含有隐变量或者潜在变量,如果概率模型的变量都是观测变量,那么给定数据,可以直接使用极大似然估计或者贝叶斯估计模型参数,但是当模型含有隐变量,就不能简单使用上述方法。<strong>EM算法就是含有隐变量的概率模型参数的极大似然估计法,或极大后验概率估计法</strong>。</p><h4 id="EM算法"><a href="#EM算法" class="headerlink" title="EM算法"></a>EM算法</h4><h5 id="例子:🌰"><a href="#例子:🌰" class="headerlink" title="例子:🌰"></a>例子:🌰</h5><p>(三个硬币模型)假设有3个硬币,ABC,硬币正面出现的概率分别是$w,p,q$,先抛A,根据其结果选择B或者C抛,正面抛B,反面抛C,然后抛选择出的硬币,正面记1,反面记0,独立重复$n$次,只能观测到抛掷硬币的最终结果,问如何估计三硬币正面出现的概率,即三硬币模型参数。</p><p>将观测数据表示为$Y=(Y_1,Y_2,…,Y_n)^T$,未观测数据表示为$Z=(Z_1,Z_2,…,Z_n)^T$,观测数据的似然函数为$$P(Y|\theta)=\sum\limits_{Z}P(Z|\theta)P(Y|Z,\theta)$$<br>即<br>$$P(Y|\theta)=\prod\limits_{j=1}^{n}[wp^{y_j}(1-p)^{1-y_j}+(1-w)q^{y_j}(1-q)^{1-y_j}]$$</p><p>求模型参数$\theta=(w,p,q)$的极大似然估计,即<br>$$\hat{\theta}=arg\max\limits_{\theta}logP(Y|\theta)$$<br><strong>这个问题没有解析解,只能通过迭代求解,EM就是可以用于求解这个问题的一种迭代算法</strong><br>例题的迭代过程见《统计学习方法》P156<br>NOTE:EM算法与初值的选择有关,选择不同的初值可能取得不同的参数估计值。</p><h5 id="具体算法"><a href="#具体算法" class="headerlink" title="具体算法"></a>具体算法</h5><p>「概念」完全数据vs不完全数据:$Y,Z$连在一起成为完全数据,$Y$成为不完全数据。</p><p><strong>具体EM算法如下:</strong><br>输入:观测变量$Y$,隐变量数据$Z$,联合分布$P(Y,Z|\theta)$,条件概率分布P(Z|Y,\theta)<br>输出:模型参数$\theta$</p><ol><li>选择初始值$\theta^{(0)}$,开始迭代</li><li>E步:记$\theta^{(i)}$为第$i$次迭代参数$\theta$的估计值,在第$i+1$次迭代的E步,计算<br>$$\begin {align}<br>Q(\theta,\theta^{(i)})&= E_Z[logP(Y,Z|\theta)|Y,\theta^{(i)}]\\<br>&=\sum\limits_{Z}logP(Y,Z|\theta)P(Z|Y,\theta^{(i)})<br>\end{align}$$<br>这里,$P(Z|Y,\theta^{(i)})$是在给定观测数据$Y$和当前的参数估计$\theta^{(i)}$下隐变量数据Z的条件概率分布。</li><li>M步:求使得$Q(\theta,\theta^{(i)})$极大化的$\theta$,确定第$i+1$次迭代的参数估计值$\theta^{(i+1)}$<br>$$\theta^{(i+1)}=arg\max_{\theta}Q(\theta,\theta^{(i)})$$</li><li>重复第2.3步,直至收敛。<br>其中$Q(\theta,\theta^{(i)})$是算法法核心,称为Q函数<br>Q函数是指完全数据的对数似然函数$logP(Y,Z|\theta)$关于在给定观测数据$Y$和当前参数$\theta^{(i)}$下对未观测数据$Z$的条件概率分布$P(Z|Y,\theta^{(i)})$的期望称为Q函数。</li></ol><p><strong>NOTE:</strong><br>EM算法说明</p><ul><li>参数的初始值可以任意选择,但注意EM算法对初始值敏感</li><li>E步:$Q(\theta,\theta^{(i)})$中,第一个变元表示要极大化的参数,第二个变元是表示参数的当前估计值,每次迭代实际上在求Q函数的极大值</li><li>M步:求$Q(\theta,\theta^{(i)})$极大化,完成$\theta^{(i)} \rightarrow \theta^{(i+1)}$,每次迭代使似然函数增大或达到局部极值,但EM算法不能保证找到全军最优值</li><li>迭代停止:满足$||\theta^{(i+1)}-\theta^{(i)} ||<\xi$</li><li>EM算法应用于生成模型的非监督学习。</li></ul><p><strong>EM算法的推导以及收敛性验证详见《统计学习方法P158》</strong><br>收敛性结果:<br>EM算法的收敛性包含关于对数似然函数序列$L(\theta^{(i)})$的收敛性和关于参数估计序列$\theta^{(i)}$的收敛性,此外,定理只能保证参数估计序列收敛到对数似然函数序列的稳定点,不能保证收敛到极大值点。应用中,初值选取非常重要,通常选择几个不同的初始值进行迭代,然后对比选择最优的结果。</p><h4 id="EM在高斯混合模型中的应用"><a href="#EM在高斯混合模型中的应用" class="headerlink" title="EM在高斯混合模型中的应用"></a>EM在高斯混合模型中的应用</h4><p>EM算法的重要应用是高斯混合模型的参数估计,在许多情况下,EM是学习高斯混合模型的有效方法。</p><h5 id="高斯混合模型"><a href="#高斯混合模型" class="headerlink" title="高斯混合模型"></a>高斯混合模型</h5><p>「高斯混合模型」具有如下概率分布模型:<br>$$P(y|\theta)=\sum\limits_{k=1}^{K}\alpha_k\phi(y|\theta_{k})$$<br>其中,$\alpha_k$是系数,$\alpha_k\geq0,\sum\limits_{k=1}^{K}\alpha_k=1;\phi(y|\theta_{k})$是高斯分布密度,$\theta_{k}=(\mu_k,\sigma_k^2)$<br>$$\phi(y|\theta_{k})=\frac{1}{\sqrt{2\pi}\sigma_k}exp\left(-\frac{(y-\mu_k)^2}{2\sigma_k^2}\right)$$<br>称第k个分模型</p><h5 id="高斯混合模型的EM算法"><a href="#高斯混合模型的EM算法" class="headerlink" title="高斯混合模型的EM算法"></a>高斯混合模型的EM算法</h5><p>假设观测数据$y_1,y_2,…,y_N$由高斯混合模型生成,<br>$$P(y|\theta)=\sum\limits_{k=1}^{K}\alpha_k\phi(y|\theta_{k})$$<br>其中,$\theta=(\alpha_1,\alpha_2,…,\alpha_K;\theta_1,\theta_2,…,\theta_K)$,用EM算法估计高斯混合模型的参数$\theta$<br>设想观测数据$y_j,j=1,2,…,N$是这样产生的:首先是依概率$a_k$选择第$k$个高斯分布分模型$\phi(y|\theta_{k})$;然后依第$k$个分模型的概率分布$\phi(y|\theta_{k})$生成观测数据$y_j$,观测数据$y_j$是已知的,反映观测数据$y_j$来自第$k$个分模型的数据是未知的,$k=1,2,…,K$,用隐变量$y_{jk}$,它是一个0-1随机变量。</p><p>高斯混合模型参数估计的EM算法(具体计算过程见《统计学习方法》P163):<br>输入:观测数据$y1,y2,…,y_N$,高斯混合模型<br>输出:高斯混合模型参数</p><ol><li>取参数的初始值开始迭代</li><li>E步:依据当前模型参数,计算分模型$k$对观测数据$y_j$的响应度<br>$$\hat{y}_{jk}=\frac{\alpha_k\phi(y|\theta_{k})}{\sum\limits_{k=1}^{K}\alpha_k\phi(y|\theta_{k})}$$</li><li>M步:计算新一轮迭代的模型参数<br>$$\hat{\mu}_k=\frac{\sum\limits_{j=1}^{N}\hat{y}_{jk}y_j}{\sum\limits_{j=1}^{N}\hat{y}_{jk}},k=1,2,…,K$$<br>$$\hat{\sigma}_k^2=\frac{\sum\limits_{j=1}^{N}\hat{y}_{jk}(y_j-\mu_k)^2}{\sum\limits_{j=1}^{N}\hat{y}_{jk}},k=1,2,…,K$$<br>$$\hat{\alpha}_k=\frac{\sum\limits_{j=1}^{N}\hat{y}_{jk}}{N},k=1,2,…,K$$</li><li>重复2.3步直至收敛</li></ol><h4 id="广义期望极大算法(GEM)"><a href="#广义期望极大算法(GEM)" class="headerlink" title="广义期望极大算法(GEM)"></a>广义期望极大算法(GEM)</h4><p>EM算法还可以解释为F函数的极大-极大算法,基于这个解释有若干变形与推广,eg广义期望极大算法(Generalized Expectation Maximization)<br>更多内容详见《统计学习方法》P166</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> EM </tag>
<tag> 高斯混合模型 </tag>
<tag> GEM </tag>
</tags>
</entry>
<entry>
<title>提升方法-1:Adaboost</title>
<link href="/2019/03/20/%E6%8F%90%E5%8D%87%E6%96%B9%E6%B3%95-1%EF%BC%9AAdaboost/"/>
<url>/2019/03/20/%E6%8F%90%E5%8D%87%E6%96%B9%E6%B3%95-1%EF%BC%9AAdaboost/</url>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>集成学习是将已有的弱的分类器或者回归模型通过一定的方法组合起来形成强的分类器或者回归模型的一种学习方法,它的思想就是“三个臭皮匠顶个诸葛亮”,综合得到的结论比单独的判断好,以袋套法(bagging)和提升法(boosting)为代表。</p><p><strong>袋套法(bagging) vs 提升法(boosting):</strong><br>Boosting,各分类器之间有依赖关系,必须串行,比如Adaboost、GBDT、Xgboost<br>Bagging,各分类器之间没有依赖关系,可各自并行,比如随机森林(RF)</p><h4 id="Adaboost算法"><a href="#Adaboost算法" class="headerlink" title="Adaboost算法"></a>Adaboost算法</h4><ul><li><strong>问题1:每一轮是如何改变样本的权重?</strong><br>提升哪些在前一轮弱分类器错误分类的样本权重,降低那些被正确分类样本的权重,使得误分类的样本得到更大的关注。于是分类问题被一系列弱分类器“分而治之”。</li><li><strong>问题2. 如何将弱分类器组合成强分类器?</strong><br>加权多数表决法,加大分类误差率小的弱分类器的权重,减少分类误差率大的弱分类器的权重,使得分类误差率小的弱分类器在表决中起更大的作用。</li></ul><p><strong>算法</strong><br>输入:训练集$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace,y_i=\lbrace -1,+1 \rbrace$;弱学习算法<br>输出:最终分类器$G(x)$</p><ol><li>初始化训练样本的权值分布,<br>$$D_1=(w_{1,1},…,w_{1,i},…,w_{l,N}),w_{1,i}=\frac{1}{N}$$</li><li>反复学习基本分类器,对$m=1,2,…,M$<br>(a)使用具有权值分布$D_m$的训练集学习,得到基本分类器<br>$$G_m(x):X \rightarrow \lbrace -1,+1 \rbrace$$<br>(b)计算$G_m(x)$在训练集上的分类误差率<br>$$e_m=P(G_m(x_i)\neq y_i)=\sum\limits_{i=1}^{N}w_{m,i}I(G_m(x_i)\neq y_i)$$<br>(c)计算$G_m(x)$的系数<br>$$\alpha_m=\frac{1}{2}log\frac{1-e_m}{e_m}$$<br>当$e_m\leq\frac{1}{2},\alpha_m\geq0$,并且$\alpha$随着$e_m$的减少而增大,所以分类误差率越小的基本分类器在最终的分类器中作用越大。<br>(d)更新训练集的权值分布<br>$$D_{m+1}=(w_{m+1,1},…,w_{m+1,i},…,w_{m+l,N})$$<br>$$w_{m+1,i}=\frac{w_{m,i}}{Z_m}exp(-\alpha_my_iG_m(x_i)),i=1,2,…,N$$<br>$$Z_m=\sum\limits_{i=1}^{N}w_{m,i}exp(-\alpha_my_iG_m(x_i))$$<br>$Z_m$是规范化因子,使得$D_{m+1}$成为一个概率分布。</li><li>构建最终的分类器<br>$$G(x)=sign(\sum\limits_{m=1}^{M}\alpha_mG_m(x))$$</li></ol><h4 id="adaboost算法的训练误差分析"><a href="#adaboost算法的训练误差分析" class="headerlink" title="adaboost算法的训练误差分析"></a>adaboost算法的训练误差分析</h4><p>adaboost在学习过程中不断减少训练误差,即训练数据上的分类误差。<br>有如下定理:<br>adaboost算法的最终分类器的训练误差界为:<br>$$\frac{1}{N}\sum\limits_{i=1}^{N}I(G(x_i)\neq y_i) \leq \frac{1}{N}\sum_{i}exp(-y_if(x_i))=\prod_mZ_m$$ (更加详细的推导见统计学习方法p142)</p><h4 id="Adaboost算法解释"><a href="#Adaboost算法解释" class="headerlink" title="Adaboost算法解释"></a>Adaboost算法解释</h4><p>adaboost另外一种解释,即认为<strong>adaboost算法是加法模型,损失函数为指数函数,学习算法为前向分步算法</strong></p><ol><li>加法模型<br>$$f(x)=\sum\limits_{m=1}^{M}\beta_mb(x;\gamma_m)$$<br>$b(x;\gamma_m)$是基函数,$\gamma_m$基函数的参数,$\beta_m$是基函数的系数。</li><li>损失函数<br>$$\min_{\beta_m,\gamma_m} \quad\sum\limits_{i=1}^{N}L(y_i,\sum\limits_{m=1}^{M}\beta_mb(x_i;\gamma_m))$$<br>由于上述是一个复杂的优化问题,使用前向分布算法来求解这类问题。<br><strong>前向分布算法思想</strong>:由于学习的模型是加法模型,如果能够从前往后,每一步只学习一个基函数及其系数,逐步逼近优化函数目标式,那么就可以简化优化的复杂度,具体地,每步优化如下损失函数:<br>$$\min_{\beta,\gamma} \quad \sum\limits_{i=1}^{N}L(y_i,\beta b(x_i;\gamma))$$</li></ol><p><strong>前向分布算法:</strong><br>输入:训练集$T$,损失函数为$L(y,f(x))$,基函数集$\lbrace b(x;\gamma)\rbrace$<br>输出:加法模型$f(x)$</p><ul><li>初始化$f_0(x)=0$</li><li>对$m=1,2,…,M$<br>(a)极小化损失函数<br>$$(\beta_m,\gamma_m)=arg\min_{\beta,\gamma}\quad\sum\limits_{i=1}^{N}L(y_i,f_{m-1}(x_i)+\beta b(x_i;\gamma))$$<br>(b)更新<br>$$f_m(x)=f_{m-1}(x)+\beta_mb(x;\gamma_m)$$</li><li>得到加法模型<br>$$f(x)=f_M(x)=\sum\limits_{m=1}^{M}\beta_mb(x;\gamma_m)$$<br>这样,前向分步算法将同时求解从$m=1$到$M$所有参数$\beta_m,\gamma_m$的优化问题简化为逐次求解各个$\beta_m,\gamma_m$的优化问题。</li></ul><h5 id="前向分步算法与Adaboost"><a href="#前向分步算法与Adaboost" class="headerlink" title="前向分步算法与Adaboost"></a>前向分步算法与Adaboost</h5><p>最终分类器模型为:<br>$$f(x)=\sum\limits_{m=1}^{M}\alpha_mG_m(x)$$<br>损失函数为:【指数损失函数】<br>$$L(y,f(x))=exp(-yf(x))$$<br>在第$m$轮迭代得到$\alpha_m,G_m(x),f_m(x)$<br>$$f_m(x)=f_{m-1}(x)+\alpha_mG_m(x)$$<br>目标是使前向分步算法得到的$\alpha_m,G_m(x)$使$f_m(x)$在训练集$T$上的指数损失最小,即<br>$$(\alpha_m,G_m(x))=arg \min_{\alpha,G}\sum\limits_{i=1}^{N}exp[-y_i(f_{m-1}(x_i)+\alpha G(x_i))]$$<br>上式可以表示为:<br>$$(\alpha_m,G_m(x))=arg \min_{\alpha,G}\sum\limits_{i=1}^{N}\hat{w}_{m,i}exp[-y_i\alpha G(x_i)]$$<br>其中,$\hat{w}_{m,i}=exp[-y_if_{m-1}(x_i)]$,其中$\hat{w}_{m,i}$既不依赖$\alpha$也不依赖$G$,所以与最小化无关,但$\hat{w}_{m,i}$依赖于$f_{m-1}(x)$,随每次迭代发生变化<br>使得上式达到最小的$\alpha_m^{\ast}$和$G_m^{\ast}(x)$,就是adaboost算法所得到的$\alpha_m,G_m(x)$</p><h4 id="提升树🌲"><a href="#提升树🌲" class="headerlink" title="提升树🌲"></a>提升树🌲</h4><p>提升方法:采用加法模型(基函数的线性组合)与前向分步算法。<br>提升树:以决策树为基函数的提升方法。对分类问题决策树是二叉分类树,对回归问题决策树是二叉回归树,即是CART作为基函数。<br>提升树的模型可以表示为决策树的加法模型:$$f_M(x)=\sum\limits_{m=1}^{M}T(x;\theta_m)$$<br>其中$T(x;\theta_m)$为决策树,$\theta_m$为决策树参数,$M$为树的个数<br><strong>提升树算法</strong><br>初始提升树为$f_0(x)=0$<br>第$m$步的模型是:$f_m(x)=f_{m-1}(x)+T(x;\theta_m)$<br>当$f_{m-1}(x)$为当前模型,通过经验风险极小化确定下一颗决策树的参数$\theta_m$<br>$$\hat{\theta}_{m}=arg \min_{\theta_m}\sum\limits_{i=1}^{N}L(y_i,f_{m-1}(x_i)+T(x;\theta_m))$$<br><strong>针对不同问题的提升树学习方法主要区别在于损失函数的不同</strong>🤓<br>回归问题用平方误差损失函数;分类问题用指数损失函数。</p><p>下面以回归问题的提升树为例:<br>采用平方误差损失函数:<br>$$L(y,f_{m-1}(x)+T(x;\theta_m))=[y-f_{m-1}(x)-T(x;\theta_m)]^2$$其中$r=y-f_{m-1}(x)$是当前数据模型拟合数据的残差,所以对于回归问题的提升树算法来说,只需要简单地拟合当前模型的残差。</p><p><strong>具体算法如下:</strong><br>输入:训练集$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace,y_i=\lbrace -1,+1 \rbrace$;<br>输出:提升树$f_M(x)$</p><ol><li>初始化$f_0(x)=0$</li><li>对$m=1,2,…,M$<br>计算残差:$r_{m,i}=y_i-f_{m-1}(x_i),i=1,2,…,N$<br>拟合残差:$r_{m,i}$学习一个回归树,得到$T(x;\theta_m)$<br>更新:$f_m(x)=f_{m-1}(x)+T(x;\theta_m)$</li><li>得到回归问题的提升树<br>$$f_M(x)=\sum\limits_{m=1}^{M}T(x;\theta_m)$$</li></ol><h5 id="梯度提升"><a href="#梯度提升" class="headerlink" title="梯度提升"></a>梯度提升</h5><p>提升树利用加法模型和前向分布算法实现学习的优化过程,当损失函数为平方损失和指数损失函数时,优化比较简单,但对于一般损失函数而言,每一步优化并不容易。<br>对于这个问题,利用<strong>梯度提升算法</strong>【利用最速下降法的近似,其关键是利用损失函数的负方向在当前模型的值】,表示如下:<br>$$\left(\frac{dL(y,f(x_i))}{df(x_i)}\right)_{f(x)=f_{m-1}(x)}$$<br>这个值作为回归问题提升树算法中的残差的近似值,拟合一个回归树。</p><p><strong>梯度提升算法:</strong><br>输入:训练集<br>输出:回归树$\hat{f}(x)$</p><ol><li>初始化$f_0(x)=arg \min\limits_{c}\sum\limits_{i=1}^{N}L(y_i,c)$</li><li>对$m=1,2,…,M$<br>(a)计算残差:$r_{m,i}=\left(\frac{dL(y,f(x_i))}{df(x_i)}\right)_{f(x)=f_{m-1}(x)}$<br>(b)对$r_{m,i}$拟合一个回归树,得到第$m$课树的叶子结点区域$R_{mj},j=1,2,…,J$<br>(c)对$j=1,2,…,J$计算$c_{m,j}=arg \min\limits_{c}\sum\limits_{x_i\in R_{mj}}L(y_i,f_{m-1}(x_i)+c)$<br>(d)更新$f_m(x)=f_{m-1}(x)+\sum\limits_{j=1}^{J}c_{mj}I(x\in R_{mj})$</li><li>得到回归树<br>$$\hat{f}(x)=f_M(x)=\sum\limits_{m=1}^{M}\sum\limits_{j=1}^{J}c_{mj}I(x\in R_{mj})$$<br>解释如下:<br>1:估计是损失函数极小化的常数值,它是只有一个根结点的树。<br>2(a):计算当前模型在损失函数的负梯度的值,将它作为残差的估计,对平方损失函数它就是残差,对一般损失函数,它是残差的近似<br>2(b):估计回归树叶子结点区域,以拟合残差的近似值<br>2(c):利用线性搜索估计叶子结点区域的值,使得损失函数极小化<br>2(d):更新回归树<br>3:输出最终的模型</li></ol><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>除了上述分析到的adaboost、提升树、梯度提升树外,下一博文将介绍工业上常用的两个模型GBDT和xgboost。</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> boosting </tag>
<tag> adaboost </tag>
<tag> 提升树 </tag>
<tag> 梯度提升 </tag>
</tags>
</entry>
<entry>
<title>支持向量机(SVM)-2:非线性支持向量机</title>
<link href="/2019/03/19/%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA-SVM-2-%E9%9D%9E%E7%BA%BF%E6%80%A7%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA/"/>
<url>/2019/03/19/%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA-SVM-2-%E9%9D%9E%E7%BA%BF%E6%80%A7%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA/</url>
<content type="html"><![CDATA[<h4 id="非线性svm与核函数"><a href="#非线性svm与核函数" class="headerlink" title="非线性svm与核函数"></a>非线性svm与核函数</h4><p>当分类问题是非线性,可以使用非线性svm,主要的特点是利用核函数。</p><h5 id="核技巧"><a href="#核技巧" class="headerlink" title="核技巧"></a>核技巧</h5><p>非线性分类问题😵<br>对于训练数据集,能用一个超曲面将正负例正确分开,则称该问题为<strong>非线性可分问题</strong><br>非线性问题往往不好求解,所以进行非线性变换,将非线性问题变换为线性问题,通过解变换后的线性问题求解原来的非线性问题。💃💃</p><p>线性分类法求解非线性分类问题:使用变换,将原空间数据映射到新空间;然后在新空间利用线性分类学习方法从训练集中学习分类模型。<strong>核技巧就属于这样的方法</strong></p><p>核技巧应用到svm的基本思想:通过非线性变换将输入空间$X$(欧氏空间&离散集合)对应于特征空间$H$(希尔伯特空间),使得输入空间的超曲面模型对应特征空间的超平面模型,最后分类问题的学习任务是通过在<strong>特征空间</strong>在求解线性支持向量机就可以完成。<br>如果存在一个从$X$到$H$的映射,映射关系表示如下:$$\phi(x):X\rightarrow H$$<br>使得对所有的$x,z\in X$,函数$K(x,z)$满足条件$$K(x,z)=\phi(x)\cdot\phi(z)$$<br>则称$K(x,z)$为核函数,$\phi(x)$为映射函数,$\phi(x)\cdot\phi(z)$为$\phi(x)和\phi(z)$内积</p><p><strong>核技巧思想</strong><br>在学习与预测中只定义核函数$K(x,z)$,而不显式地定义映射函数$\phi(x)$,通常计算核函数比计算内积更容易。对于给定的核函数$K(x,z)$,$\phi(x)$的取法不唯一,可以取不同的特征空间,即使是同一特征空间也可以取不同的映射。</p><p>在svm中的应用:线性svm的对偶问题中,无论是目标函数还是决策函数都涉及到实例之间的内积,在对偶问题的目标函数$x_i\cdot x_j$,可以使用核函数$K(x_i,x_j)=\phi(x_i)\cdot\phi(x_j)$来代替。<br>所以对偶问题的目标函数表示为:<br>$$W(\alpha)=\frac{1}{2}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}a_ia_jy_iy_jK(x_i,x_j)-\sum\limits_{i=1}^{N}\alpha_i$$<br>分类决策函数表示为:<br>$$f(x)=sign(\sum\limits_{i=1}^{N_s}\alpha_i^{\ast}y_iK(x_i,x)+b^{\ast})$$<br>即,在核函数给定的条件下,可以利用解线性分类问题的方法求解非线性分类问题的svm。学习过程是隐式地在特征空间进行的,不需要定义特征空间和映射函数,这样的技巧称为核技巧。</p><h5 id="正定核"><a href="#正定核" class="headerlink" title="正定核"></a>正定核</h5><p><strong>核函数$K(x,z)$需为正定核函数</strong></p><p>正定核的充要条件:设$K:X\times X\rightarrow R$是对称函数,则$K(x,z)$为正定核函数的充要条件是对任意$x_i\in X,i=1,2,…,m,K(x,m)$对应的Gram矩阵:$$K=[K(x_i,x_j)]_{m\times m}$$<br>是半正定的</p><h5 id="常用的核函数"><a href="#常用的核函数" class="headerlink" title="常用的核函数"></a>常用的核函数</h5><ol><li>线性核函数<br>$$K(x,z)=(x\cdot z)$$<br>适用于线性svm,其实就是在原始的输出空间进行学习</li><li>多项式核函数<br>$$K(x,z)=(x\cdot z+1)^p$$<br>对应的svm是一个$p$次多项式分类器,分类决策函数为:<br>$$f(x)=sign\left(\sum\limits_{i=1}^{N_s}\alpha_i^{\ast}y_i(x_i\cdot x+1)^p+b^{\ast}\right)$$</li><li>高斯核函数<br>$$K(x,z)=exp\left(-\frac{||x-z||^2}{2\sigma}\right)$$<br>对应的svm是高斯径向基函数分类器,分类决策函数表示为:<br>$$f(x)=sign\left(\sum\limits_{i=1}^{N_s}\alpha_i^{\ast}y_iexp(-\frac{||x-z||^2}{2\sigma})+b^{\ast}\right)$$</li><li>字符串核函数<br>核函数不仅可以定义在欧氏距离还可以定义在离散数据的集合上,eg字符串核函数是定义在字符串集合上的核函数,字符串核函数在文本分类、信息检索等方法有应用。</li><li>sigmod核函数<br>采用sigmoid核函数,支持向量机实现的就是一种多层神经网络<br>更多核函数参考博文 <a href="https://blog.csdn.net/wsj998689aa/article/details/47027365" target="_blank" rel="noopener">总结一下遇到的各种核函数</a><h5 id="非线性svm学习算法"><a href="#非线性svm学习算法" class="headerlink" title="非线性svm学习算法"></a>非线性svm学习算法</h5>输入:训练数据集<br>输出:分离超平面和分类决策函数</li><li>选择适当的核函数$K(x,z)$和惩罚参数$C$,构造并求解凸二次规划问题,求解最优$\alpha^{\ast}=(\alpha_1^{\ast},\alpha_2^{\ast},…,\alpha_N^{\ast})^T$</li></ol><p>$$\begin{equation}<br> \mathop{\min}_{\alpha} \quad\frac{1}{2} \sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_{i}\alpha_{j}y_iy_jK(x_i,x_j)-\sum\limits_{i=1}^{N}\alpha_{i} \\<br> \begin{cases}<br> & s.t.\quad \sum\limits_{i=1}^{N}\alpha_{i}y_i=0 \\<br> &\quad 0 \leq \alpha_i \leq C,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><ol start="2"><li>选择$\alpha^{\ast}$的一个正分量$0\leq a_j^{\ast} \leq C$计算$b^{\ast}$<br>$$b^{\ast} = y_j -\sum\limits_{i=1}^{N}\alpha_{i}^{\ast}y_iK(x_i,x_j) $$</li><li>求得分类决策函数<br>$$f(x)=sign\left(\sum\limits_{i=1}^{N}\alpha_i^{\ast}y_iK(x_i,x)+b^{\ast}\right)$$</li></ol><h4 id="序列最小最优化算法"><a href="#序列最小最优化算法" class="headerlink" title="序列最小最优化算法"></a>序列最小最优化算法</h4><p>svm的学习最后形式化求解凸二次规划,这样的规划具有全局最优解,但是当训练样本容量很大时,这些算法变得非常低效,这里解析一个快速实现算法:序列最小最优化算法(SMO)。<br>SMO是一种启发式算法:思路是:如果所有变量的解都满足此KKT条件,那么这个最优化问题的解就找到了。【KKT条件是该最优化问题的充分必要条件】</p><p>SMO包括两个部分:求解两个变量二次规划的解析方法(P125)和选择变量的启发式方法(P128)。【NOTE✋:两个变量的确定:一个是违反KKT条件最严重的那个,另外一个由约束条件自动确定。】</p><p>特点:不断地将原二次规划问题分解为只有两个变量的二次规划子问题,并对子问题进行解析求解,知道所有的变量满足KKT条件,通过启发式的方法得到原谅二次规划的最优解,子问题有解析解且计算快,虽然计算次数更多,但总体还是很高效。</p><h4 id="总结👻"><a href="#总结👻" class="headerlink" title="总结👻"></a>总结👻</h4><p>非线性支持向量机最重要是应用的核函数,将输入空间的数据映射到特征空间,在特征空间里利用线性支持向量机求解。而SMO是svm快速学习的一种算法,具体见《统计学习方法》P125</p>]]></content>
<tags>
<tag> svm </tag>
<tag> 核函数 </tag>
<tag> smo </tag>
</tags>
</entry>
<entry>
<title>支持向量机(SVM)-1:线性支持向量机</title>
<link href="/2019/03/08/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA-SVM/"/>
<url>/2019/03/08/%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA-SVM/</url>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>SVM是一种二分类模型,是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机,SVM还包括核技巧,使它成为非线性分类器,而间隔最大的策略使得形式化为一个求解<strong>凸二次规划,等价于正则化的合页损失函数的最小化问题</strong>。</p><p>SVM学习方法包含构建由简到繁的模型:线性可分支持向量机【训练集线性可分,对应硬间隔最大化,又称硬间隔支持向量机】、线性支持向量机【训练集近似线性可分,对应软间隔支持向量机】、非线性支持向量机【当线性不可分,通过核技巧以及软间隔最大化学习】</p><p><strong>核函数:</strong> 当输入空间为欧式空间或者离散集合、特征空间为希尔伯特空间(完备的内积空间)时,核函数表示将输入从输入空间映射到特征空间得到的特征向量之间的内积。<strong>通过使用核函数可以学习非线性支持向量机,等价于隐式地在高维的特征空间中学习线性支持向量机。</strong><br><img src="/images/pasted-11.png" alt="框架图"></p><h4 id="线性可分SVM与硬间隔最大化"><a href="#线性可分SVM与硬间隔最大化" class="headerlink" title="线性可分SVM与硬间隔最大化"></a>线性可分SVM与硬间隔最大化</h4><h5 id="线性可分支持向量机"><a href="#线性可分支持向量机" class="headerlink" title="线性可分支持向量机"></a>线性可分支持向量机</h5><p>概念:输入空间&特征空间<br>假设输入空间为欧式空间或者离散集合,特征空间为欧式空间或希尔伯特空间。线性/线性可分支持向量值假设这两个空间元素一一对应,而非线性支持向量机利用核函数将输入从输入空间映射到特征空间形成特征向量,因此svm的学习是在特征空间进行的。</p><p><strong>假设特征空间上的训练集:</strong><br>$$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace$$<br>其中$y_i=\lbrace-1,+1\rbrace$</p><p>学习的目标是在特征空间找到一个分离超平面($w\cdot x+b$)能将实例分为不同的类别,一般地当数据集线性可分时,存在无数个分离超平面可以将这个两类数据正确分开,感知机利用误分类最小的策略,求得超平面,不过解有无穷多个,而线性可分支持向量机是利用间隔最大求最优的分离超平面,这个解释唯一。<br>假设学习到的分离超平面为$w^{\ast}\cdot x+b^{\ast}$<br>那么线性可分支持向量机的决策函数为$f(x)=sign(w^{\ast}\cdot x+b^{\ast})$</p><h5 id="函数间隔-amp-几何间隔"><a href="#函数间隔-amp-几何间隔" class="headerlink" title="函数间隔&几何间隔"></a>函数间隔&几何间隔</h5><ol><li><p>函数间隔<br>一般,一个点到分离超平面的远近可以表示为分类预测的确信程度,在超平面$w\cdot x+b$确定的情况下,$|w\cdot x+b|$表示点$x$到超平面的远近,而$w\cdot x+b$与类标记$y$是否一致表示分类是否正确,所以用$y(w\cdot x+b)$来表示分类的正确性以及确信度,这就是函数间隔。<br>定义:<br>超平面关于训练集$T$的函数间隔为超平面关于$T$中所有样本点的函数间隔之最小值,表示为:$$\hat{\gamma}=\min\limits_{i=1,2,…,N}\quad y_i\left(w\cdot x_i+b\right)$$</p></li><li><p>几何间隔<br>但是选择超平面时,光有函数间隔是不够的,因为只要成比例的改变$w$和$b$,超平面没有变,但是函数间隔变成了原来的比例倍,因此需要对法向量$w$加约束,eg规范化$||w||$,使间隔确定,这时就是几何间隔。<br>定义:<br>超平面关于训练集$T$的几何间隔为超平面关于$T$中所有样本点的几何间隔之最小值,表示为<br>$$\gamma=\min\limits_{i=1,2,…,N}\quad y_i\left(\frac{w}{||w||}\cdot x_i+\frac{b}{||w||}\right)$$</p></li><li>函数间隔与几何间隔关系<br>$$\gamma = \frac{\hat{\gamma}}{||w||}$$<br>如果$||w||=1$那么几何间隔=函数间隔,如果超平面参数$w,b$成比例的改变(超平面不变),函数间隔按该比例改变,而几何间隔不变。</li></ol><h5 id="间隔最大化"><a href="#间隔最大化" class="headerlink" title="间隔最大化"></a>间隔最大化</h5><p><strong>支持向量机学习的基本思想求解能够正确划分训练数据集并且几何间隔最大的超平面,几何间隔最大的分离超平面是唯一的。</strong><br>直观解释:对训练集找到几何间隔最大的超平面意味着以充分大的确信度对训练数据进行分类,这样的超平面对未知的新实例有很好的泛化能力。</p><p>最大化间隔分离超平面转化为如下约束最优化问题:<br>$$\begin{equation}<br> \mathop{\max}_{(w,b)} \quad\gamma \\<br> \begin{cases}<br> & s.t.\quad y_i\left(\frac{w}{||w||}\cdot x_i+\frac{b}{||w||}\right)\geq \gamma,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><p>即最大化超平面关于训练集的几何间隔$\gamma$,约束条件表示超平面关于每个训练样本的几何间隔至少为$\gamma$。<br>用函数间隔表示为:<br>$$\begin{equation}<br> \mathop{\max}_{(w,b)} \quad\frac{\hat{\gamma}}{||w||} \\<br> \begin{cases}<br> & s.t.\quad y_i\left(w\cdot x_i+b\right)\geq \hat{\gamma},i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><p>函数间隔$\hat{\gamma}$的取值不影响最优化问题的解,这样就可以取$\hat{\gamma}=1$,代入上式,将$\frac{1}{||w||}$的最大化转化为$\frac{1}{2}||w||^2$最小化,它们是等价的,即线性可分支持向量机学习的最优化问题转化为:<br>$$\begin{equation}<br> \mathop{\min}_{(w,b)} \quad\frac{1}{2}||w||^2 \\<br> \begin{cases}<br> & s.t.\quad y_i(w\cdot x_i+b)-1\geq 0,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$<br>此为一个凸二次规划问题求解最优值。</p><p><strong>NOTE:</strong><br>概念:支持向量&间隔边界<br><img src="/images/pasted-9.png" alt="支持向量机"><br>$H1:w\cdot x+b=1,H2:w\cdot x+b=-1$。在H1\H2上的点就是支持向量,H1\H2就是间隔边界,H1\H2之间的距离为$\frac{2}{||w||}$为间隔</p><h5 id="学习对偶算法"><a href="#学习对偶算法" class="headerlink" title="学习对偶算法"></a>学习对偶算法</h5><p>原因:对偶问题比原始问题更好求解,方便引入核函数。<br><img src="/images/pasted-10.png" alt="对偶算法转化过程"><br>具体算法:<br>输入:线性数据集$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace$,<br>输出:分离超平面和决策函数</p><ol><li>构造并求解约束最优化问题</li></ol><p>$$\begin{equation}<br> \mathop{\min}_{\alpha} \quad\frac{1}{2} \sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_{i}\alpha_{j}y_iy_j(x_i \cdot x_j)-\sum\limits_{i=1}^{N}\alpha_{i} \\<br> \begin{cases}<br> & s.t.\quad \sum\limits_{i=1}^{N}\alpha_{i}y_i=0 \\<br> &\quad \alpha_i \geq 0,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><ol start="2"><li>计算<br>$$w^{\ast} = \sum\limits_{i=1}^{N}\alpha_{i}^{\ast}y_ix_i$$<br>并选择$\alpha^{\ast}$的一个正分量$a_j^{\ast}>0$计算$b^{\ast}$<br>$$b^{\ast} = y_j -\sum\limits_{i=1}^{N}\alpha_{i}^{\ast}y_i(x_i\cdot x_j) $$</li><li>求得分离超平面和分类决策函数<br>$$w^{\ast}\cdot x+b^{\ast}=0,\quad f(x)=sign(w^{\ast}\cdot x+b^{\ast})$$</li></ol><h4 id="线性支持向量机与软间隔最大化"><a href="#线性支持向量机与软间隔最大化" class="headerlink" title="线性支持向量机与软间隔最大化"></a>线性支持向量机与软间隔最大化</h4><p>在现实中,训练集往往是不可分的,线性可分的支持向量机对线性不可分训练数据不适用,因为上述的不等式约束不能都成立,因此需要修改硬间隔最大化为软间隔最大化。<br>线性不可分意味着某些样本点不能满足函数间隔大于等于1的约束条件,为了解决这个问题,对每个样本引入了一个松弛变量$\xi_i \geq 0$,使得函数间隔加上松弛变量大于等于1,约束条件变为$y_i(w \cdot x_i+b)+\xi_i\geq 1$,同时对每个松弛变量$\xi_i$支付一个代价$\xi_i$,目标函数由原来的$\frac{1}{2}||w||^2$变成$$\frac{1}{2}||w||^2+C\sum\limits_{i=1}^N\xi_i$$<br>上述公式$C>0$为惩罚参数,越大时,对误分类的惩罚增大,最小化上述目标函数:一方面使$\frac{1}{2}||w||^2$尽量小即间隔尽量大,同时是误分类点的个数尽量少。</p><p>线性不可分的支持向量机转为学习如下的凸二次规划最优化问题:<br>$$\begin{equation}<br> \mathop{\min}_{(w,b)} \quad\frac{1}{2}||w||^2 +C\sum\limits_{i=1}^N\xi_i\\<br> \begin{cases}<br> s.t.\quad &y_i(w \cdot x_i+b)\geq 1-\xi_i,i=1,2,…,N \\<br> \quad &\xi_i \geq 0,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><p>转化为对偶算法(具体转化方法类似线性可分支持向量机),即计算如下的凸二次规划:<br>$$\begin{equation}<br> \mathop{\min}_{\alpha} \quad\frac{1}{2} \sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_{i}\alpha_{j}y_iy_j(x_i \cdot x_j)-\sum\limits_{i=1}^{N}\alpha_{i} \\<br> \begin{cases}<br> & s.t.\quad \sum\limits_{i=1}^{N}\alpha_{i}y_i=0 \\<br> &\quad 0 \leq \alpha_i \leq C,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><p>线性支持向量机的算法:<br>输入:训练数据集<br>输出:分离超平面和分类决策函数</p><ol><li>选择惩罚参数$C$,构造并求解凸二次规划问题,求解最优$\alpha^{\ast}=(\alpha_1^{\ast},\alpha_2^{\ast},…,\alpha_N^{\ast})^T$</li></ol><p>$$\begin{equation}<br> \mathop{\min}_{\alpha} \quad\frac{1}{2} \sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_{i}\alpha_{j}y_iy_j(x_i \cdot x_j)-\sum\limits_{i=1}^{N}\alpha_{i} \\<br> \begin{cases}<br> & s.t.\quad \sum\limits_{i=1}^{N}\alpha_{i}y_i=0 \\<br> &\quad 0 \leq \alpha_i \leq C,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$</p><ol start="2"><li>计算$$w^{\ast} = \sum\limits_{i=1}^{N}\alpha_{i}^{\ast}y_ix_i$$<br>并选择$\alpha^{\ast}$的一个正分量$0\leq a_j^{\ast} \leq C$计算$b^{\ast}$<br>$$b^{\ast} = y_j -\sum\limits_{i=1}^{N}\alpha_{i}^{\ast}y_i(x_i\cdot x_j) $$</li><li>求得分离超平面和分类决策函数<br>$$w^{\ast}\cdot x+b^{\ast}=0,\quad f(x)=sign(w^{\ast}\cdot x+b^{\ast})$$</li></ol><h5 id="线性svm的支持向量"><a href="#线性svm的支持向量" class="headerlink" title="线性svm的支持向量"></a>线性svm的支持向量</h5><p>在线性不可分的情况下,通过对偶问题求解到$\alpha^{\ast}=(\alpha_1^{\ast},\alpha_2^{\ast},…,\alpha_N^{\ast})^T$中对应$\alpha_i^{\ast}>0$的样本点的实例$x_i$为支持向量,其中实例$x_i$到间隔编辑的距离为$\frac{\xi_i}{||w||}$</p><p>软间隔的支持向量:</p><ul><li>在间隔边界上$(若\alpha_i^{\ast}<C,则\xi_i=0)$,</li><li>在间隔边界与分离超平面之间$(若\alpha_i^{\ast}=C,则0<\xi_i<1)$,</li><li>在分离超平面误分的一侧$(若\alpha_i^{\ast}=C,则\xi_i>1)$</li><li>在分离超平面上$(若\alpha_i^{\ast}=C,则\xi_i=1)$</li></ul><h5 id="合页损失函数-hinge-loss"><a href="#合页损失函数-hinge-loss" class="headerlink" title="合页损失函数(hinge loss)"></a>合页损失函数(hinge loss)</h5><p>损失函数表示为$$L(y,f(x))=max(0,1-yf(x))$$<br>而线性支持向量机的原始问题为:<br>$$\begin{equation}<br> \mathop{\min}_{(w,b)} \quad\frac{1}{2}||w||^2 +C\sum\limits_{i=1}^N\xi_i\\<br> \begin{cases}<br> s.t.\quad &y_i(w \cdot x_i+b)\geq 1-\xi_i,i=1,2,…,N \\<br> \quad &\xi_i \geq 0,i=1,2,…,N<br> \end{cases}<br>\end{equation}$$<br><strong>应用合页损失函数,线性svm的原始问题等价于最优化问题</strong>:😇😇😇<br>$$\mathop{\min}_{(w,b)} \quad\sum\limits_{i=1}^{N} max(0,1-y_i(w\cdot x_i +b)) + \lambda ||w||^2$$<br>而$max(0,1-y_i(w\cdot x_i +b))=\xi_i, \lambda=\frac{1}{2C}$</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>线性支持向量机很好理解跟解释,下一章节见非线性支持向量机的原理。</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> SVM </tag>
<tag> 间隔最大化 </tag>
</tags>
</entry>
<entry>
<title>贝叶斯分类: 朴素贝叶斯法</title>
<link href="/2019/03/06/%E8%B4%9D%E5%8F%B6%E6%96%AF/"/>
<url>/2019/03/06/%E8%B4%9D%E5%8F%B6%E6%96%AF/</url>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。</p><p>而朴素贝叶斯分类是<strong>基于贝叶斯定理与特征条件独立假设</strong>的分类方法,是贝叶斯分类中最简单,也是常见的一种分类方法。对于给定的训练集,首先基于特征独立假设学习输入\输出的联合概率分布,然后基于此模型,对给定的输入$x$,利用贝叶斯定理求出后验概率最大的输出$y$,朴素贝叶斯实际上是学习到生成数据的机制,属于生成模型</p><p>特点:实现简单、学习与预测效率都很高</p><h4 id="朴素贝叶斯"><a href="#朴素贝叶斯" class="headerlink" title="朴素贝叶斯"></a>朴素贝叶斯</h4><h5 id="模型生成"><a href="#模型生成" class="headerlink" title="模型生成"></a>模型生成</h5><p>给定训练集$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)$,输入空间是$n$维向量的集合,输出空间$\lbrace c_1,c_2,…,c_K\rbrace$,训练集是由$P(X,Y)$独立同分布产生。<br>那么先验分布表示为:$$P(Y=c_k),k=1,2,…,K$$<br>条件概率分布表示为:$$P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},…,X^{(n)}=x^{(n)}|Y=c_k),k=1,2,…,K$$<br>由于朴素贝叶斯假定特征是独立的,所以,条件概率分布表示为:$$P(X=x|Y=c_k)=\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k),k=1,2,…,K$$</p><h5 id="模型预测"><a href="#模型预测" class="headerlink" title="模型预测"></a>模型预测</h5><p>朴素贝叶斯分类时,对给定的输入x,通过学习模型计算后验概率$P(Y=c_k|X=x)$,将后验概率最大的类作为$x$的输出。<br>后验概率表示为:<br>$$P(Y=c_k|X=x)=\frac{P(X=x|Y=c_k)P(Y=c_k)}{\sum_k P(X=x|Y=c_k)P(Y=c_k)}$$<br>代入特征条件独立后的公式,后验概率表示为:<br>$$P(Y=c_k|X=x)=\frac{P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_k P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}$$<br>于是朴素贝叶斯分离器的公式可以表示为:<br>$$y=f(x)=arg \max \limits_{c_k}\frac{P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_k P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}$$<br>而分母中对所有的$c_k$都是相同的,所以简化为:<br>$$y=f(x)=arg \max \limits_{c_k}P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)$$</p><h4 id="后验最大化-期望风险最小化"><a href="#后验最大化-期望风险最小化" class="headerlink" title="后验最大化=期望风险最小化"></a>后验最大化=期望风险最小化</h4><p>朴素贝叶斯后验概率最大化等价于期望风险最小化。<br>首先选择0-1损失函数:$$<br>L(Y,f(X)) =<br>\begin{cases}<br>1, & \text{$Y \neq f(X)$} \\<br>0, & \text{$Y = f(X)$}<br>\end{cases} $$<br>$f(X)$是决策函数,所以期望函数表示为:<br>$$R_{exp}(f)=E[L(Y,f(X))]=E_X \sum \limits_{k=1}^K[L(c_k,f(X))]P(c_k|X)$$<br>为了使期望风险最小化,需对$X=x$逐个极小化,由此得到<br>$$<br>\begin {align}<br>f(x)<br>&=arg \min \limits_{y \in \gamma} \sum \limits_{k=1}^{K}L(c_k,y)P(c_k|X=x) \\<br>&=arg \min \limits_{y \in \gamma} \sum \limits_{k=1}^{K}P(y \neq c_k|X=x) \\<br>&=arg \min (1-P(y=c_k|X=x)) \\<br>&=arg \max P(y=c_k|X=x)<br>\end {align}<br>$$<br>这样期望风险最小化准则就得到了后验概率最大化准则<br>$$f(x)=arg \max \limits_{c_k} P(c_k|X=x)$$</p><h4 id="参数估计"><a href="#参数估计" class="headerlink" title="参数估计"></a>参数估计</h4><p>在朴素贝叶斯法中,学习意味着估计$P(Y=c_k)$和$P(X^{(j)}=x^{(j)}|Y=c_k)$,所以可以利用极大似然估计法去估计相应的概率。<br>先验概率$P(Y=c_k)$的极大似然估计是:$$P(Y=c_k)=\frac{\sum \limits_{i=1}^NI(y_i=c_k)}{N},k=1,2,…,K$$<br>设第$j$个特征$x^(j)$可能的取值集合为$\lbrace a_{j1},a_{j2},…,a_{jS_j}\rbrace$,条件概率$P(X^{(j)}=a_{jl}|Y=c_k)$的极大似然估计是<br>$$P(X^{(j)}=a_{jl}|Y=c_k)=\frac{\sum \limits_{i=1}^{N}I(X^{(j)}=a_{jl},y_i=c_k)}{\sum \limits_{i=1}^{N}I(y_i=c_k)} \\<br>j=1,2,…,n;l=1,2,…,S_j;k=1,2,…,K$$<br>上式,$x_i^{(j)}$是第$i$个样本的第$j$个特征,$a_{jl}$是第$j$个特征可能取的第$l$个值,$I$是指数函数。</p><h4 id="朴素贝叶斯算法"><a href="#朴素贝叶斯算法" class="headerlink" title="朴素贝叶斯算法"></a>朴素贝叶斯算法</h4><p>输入:训练数据$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)$,其中$x_i=(x_i^{(1)},x_i^{(2)},…,x_i^{(n)})^T$,$x_i^{(j)}$是第$i$个样本的第$j$个特征;$x_i^(j) \in \lbrace a_{j1},a_{j2},…,a_{jS_j}\rbrace$;$a_{jl}$是第$j$个特征可能取的第$l$个值,$j=1,2,…,n;l=1,2,…,S_j;k=1,2,…,K$;实例$x$<br>输出:实例$x$的分类</p><ol><li>计算先验概率和条件概率<br>$$P(Y=c_k)=\frac{\sum \limits_{i=1}^NI(y_i=c_k)}{N},k=1,2,…,K$$<br>$$P(X^{(j)}=a_{jl}|Y=c_k)=\frac{\sum \limits_{i=1}^{N}I(X^{(j)}=a_{jl},y_i=c_k)}{\sum \limits_{i=1}^{N}I(y_i=c_k)} \\<br>j=1,2,…,n;l=1,2,…,S_j;k=1,2,…,K$$</li><li>对给定的实例$x=(x^{(1)},x^{(2)},…,x^{(n)})^T$,计算<br>$$P(Y=c_k)\prod \limits_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_k),k=1,2,…,K$$</li><li>确定实例$x$的类<br>$$y=f(x)=arg \max \limits_{c_k}P(Y=c_k)\prod \limits_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)$$</li></ol><h4 id="贝叶斯估计"><a href="#贝叶斯估计" class="headerlink" title="贝叶斯估计"></a>贝叶斯估计</h4><p><strong>由于用极大似然估计可能会出现所估计概率为0,这会影响到后验概率的计算,使分类产生偏差</strong>,解决这一问题使用贝叶斯估计。<br>条件概率的贝叶斯估计是:<br>$$P_{\lambda}(X^{(j)}=a_{jl}|Y=c_k)=\frac{\sum \limits_{i=1}^{N}I(X^{(j)}=a_{jl},y_i=c_k)+\lambda}{\sum \limits_{i=1}^{N}I(y_i=c_k)+S_j\lambda} $$<br>上式中,$\lambda \geq 0$,当$\lambda=0$就是极大似然估计,$\lambda=1$称为拉普拉斯平滑<br>同样的,先验概率的贝叶斯估计为:<br>$$P_{\lambda}(Y=c_k)=\frac{\sum \limits_{i=1}^NI(y_i=c_k)+\lambda}{N+K\lambda},k=1,2,…,K$$</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><ul><li>朴素贝叶斯是典型的生成学习方法,生成方法由训练数据学习联合分布$P(X,Y)$,然后求得后验概率分布$P(Y|X)$。<br>具体来说,利用训练集学习$P(X|Y),P(Y)$的估计,然后得到联合概率分布$P(X,Y)=P(Y)P(X|Y)$,然后利用学习到的联合概率模型和贝叶斯定理进行分类预测$$P(Y|X)=\frac{P(X,Y)}{P(X)}=\frac{P(Y)P(X|Y)}{\sum \limits_Y P(Y)P(X|Y)}$$</li><li>概率估计方法可以使用极大似然估计或者贝叶斯估计</li><li>分类预测输出的类为后验概率最大的类,后验概率最大等价于0-1损失函数的期望风险最小化</li></ul>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> python </tag>
<tag> 贝叶斯 </tag>
<tag> 参数估计 </tag>
<tag> 极大似然估计 </tag>
</tags>
</entry>
<entry>
<title>Linux 常用命令大全</title>
<link href="/2019/03/05/Linux-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E5%A4%A7%E5%85%A8/"/>
<url>/2019/03/05/Linux-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E5%A4%A7%E5%85%A8/</url>
<content type="html"><![CDATA[<h4 id="关机-系统的关机、重启以及登出"><a href="#关机-系统的关机、重启以及登出" class="headerlink" title="关机 (系统的关机、重启以及登出 )"></a>关机 (系统的关机、重启以及登出 )</h4><p>shutdown -h now 关闭系统(1)<br>init 0 关闭系统(2)<br>telinit 0 关闭系统(3)<br>shutdown -h hours:minutes & 按预定时间关闭系统<br>shutdown -c 取消按预定时间关闭系统<br>shutdown -r now 重启(1)<br>reboot 重启(2)<br>logout 注销</p><h4 id="文件和目录"><a href="#文件和目录" class="headerlink" title="文件和目录"></a>文件和目录</h4><p>cd /home 进入 ‘/ home’ 目录’<br>cd .. 返回上一级目录<br>cd ../.. 返回上两级目录<br>cd 进入个人的主目录<br>cd ~user1 进入个人的主目录<br>cd - 返回上次所在的目录<br>pwd 显示工作路径<br>ls 查看目录中的文件<br>ls -F 查看目录中的文件<br>ls -l 显示文件和目录的详细资料<br>ls -a 显示隐藏文件<br>ls <em>[0-9]</em> 显示包含数字的文件名和目录名<br>tree 显示文件和目录由根目录开始的树形结构(1)<br>lstree 显示文件和目录由根目录开始的树形结构(2)<br>mkdir dir1 创建一个叫做 ‘dir1’ 的目录’<br>mkdir dir1 dir2 同时创建两个目录<br>mkdir -p /tmp/dir1/dir2 创建一个目录树<br>rm -f file1 删除一个叫做 ‘file1’ 的文件’<br>rmdir dir1 删除一个叫做 ‘dir1’ 的目录’<br>rm -rf dir1 删除一个叫做 ‘dir1’ 的目录并同时删除其内容<br>rm -rf dir1 dir2 同时删除两个目录及它们的内容<br>mv dir1 new_dir 重命名/移动 一个目录<br>cp file1 file2 复制一个文件<br>cp dir/<em> . 复制一个目录下的所有文件到当前工作目录<br>cp -a /tmp/dir1 . 复制一个目录到当前工作目录<br>cp -a dir1 dir2 复制一个目录<br>ln -s file1 lnk1 创建一个指向文件或目录的软链接<br>ln file1 lnk1 创建一个指向文件或目录的物理链接<br>touch -t 0712250000 file1 修改一个文件或目录的时间戳 - (YYMMDDhhmm)<br>file file1 outputs the mime type of the file as text<br>iconv -l 列出已知的编码<br>iconv -f fromEncoding -t toEncoding inputFile > outputFile creates a new from the given input file by assuming it is encoded in fromEncoding and converting it to toEncoding.<br>find . -maxdepth 1 -name </em>.jpg -print -exec convert “{}” -resize 80x60 “thumbs/{}” \; batch resize files in the current directory and send them to a thumbnails directory (requires convert from Imagemagick) </p><h4 id="文件搜索"><a href="#文件搜索" class="headerlink" title="文件搜索"></a>文件搜索</h4><p>find / -name file1 从 ‘/‘ 开始进入根文件系统搜索文件和目录<br>find / -user user1 搜索属于用户 ‘user1’ 的文件和目录<br>find /home/user1 -name *.bin 在目录 ‘/ home/user1’ 中搜索带有’.bin’ 结尾的文件<br>find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件<br>find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件<br>find / -name *.rpm -exec chmod 755 ‘{}’ \; 搜索以 ‘.rpm’ 结尾的文件并定义其权限<br>find / -xdev -name *.rpm 搜索以 ‘.rpm’ 结尾的文件,忽略光驱、捷盘等可移动设备<br>locate *.ps 寻找以 ‘.ps’ 结尾的文件 - 先运行 ‘updatedb’ 命令<br>whereis halt 显示一个二进制文件、源码或man的位置<br>which halt 显示一个二进制文件或可执行文件的完整路径 </p><h4 id="用户和群组"><a href="#用户和群组" class="headerlink" title="用户和群组"></a>用户和群组</h4><p>groupadd group_name 创建一个新用户组<br>groupdel group_name 删除一个用户组<br>groupmod -n new_group_name old_group_name 重命名一个用户组<br>useradd -c “Name Surname “ -g admin -d /home/user1 -s /bin/bash user1 创建一个属于 “admin” 用户组的用户<br>useradd user1 创建一个新用户<br>userdel -r user1 删除一个用户 ( ‘-r’ 排除主目录)<br>usermod -c “User FTP” -g system -d /ftp/user1 -s /bin/nologin user1 修改用户属性<br>passwd 修改口令<br>passwd user1 修改一个用户的口令 (只允许root执行)<br>chage -E 2005-12-31 user1 设置用户口令的失效期限<br>pwck 检查 ‘/etc/passwd’ 的文件格式和语法修正以及存在的用户<br>grpck 检查 ‘/etc/passwd’ 的文件格式和语法修正以及存在的群组<br>newgrp group_name 登陆进一个新的群组以改变新创建文件的预设群组 </p><h4 id="文件的权限-使用-“-”-设置权限,使用-“-“-用于取消"><a href="#文件的权限-使用-“-”-设置权限,使用-“-“-用于取消" class="headerlink" title="文件的权限 - 使用 “+” 设置权限,使用 “-“ 用于取消"></a>文件的权限 - 使用 “+” 设置权限,使用 “-“ 用于取消</h4><p>ls -lh 显示权限<br>ls /tmp | pr -T5 -W$COLUMNS 将终端划分成5栏显示<br>chmod ugo+rwx directory1 设置目录的所有人(u)、群组(g)以及其他人(o)以读(r )、写(w)和执行(x)的权限<br>chmod go-rwx directory1 删除群组(g)与其他人(o)对目录的读写执行权限<br>chown user1 file1 改变一个文件的所有人属性<br>chown -R user1 directory1 改变一个目录的所有人属性并同时改变改目录下所有文件的属性<br>chgrp group1 file1 改变文件的群组<br>chown user1:group1 file1 改变一个文件的所有人和群组属性<br>find / -perm -u+s 罗列一个系统中所有使用了SUID控制的文件<br>chmod u+s /bin/file1 设置一个二进制文件的 SUID 位 - 运行该文件的用户也被赋予和所有者同样的权限<br>chmod u-s /bin/file1 禁用一个二进制文件的 SUID位<br>chmod g+s /home/public 设置一个目录的SGID 位 - 类似SUID ,不过这是针对目录的<br>chmod g-s /home/public 禁用一个目录的 SGID 位<br>chmod o+t /home/public 设置一个文件的 STIKY 位 - 只允许合法所有人删除文件<br>chmod o-t /home/public 禁用一个目录的 STIKY 位</p><h4 id="文件的特殊属性-使用-“-”-设置权限,使用-“-“-用于取消"><a href="#文件的特殊属性-使用-“-”-设置权限,使用-“-“-用于取消" class="headerlink" title="文件的特殊属性 - 使用 “+” 设置权限,使用 “-“ 用于取消"></a>文件的特殊属性 - 使用 “+” 设置权限,使用 “-“ 用于取消</h4><p>chattr +a file1 只允许以追加方式读写文件<br>chattr +c file1 允许这个文件能被内核自动压缩/解压<br>chattr +d file1 在进行文件系统备份时,dump程序将忽略这个文件<br>chattr +i file1 设置成不可变的文件,不能被删除、修改、重命名或者链接<br>chattr +s file1 允许一个文件被安全地删除<br>chattr +S file1 一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘<br>chattr +u file1 若文件被删除,系统会允许你在以后恢复这个被删除的文件<br>lsattr 显示特殊的属性 </p><h4 id="打包和压缩文件"><a href="#打包和压缩文件" class="headerlink" title="打包和压缩文件"></a>打包和压缩文件</h4><p>bunzip2 file1.bz2 解压一个叫做 ‘file1.bz2’的文件<br>bzip2 file1 压缩一个叫做 ‘file1’ 的文件<br>gunzip file1.gz 解压一个叫做 ‘file1.gz’的文件<br>gzip file1 压缩一个叫做 ‘file1’的文件<br>gzip -9 file1 最大程度压缩<br>rar a file1.rar test_file 创建一个叫做 ‘file1.rar’ 的包<br>rar a file1.rar file1 file2 dir1 同时压缩 ‘file1’, ‘file2’ 以及目录 ‘dir1’<br>rar x file1.rar 解压rar包<br>unrar x file1.rar 解压rar包<br>tar -cvf archive.tar file1 创建一个非压缩的 tarball<br>tar -cvf archive.tar file1 file2 dir1 创建一个包含了 ‘file1’, ‘file2’ 以及 ‘dir1’的档案文件<br>tar -tf archive.tar 显示一个包中的内容<br>tar -xvf archive.tar 释放一个包<br>tar -xvf archive.tar -C /tmp 将压缩包释放到 /tmp目录下<br>tar -cvfj archive.tar.bz2 dir1 创建一个bzip2格式的压缩包<br>tar -jxvf archive.tar.bz2 解压一个bzip2格式的压缩包<br>tar -cvfz archive.tar.gz dir1 创建一个gzip格式的压缩包<br>tar -zxvf archive.tar.gz 解压一个gzip格式的压缩包<br>zip file1.zip file1 创建一个zip格式的压缩包<br>zip -r file1.zip file1 file2 dir1 将几个文件和目录同时压缩成一个zip格式的压缩包<br>unzip file1.zip 解压一个zip格式压缩包 </p><h4 id="APT-软件工具-Debian-Ubuntu-以及类似系统"><a href="#APT-软件工具-Debian-Ubuntu-以及类似系统" class="headerlink" title="APT 软件工具 (Debian, Ubuntu 以及类似系统)"></a>APT 软件工具 (Debian, Ubuntu 以及类似系统)</h4><p>apt-get install package_name 安装/更新一个 deb 包<br>apt-cdrom install package_name 从光盘安装/更新一个 deb 包<br>apt-get update 升级列表中的软件包<br>apt-get upgrade 升级所有已安装的软件<br>apt-get remove package_name 从系统删除一个deb包<br>apt-get check 确认依赖的软件仓库正确<br>apt-get clean 从下载的软件包中清理缓存<br>apt-cache search searched-package 返回包含所要搜索字符串的软件包名称 </p><h4 id="查看文件内容"><a href="#查看文件内容" class="headerlink" title="查看文件内容"></a>查看文件内容</h4><p>cat file1 从第一个字节开始正向查看文件的内容<br>tac file1 从最后一行开始反向查看一个文件的内容<br>more file1 查看一个长文件的内容<br>less file1 类似于 ‘more’ 命令,但是它允许在文件中和正向操作一样的反向操作<br>head -2 file1 查看一个文件的前两行<br>tail -2 file1 查看一个文件的最后两行<br>tail -f /var/log/messages 实时查看被添加到一个文件中的内容 </p><h4 id="文本处理"><a href="#文本处理" class="headerlink" title="文本处理"></a>文本处理</h4><p>cat file1 file2 … | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT<br>cat file1 | command( sed, grep, awk, grep, etc…) > result.txt 合并一个文件的详细说明文本,并将简介写入一个新文件中<br>cat file1 | command( sed, grep, awk, grep, etc…) >> result.txt 合并一个文件的详细说明文本,并将简介写入一个已有的文件中<br>grep Aug /var/log/messages 在文件 ‘/var/log/messages’中查找关键词”Aug”<br>grep ^Aug /var/log/messages 在文件 ‘/var/log/messages’中查找以”Aug”开始的词汇<br>grep [0-9] /var/log/messages 选择 ‘/var/log/messages’ 文件中所有包含数字的行<br>grep Aug -R /var/log/<em> 在目录 ‘/var/log’ 及随后的目录中搜索字符串”Aug”<br>sed ‘s/stringa1/stringa2/g’ example.txt 将example.txt文件中的 “string1” 替换成 “string2”<br>sed ‘/^$/d’ example.txt 从example.txt文件中删除所有空白行<br>echo ‘esempio’ | tr ‘[:lower:]’ ‘[:upper:]’ 合并上下单元格内容<br>sed -e ‘1d’ result.txt 从文件example.txt 中排除第一行<br>sed -n ‘/stringa1/p’ 查看只包含词汇 “string1”的行<br>sed -e ‘s/ </em>$//‘ example.txt 删除每一行最后的空白字符<br>sed -e ‘s/stringa1//g’ example.txt 从文档中只删除词汇 “string1” 并保留剩余全部<br>sed -n ‘1,5p;5q’ example.txt 查看从第一行到第5行内容<br>sed -n ‘5p;5q’ example.txt 查看第5行<br>sed -e ‘s/00*/0/g’ example.txt 用单个零替换多个零<br>cat -n file1 标示文件的行数<br>cat example.txt | awk ‘NR%2==1’ 删除example.txt文件中的所有偶数行<br>echo a b c | awk ‘{print $1}’ 查看一行第一栏<br>paste file1 file2 合并两个文件或两栏的内容<br>paste -d ‘+’ file1 file2 合并两个文件或两栏的内容,中间用”+”区分<br>sort file1 file2 排序两个文件的内容<br>sort file1 file2 | uniq 取出两个文件的并集(重复的行只保留一份)<br>sort file1 file2 | uniq -u 删除交集,留下其他的行<br>sort file1 file2 | uniq -d 取出两个文件的交集(只留下同时存在于两个文件中的文件)<br>comm -1 file1 file2 比较两个文件的内容只删除 ‘file1’ 所包含的内容<br>comm -2 file1 file2 比较两个文件的内容只删除 ‘file2’ 所包含的内容<br>comm -3 file1 file2 比较两个文件的内容只删除两个文件共有的部分 </p><h4 id="字符设置和文件格式转换"><a href="#字符设置和文件格式转换" class="headerlink" title="字符设置和文件格式转换"></a>字符设置和文件格式转换</h4><p>dos2unix filedos.txt fileunix.txt 将一个文本文件的格式从MSDOS转换成UNIX<br>unix2dos fileunix.txt filedos.txt 将一个文本文件的格式从UNIX转换成MSDOS<br>recode ..HTML < page.txt > page.html 将一个文本文件转换成html<br>recode -l | more 显示所有允许的转换格式 </p><h4 id="文件系统分析"><a href="#文件系统分析" class="headerlink" title="文件系统分析"></a>文件系统分析</h4><p>badblocks -v /dev/hda1 检查磁盘hda1上的坏磁块<br>fsck /dev/hda1 修复/检查hda1磁盘上linux文件系统的完整性<br>fsck.ext2 /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性<br>e2fsck /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性<br>e2fsck -j /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性<br>fsck.ext3 /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性<br>fsck.vfat /dev/hda1 修复/检查hda1磁盘上fat文件系统的完整性<br>fsck.msdos /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性<br>dosfsck /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性 </p><h4 id="初始化一个文件系统"><a href="#初始化一个文件系统" class="headerlink" title="初始化一个文件系统"></a>初始化一个文件系统</h4><p>mkfs /dev/hda1 在hda1分区创建一个文件系统<br>mke2fs /dev/hda1 在hda1分区创建一个linux ext2的文件系统<br>mke2fs -j /dev/hda1 在hda1分区创建一个linux ext3(日志型)的文件系统<br>mkfs -t vfat 32 -F /dev/hda1 创建一个 FAT32 文件系统<br>fdformat -n /dev/fd0 格式化一个软盘<br>mkswap /dev/hda3 创建一个swap文件系统 </p><h4 id="SWAP文件系统"><a href="#SWAP文件系统" class="headerlink" title="SWAP文件系统"></a>SWAP文件系统</h4><p>mkswap /dev/hda3 创建一个swap文件系统<br>swapon /dev/hda3 启用一个新的swap文件系统<br>swapon /dev/hda2 /dev/hdb3 启用两个swap分区 </p><h4 id="备份"><a href="#备份" class="headerlink" title="备份"></a>备份</h4><p>dump -0aj -f /tmp/home0.bak /home 制作一个 ‘/home’ 目录的完整备份<br>dump -1aj -f /tmp/home0.bak /home 制作一个 ‘/home’ 目录的交互式备份<br>restore -if /tmp/home0.bak 还原一个交互式备份<br>rsync -rogpav –delete /home /tmp 同步两边的目录<br>rsync -rogpav -e ssh –delete /home ip_address:/tmp 通过SSH通道rsync<br>rsync -az -e ssh –delete ip_addr:/home/public /home/local 通过ssh和压缩将一个远程目录同步到本地目录<br>rsync -az -e ssh –delete /home/local ip_addr:/home/public 通过ssh和压缩将本地目录同步到远程目录<br>dd bs=1M if=/dev/hda | gzip | ssh user@ip_addr ‘dd of=hda.gz’ 通过ssh在远程主机上执行一次备份本地磁盘的操作<br>dd if=/dev/sda of=/tmp/file1 备份磁盘内容到一个文件<br>tar -Puf backup.tar /home/user 执行一次对 ‘/home/user’ 目录的交互式备份操作<br>( cd /tmp/local/ && tar c . ) | ssh -C user@ip_addr ‘cd /home/share/ && tar x -p’ 通过ssh在远程目录中复制一个目录内容<br>( tar c /home ) | ssh -C user@ip_addr ‘cd /home/backup-home && tar x -p’ 通过ssh在远程目录中复制一个本地目录<br>tar cf - . | (cd /tmp/backup ; tar xf - ) 本地将一个目录复制到另一个地方,保留原有权限及链接<br>find /home/user1 -name ‘<em>.txt’ | xargs cp -av –target-directory=/home/backup/ –parents 从一个目录查找并复制所有以 ‘.txt’ 结尾的文件到另一个目录<br>find /var/log -name ‘</em>.log’ | tar cv –files-from=- | bzip2 > log.tar.bz2 查找所有以 ‘.log’ 结尾的文件并做成一个bzip包<br>dd if=/dev/hda of=/dev/fd0 bs=512 count=1 做一个将 MBR (Master Boot Record)内容复制到软盘的动作<br>dd if=/dev/fd0 of=/dev/hda bs=512 count=1 从已经保存到软盘的备份中恢复MBR内容 </p><h4 id="光盘"><a href="#光盘" class="headerlink" title="光盘"></a>光盘</h4><p>cdrecord -v gracetime=2 dev=/dev/cdrom -eject blank=fast -force 清空一个可复写的光盘内容<br>mkisofs /dev/cdrom > cd.iso 在磁盘上创建一个光盘的iso镜像文件<br>mkisofs /dev/cdrom | gzip > cd_iso.gz 在磁盘上创建一个压缩了的光盘iso镜像文件<br>mkisofs -J -allow-leading-dots -R -V “Label CD” -iso-level 4 -o ./cd.iso data_cd 创建一个目录的iso镜像文件<br>cdrecord -v dev=/dev/cdrom cd.iso 刻录一个ISO镜像文件<br>gzip -dc cd_iso.gz | cdrecord dev=/dev/cdrom - 刻录一个压缩了的ISO镜像文件<br>mount -o loop cd.iso /mnt/iso 挂载一个ISO镜像文件<br>cd-paranoia -B 从一个CD光盘转录音轨到 wav 文件中<br>cd-paranoia – “-3” 从一个CD光盘转录音轨到 wav 文件中(参数-3)<br>cdrecord –scanbus 扫描总线以识别scsi通道<br>dd if=/dev/hdc | md5sum 校验一个设备的md5sum编码,例如一张 CD </p><h4 id="系统信息"><a href="#系统信息" class="headerlink" title="系统信息"></a>系统信息</h4><p>arch 显示机器的处理器架构(1)<br>uname -m 显示机器的处理器架构(2)<br>uname -r 显示正在使用的内核版本<br>dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI)<br>hdparm -i /dev/hda 罗列一个磁盘的架构特性<br>hdparm -tT /dev/sda 在磁盘上执行测试性读取操作<br>cat /proc/cpuinfo 显示CPU info的信息<br>cat /proc/interrupts 显示中断<br>cat /proc/meminfo 校验内存使用<br>cat /proc/swaps 显示哪些swap被使用<br>cat /proc/version 显示内核的版本<br>cat /proc/net/dev 显示网络适配器及统计<br>cat /proc/mounts 显示已加载的文件系统<br>lspci -tv 罗列 PCI 设备<br>lsusb -tv 显示 USB 设备<br>date 显示系统日期<br>cal 2007 显示2007年的日历表<br>date 041217002007.00 设置日期和时间 - 月日时分年.秒<br>clock -w 将时间修改保存到 BIOS </p><h4 id="挂载一个文件系统"><a href="#挂载一个文件系统" class="headerlink" title="挂载一个文件系统"></a>挂载一个文件系统</h4><p>mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 - 确定目录 ‘/ mnt/hda2’ 已经存在<br>umount /dev/hda2 卸载一个叫做hda2的盘 - 先从挂载点 ‘/ mnt/hda2’ 退出<br>fuser -km /mnt/hda2 当设备繁忙时强制卸载<br>umount -n /mnt/hda2 运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用<br>mount /dev/fd0 /mnt/floppy 挂载一个软盘<br>mount /dev/cdrom /mnt/cdrom 挂载一个cdrom或dvdrom<br>mount /dev/hdc /mnt/cdrecorder 挂载一个cdrw或dvdrom<br>mount /dev/hdb /mnt/cdrecorder 挂载一个cdrw或dvdrom<br>mount -o loop file.iso /mnt/cdrom 挂载一个文件或ISO镜像文件<br>mount -t vfat /dev/hda5 /mnt/hda5 挂载一个Windows FAT32文件系统<br>mount /dev/sda1 /mnt/usbdisk 挂载一个usb 捷盘或闪存设备<br>mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share 挂载一个windows网络共享 </p><h4 id="磁盘空间"><a href="#磁盘空间" class="headerlink" title="磁盘空间"></a>磁盘空间</h4><p>df -h 显示已经挂载的分区列表<br>ls -lSr |more 以尺寸大小排列文件和目录<br>du -sh dir1 估算目录 ‘dir1’ 已经使用的磁盘空间’<br>du -sk * | sort -rn 以容量大小为依据依次显示文件和目录的大小<br>rpm -q -a –qf ‘%10{SIZE}t%{NAME}n’ | sort -k1,1n 以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统)<br>dpkg-query -W -f=’${Installed-Size;10}t${Package}n’ | sort -k1,1n 以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统) </p>]]></content>
<categories>
<category> tool </category>
</categories>
<tags>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>k近邻法</title>
<link href="/2019/03/05/k%E8%BF%91%E9%82%BB%E6%B3%95/"/>
<url>/2019/03/05/k%E8%BF%91%E9%82%BB%E6%B3%95/</url>
<content type="html"><![CDATA[<h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>k近邻(KNN)是一种基本的分类和回归的方法。KNN的输入为实例的特征向量,输出为实例的类别,不需要训练【实际上利用训练集对特征向量空间进行划分】,给定一个训练集,其中的实例类别已定,分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过投票等方式进行预测。</p><p><strong>三个基本要素:</strong>$k$值的选择、距离度量、分类决策规则</p><p><strong>优点</strong>:简单、直观</p><h4 id="KNN算法"><a href="#KNN算法" class="headerlink" title="KNN算法"></a>KNN算法</h4><p>给定一个训练集,对新的输入实例,在训练集中找到与该实例最近邻的k个实例,这k个实例的多数属于某个类,就把该输入实例分为这个类。</p><p>算法如下:<br>输入:训练集$T$<br>输出:新的实例所属的类</p><ol><li>根据给定的距离度量,在训练集$T$中找到与实例最接近的k个点,涵盖这k个点的$x$的邻域记作$N_k(x)$</li><li>在邻域$N_k(x)$中根据分类决策规则(eg 多数表决)决定$x$的类别$y$:$$y=arg \max \limits_{c_j} \sum \limits_{x_j \in N_k(x)} I(y_i=c_j),i=1,2,…,N;j=1,2,…,K$$其中I为指示函数,即$y_i=c_j$时I为1,否则为0.</li></ol><p>NOTE:</p><ol><li>knn的特殊情况是k=1时,称为最近邻算法。</li><li>knn没有显式学习,当训练集、距离度量、k值以及分类决策规则确定后,对任何一个新输入的实例,它所属的类就唯一地确定。</li></ol><hr><h4 id="距离度量"><a href="#距离度量" class="headerlink" title="距离度量"></a>距离度量</h4><p>设特征空间是$n$维实数向量空间$R^n$,$x_i=(x_i^{(1)},x_i^{(2)},…,x_i^{(n)})^T,x_j=(x_j^{(1)},x_j^{(2)},…,x_j^{(n)})^T$,$x_i,x_j$的距离:</p><ol><li><strong>$L_p$距离</strong>:$$L_p(x_i,x_j)=\left(\sum \limits_{l=1}^n |x_i^{(l)}-x_j^{(l)}|^p \right)^{\frac{1}{p}}$$这里的$p\geq 1$</li><li>当$p=2$时,称为欧式距离,即:$$L_2(x_i,x_j)=\left(\sum \limits_{l=1}^n |x_i^{(l)}-x_j^{(l)}|^2 \right)^{\frac{1}{2}}$$</li><li>当$p=1$时,称为曼哈顿距离,即:$$L_1(x_i,x_j)=\sum \limits_{l=1}^n |x_i^{(l)}-x_j^{(l)}|$$</li><li>当$p=+\infty$时,它是各个坐标距离的最大值,即:$$L_{\infty}(x_i,x_j)=\max \limits_{l}|x_i^{(l)}-x_j^{(l)}|$$<br>更多距离公式请查阅博文《机器学习中距离度量完整版》</li></ol><h4 id="k值的选择"><a href="#k值的选择" class="headerlink" title="k值的选择"></a>k值的选择</h4><p>k值越小学习误差会减小,缺点是,预测误差会增大,预测结果会对近邻的实例点非常敏感,如果恰巧是噪音,预测就会出错,<strong>k值越小整体模型越复杂,容易发生过拟合</strong></p><p>k值越大,学习误差会增大,但是预测误差会减小,这是与输入实例较远的训练实例也会对预测起作用,<strong>k值增大就意味着模型越简单</strong></p><p>NOTE:在应用中,k值一般选取较小值,<strong>通常采用交叉验证来选取最优k值</strong></p><h4 id="分类决策规则"><a href="#分类决策规则" class="headerlink" title="分类决策规则"></a>分类决策规则</h4><p>多数表决规则等价于经验风险最小化。<br>对给定的实例$x$,其最近邻的$k$个训练实例点构成集合$N_k(x)$,如果涵盖$N_k(x)$的区域的类别是$c_j$,那么误分类率是$$\frac{1}{k} \sum \limits_{x_i \in N_k(x)} I(y_i \neq c_j)=1-\frac{1}{k} \sum \limits_{x_i \in N_k(x)} I(y_i =c_j)$$<br>要使误分类率最小即经验风险最小,就要使$\sum \limits_{x_i \in N_k(x)} I(y_i =c_j)$最大,所以多数表决规则等价于经验风险最小化。</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><hr><p>补充后加入</p><hr><h4 id="kd树🌲"><a href="#kd树🌲" class="headerlink" title="kd树🌲"></a>kd树🌲</h4><p><strong>实现knn时,主要考虑的问题是如何对训练集进行快速j近邻搜索,尤其是特征空间维度大以及训练数据容量大的时候</strong><br>KNN最简单的实现方法是线性扫描,但是当训练集很大时,很费时,为了提高KNN的效率,使用kd树存储数据,减少计算距离的次数。</p><h5 id="kd树生成"><a href="#kd树生成" class="headerlink" title="kd树生成"></a>kd树生成</h5><p>kd树🌲是一种对$k$维空间中的实例点进行存储以便对其进行快速检索的树形结构,kd树是二叉树,表示对k维空间的划分,构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的$k$维超矩形区域,kd树的每个结点对应于一个$k$维超矩形区域。</p><p>通常,依次选择坐标轴对空间切分,选择训练实例点在选定坐标轴的中位数为切分点,这样得到的kd树是平衡的,注意,平衡的kd树搜索效率不一定是最优的。</p><p><strong>算法</strong><br>输入: $k$维空间数据集$T=\lbrace x_1,x_2,…,x_N \rbrace$,其中$x_i=(x_i^{(1)},x_i^{(2)},…,x_i^{(k)})^T,i=1,2,…,N;$<br>输出:kd树</p><ol><li>开始:构造根结点,根结点对应于包含$T$的$k$空间的超矩形区域<br>选择$x^{(1)}$为坐标轴,以$T$中所有实例的$x^{(1)}$坐标的中位数为切分点,将根结点对应的矩形超矩形区域切分成两个区域,切分由通过切分点并与坐标轴$x^{(1)}$垂直,左子结点对应坐标$x^{(1)}$小于切分点,右子结点对应坐标$x^{(1)}$大于切分点。</li><li>重复切分子结点</li><li>直至两个子区域没有实例存在时,停止,从而形成kd树的划分</li></ol><h5 id="kd树搜索"><a href="#kd树搜索" class="headerlink" title="kd树搜索"></a>kd树搜索</h5><p>利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。<br>搜索🔍:<br>给定目标点,搜索其最近邻,首先找到包含目标点的叶结点;然后从该叶结点出发,依次回退到父结点;不断查找与目标点最邻近的结点,当确定不可能存在更近的结点时终止。【目标点的最邻近一定在以目标点为中心并通过当前最近点的超球体的内部】。<br>具体搜索过程参考李航《统计学习方法》page43</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>KNN简单且不需要训练,而是利用训练集对特征空间进行分类,当KNN三要素【训练集、距离度量、k值以及分类决策规则】确定后,利用KNN模型进行分类,结果就是唯一确定的;k值的大小与模型复杂度相关,k越小模型复杂度越高,k越大模型复杂度越低;KNN实现需要考虑如何快速搜索k个最近邻的点,利用kd树可以减少搜索的计算量。</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> knn </tag>
<tag> 距离度量 </tag>
<tag> 欧氏距离 </tag>
<tag> 曼哈顿距离 </tag>
<tag> kd树 </tag>
</tags>
</entry>
<entry>
<title>感知机</title>
<link href="/2019/03/04/%E6%84%9F%E7%9F%A5%E6%9C%BA/"/>
<url>/2019/03/04/%E6%84%9F%E7%9F%A5%E6%9C%BA/</url>
<content type="html"><![CDATA[<h4 id="感知机是什么?"><a href="#感知机是什么?" class="headerlink" title="感知机是什么?"></a>感知机是什么?</h4><p>感知机是一个<strong>二分类的线性分类模型</strong>,输入特征向量,输出为实例的类别$\lbrace +1,-1\rbrace$。<br>感知机模型旨在求出将训练数据进行线性划分的超平面,求解过程中使用误分类的损失函数,利用梯度下降法对损失函数进行极小化。<br><strong>特点:简单易实现</strong></p><p><strong>概念:</strong><br><strong>什么叫线性可分(linearly separable)?</strong><br>对于给定一数据集$T$,如果存在一超平面可以将数据集中的正负样例完全正确的划分到超平面的两侧,即对所有的$y_i=+1$的实例$i$,有$w\cdot x_i+b>0$,$y_i=-1$的实例$i$,有$w\cdot x_i+b<0$<br>则称数据集$T$是线性可分的,否则就是线性不可分。</p><hr><p>具体模型:<br>假设输入向量为$x$,输出$y$表示实例的类别$\lbrace +1,-1\rbrace$,从输入空间到输出空间有如下函数:<br>$$f(x)=sign(w\cdot x+b)$$</p><p>$$sign(x)=<br>\begin{cases}<br>1, & \text{$x \geq 0$} \\<br>0, & \text{$x < 0$}<br>\end{cases} $$<br>感知机模型的假设空间是定义在特征空间中的所有线性分类模型或者线性分类器,函数集合为$\lbrace f(x)=w\cdot x+b \rbrace$<br>感知机学习就是由训练集$T={(x_1,y_1),(x_2,y_2),…,(x_N,y_N)}$求得参数$w,b$,感知器预测就是利用感知机对新的实例进行预测。</p><hr><p><strong>学习过程:</strong><br>为了找出这样的超平面,确定参数$w,b$,需要定义损失函数,并将损失函数最小化。<br>我们容易想到,误分类点的总数作为损失函数,但是这样的损失函数不是参数$w,b$的连续可导,不易优化。为此,<strong>选择误分类点到超平面的总距离</strong>,输入空间任一点$x_0$到超平面$S$的总距离表示为:<br>$$\frac{1}{||w||}|w\cdot x_0+b|$$<br>对于误分类的数据来说,$-y_i(w\cdot x_i+b)>0$,因此假设所有误分类点集合未$M$,那么所有误分类点到超平面的总距离为$$-\frac{1}{||w||}\sum \limits_{x_i \in M}y_i(w\cdot x_i+b)$$<br>所以,最终的损失函数定义为:<br>$$L(w,b)=-\sum \limits_{x_i \in M}y_i(w\cdot x_i+b)$$<br>由于损失函数是$w,b$的连续可导函数,所以用梯度下降法更新参数$w,b$。<br>$$\min \limits_{w,b} L(w,b)=-\sum \limits_{x_i \in M}y_i(w\cdot x_i+b)$$<br>$M$是误分类点的集合<br>梯度为:<br>$$\frac{dL(w,b)}{dw}=-\sum \limits_{x_i \in M}y_ix_i$$<br>$$\frac{dL(w,b)}{db}=-\sum \limits_{x_i \in M}y_i$$<br>首先,任意选取一个超平面$w_0,b_0$,然后用梯度下降法优化极小化目标函数$L(w,b)$,极小化过程中不是一次使$M$中所有的误分类点的梯度下降,而是一次随机选取一个误分类点随其梯度下降。<br>随机去一个误分类点$(x_i,y_i)$进行更新:<br>$$w\leftarrow w+\eta y_ix_i,b \leftarrow b+\eta y_i$$</p><hr><p><strong>基本算法:</strong><br>输入:训练集$T$,学习率$\eta(0<\eta\leq 1)$<br>输出:$w,b$以及感知机模型$f(x)=sign(w\cdot x+b)$</p><ol><li>初始值$w_0,b_0$</li><li>训练集中选择$(x_i,y_i)$</li><li>如果$y_i(w \cdot x_i +b) \leq 0$更新$$w\leftarrow w+\eta y_ix_i,b \leftarrow b+\eta y_i$$</li><li>转至2.直至数据集中没有误分类点</li></ol><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><hr><p>整理后加入</p><hr><h4 id="算法收敛性"><a href="#算法收敛性" class="headerlink" title="算法收敛性"></a>算法收敛性</h4><p><strong>收敛</strong>:指迭代若干次之后,目标量收敛曲线趋于平稳,趋于定值。<br>在这里,主要是证明,对于线性可分数据集感知机学习算法原始形式收敛,即经验有限次迭代可以得到一个将训练集完全正确划分的分离超平面及感知机模型。<br>定理:设训练集$T=\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace$是线性可分的,其中$x_i \in X=R^n,y_i \in Y=\lbrace -1,+1\rbrace,i=1,2,…,N$,则<br>(1)存在满足条件的$|| \hat{w}_{opt}||$的超平面$ \hat{w}_{opt} \cdot \hat{x}=w_{opt} \cdot x+b_{opt}=0$将训练数据完全正确分开,且存在$\gamma>0$,对所有$i=1,2,…,N$<br>$$y_i(\hat{w}_{opt} \cdot \hat{x})=y_i(w_{opt} \cdot x+b_{opt}) \geq \gamma$$<br>(2)令$R=\max\limits_{1 \leq i \leq N}||\hat{x_i}||$,则感知机算法在训练数据集上的误分类次数$k$满足不等式$$k \leq \left(\frac{R}{\gamma} \right)^2$$<br>内容推算过程参考《统计学习方法》<br>定理证明,误分类的次数$k$是有上界的,也就是说线性可分时,感知器学习算法原始形式迭代是收敛的。<br>当训练集线性不可分,感知机学习算法不收敛,迭代结果会发生震荡。</p><h4 id="算法的对偶形式"><a href="#算法的对偶形式" class="headerlink" title="算法的对偶形式"></a>算法的对偶形式</h4><p>感知机学习的原始形式与对偶形式与支持向量机学习算法的原始形式和对偶形式相对应。<br>对偶形式的基本想法是,将$w$和$b$表示为实例$x_i$和$y_i$的线性组合的形式,假设初始值$w_0=0,b_0=0$<br>误分类点$(x_i,y_i)$通过$$w\leftarrow w+\eta y_ix_i,b \leftarrow b+\eta y_i$$<br>设修改$n$次,则$w,b$关于$(x_i,y_i)$的增量分别是$\alpha_iy_ix_i$和$\alpha_iy_i$,$\alpha_i=n_i\eta$,最后学习到的$w,b$可以表示为<br>$$w=\sum \limits_{i=1}^{N}a_iy_ix_i,b=\sum \limits_{i=1}^{N}a_iy_i$$<br>这里,$\alpha_i\geq 0,i=1,2,…,N$,当$\eta=1$时,表示第$i$个实例由于误分类而进行更新的次数,实例点更新次数越多,意味着他距离超平面越近,也越难正确分类。</p><p>算法:<br>输入:训练集$T$,学习率$\eta$<br>输出:$\alpha,b$,感知机模型$f(x)=sign \left(\sum \limits_{j=1}^Na_jy_jx_j\cdot x+b \right)$,其中$\alpha=(\alpha_1,\alpha_2,…,\alpha_N)^T$</p><ol><li>$\alpha \leftarrow 0,b \leftarrow 0$</li><li>在训练集中选取数据$\lbrace x_i,y_i \rbrace$</li><li>如果$y_i \left( \sum \limits_{j=1}^Na_jy_jx_j\cdot x+b \right) \leq 0$ $$ \alpha \leftarrow \alpha_i +\eta, b\leftarrow b+ \eta y_i$$</li><li>转至第2直到没有误分类</li></ol><hr><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>总体来说感知机相对简单一些,而且针对的是线性可分的数据集,感知机用到的损失函数对应于误分类点到分离超平面的总距离,这样就可以基于随机梯度下降法对损失函数进行最优化。另外,感知机学习算法存在无穷多个解,其解与初始值或者不同的迭代顺序而有可能产生不同。</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> ML </tag>
<tag> 感知机 </tag>
<tag> 线性可分 </tag>
<tag> 收敛性 </tag>
<tag> 对偶形式 </tag>
</tags>
</entry>
<entry>
<title>CART的理解与应用</title>
<link href="/2019/03/01/CART%E7%9A%84%E7%90%86%E8%A7%A3%E4%B8%8E%E5%BA%94%E7%94%A8/"/>
<url>/2019/03/01/CART%E7%9A%84%E7%90%86%E8%A7%A3%E4%B8%8E%E5%BA%94%E7%94%A8/</url>
<content type="html"><![CDATA[<p>本博客接上一篇博客《决策树的理解与运用》。</p><h4 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h4><p>分类与回归树(Classification AND Regression tree,CART)同样是由特征选择、树的生成和剪枝三部分组成,<strong>它的特点是既可以用于分类又可以用于回归。</strong></p><p>CART是在给定输入随机变量为$X$条件下输出随机变量Y的条件概率分布的学习方法,假设决策树为二叉树,内部结点取值为“是”or“否”【左是右否】。决策树等价于递归地二分每个特征,将输入空间划分为有限个单元,并在这些单元上预测概率分布,也就是给定条件下输出的条件概率分布。<br>类似表示如下<br><img src="/images/pasted-8.png" alt="决策树"><br>CART算法组成:<br>1.决策树生成🌲:基于训练集生成决策树,生产的决策树尽力大【生成过程等价于递归地构建二叉树的过程】<br>2.决策树剪枝✂️:用验证数据集对已生成的树进行剪枝,选择最优子树,用损失函数最下作为剪枝的标准。</p><hr><h4 id="CART生成"><a href="#CART生成" class="headerlink" title="CART生成"></a>CART生成</h4><h5 id="回归树"><a href="#回归树" class="headerlink" title="回归树"></a>回归树</h5><p><strong>回归树的生成用平方误差最小化准则</strong><br>假设$X$和$Y$分别是输入和输出,并且Y是连续变量,训练集表示为$D=(x_1,y_1),(x_2,y_2),…,(x_N,y_N)$<br>假设回归树将输入空间(特征空间)划分为$M$个单元$R_1,R_2,…,R_M$并且每一个单元有一个固定的输出值$c_m$,于是回归树表示成:<br>$$f(x)=\sum_{m=1}^Mc_mI(x \in R_m)$$</p><p>当输入空间的划分确定时,可以用平方误差$\sum_{x_i \in R_m}{(y_i-f(x_i))}^2$表示回归树的训练集的预测误差,平方误差最小的准则求解每个单元上的最优输出值,易知,单元$R_m$的最优输出值是$R_m$上的所有输入实例$x_i$对应的输出$y_i$的均值,即:<br>$$\hat{c_m}=ave(y_i|x_i\in R_m)$$</p><p><strong>问题是如何划分??</strong><br>【采用启发式的方法】<br>选择第$j$个变量$x^{(j)}$和它的取值$s$,作为切分变量和切分点定义两个区域:<br>$$R_1(j,s)=\lbrace x|x^{(j)}\leq s\rbrace和R_2(j,s)=\lbrace x|x^{(j)}> s\rbrace$$<br>然后求最优切分变量j和最优切分点s,求解:</p><p>$$\min \limits_{(j,s)} \left(\min \limits_{c_1} \sum \limits_{x_i \in R_1(j,s)}(y_i−c_1)^2+\min \limits_{c_2} \sum \limits_{x_i \in R_2(j,s)}(y_i−c_2)^2 \right)$$</p><p>给定输入变量j可以找到最优切分点s.<br>$$\hat{c_1}=ave(y_i|x_i\in R_1(j,s)) ,\hat{c_2}=ave(y_i|x_i \in R_2(j,s))$$<br>遍历所有输入变量,找到最优的切分变量$j$,构成一个对$(j,s)$,这样将空间划分为2个区域,然后每个区域重复上面的划分过程,这样就生成了一颗回归树,<strong>称为最小二乘回归树</strong></p><hr><p><strong>最小二乘回归树生成算法</strong><br>输入训练集$D$<br>输出:回归树$f(x)$<br>在训练集所在的特征空间,递归地将每个区域划分为两个子区域并决定每个子区域的输出值,构建二叉树:</p><ol><li>选择最优切分变量j和最优切分点s,求解:<br>$$\min \limits_{(j,s)} \left(\min \limits_{c_1} \sum \limits_{x_i \in R_1(j,s)}(y_i−c_1)^2+\min \limits_{c_2} \sum \limits_{x_i \in R_2(j,s)}(y_i−c_2)^2 \right)$$</li><li>遍历变量$j$,对固定的切分变量$j$扫描切分点$s$,使得上公式达到最小值的对$(j,s)$</li><li>用选定的对(j,s)划分区域并决定相应的输出值:<br>$$R_1(j,s)=\lbrace x|x^{(j)}\leq s\rbrace和R_2(j,s)=\lbrace x|x^{(j)}> s\rbrace$$<br>$$\hat{c_m}=\frac{1}{N_m}\sum \limits_{x_i \in {R_m(j,s)}}y_i,x \in R_m,m=1,2$$</li><li>继续对两个子域调用步骤1,2,直到满足停止条件<br>将输入空间(特征空间)划分为$M$个单元$R_1,R_2,…,R_M$并且每一个单元有一个固定的输出值c_m,于是回归树表示成<br>$$f(x)=\sum_{m=1}^Mc_mI(x \in R_m)$$</li></ol><hr><h5 id="分类树的生成"><a href="#分类树的生成" class="headerlink" title="分类树的生成"></a>分类树的生成</h5><p>分类树用<strong>基尼指数</strong>来选择最优特征,同时决定该特征的最优二值切分。</p><p>定义:分类问题中,假设有$K$个类,样本中属于第$k$类的概率为$p_k$,则概率分布的基尼指数定义为:<br>$$Gini(p)=\sum_{k=1}^{K}p_k(1-p_k)=1-\sum_{k=1}^{K}{p_k}^2$$<br>二分类中样本点属于第一类概率为$p$,概率分布的基尼系数为:<br>$$Gini(p)=2p(1-p)$$<br>对于样本集合$D$,其基尼系数为:<br>$$Gini(D)=1-\sum_{k=1}^{K}{\lbrace\frac{|C_k|}{|D|}}\rbrace^2$$<br>其中,$C_k$是$D$中属于第$k$类的样本子集,$K$是类的个数<br>基尼指数$Gini(D)$表示集合$D$的不确定性,基尼指数越大,不确定性也就越大,这与熵相似。<br><strong>分割:</strong><br>如果样本集合$D$根据特征$A$是否取某一值$\alpha$被分割为$D_1$和$D_2$,表示为:<br>$$D_1=\lbrace (x,y) \in D|A(x)=\alpha\rbrace,D_2=D-D_1$$<br>在特征$A$的条件下,$Gini(D,A)$表示经过$A=\alpha$分割后集合$D$的不确定性,基尼指数表示为:<br>$$Gini(D,A)=\frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2)$$<br><strong>算法生成</strong><br><strong>输入</strong>:训练集$D$,停止条件【eg 结点中的样本个数小于阈值,基尼指数小于阈值,或者没有更多的特征等】 <strong>输出</strong>:CART树<br>根据训练集,从根结点开始,递归地对每个结点进行以下操作,构建二叉树决策树。</p><ol><li>设结点的数据集为$D$,计算现有特征对该数据集的基尼指数,对每个特征,每个其可能取的每个值$\alpha$,计算基尼指数。</li><li>选择最优特征以及其对应的最优切分点,从而生成两个子结点</li><li>对子结点递归的调用1.2步骤,直至满足停止条件</li><li>生成CART树</li></ol><p>CART生成方式与ID3完成一致</p><hr><h4 id="CART剪枝✂️"><a href="#CART剪枝✂️" class="headerlink" title="CART剪枝✂️"></a>CART剪枝✂️</h4><p>CART是一个“完全二叉树”<br>剪枝算法如下:<br>从生成算法产生的决策树$T_0$底部开始剪枝,直到$T_0$的根结点,形成子树序列为$\lbrace T_0,T_1,T_2,…,T_n \rbrace$,然后再用交叉验证法在独立的验证集熵对序列进行测试,从中选择最优子树。</p><ol><li><strong>剪枝,形成子树序列</strong><br>子树的损失函数表示如下:<br>$$C_a(T)=C(T)+\alpha|T|$$<br>其中,$T$是任意子树,$C(T)$是训练集的预测误差(eg基尼指数),$|T|$是子树的叶子结点,$\alpha$是正则化参数,权衡训练集拟合程度与模型复杂度。<br>利用递归地方法进行剪枝✂️:<br>$\alpha$从小到大产生一系列区间$\alpha_0<\alpha_1<\cdots<\alpha_n<$,产生一系列的区间$[\alpha_i,\alpha_{i+1}],i=0,1,\cdots,n$;剪枝对应的子树序列对应着区间$\alpha \in[\alpha_i,\alpha_{i+1}],i=0,1,\cdots,n$的最优子树序列$\lbrace T_0,T_1,T_2,…,T_n \rbrace$,序列中的子树是嵌套的。<br>具体:<br>从整体树$T_0$开始剪枝,对$T_0$的任意内部结点$t$,以单结点树的损失函数是:$$C_a(t)=C(t)+\alpha$$<br>以$t$为根结点的子树$T_t$的损失函数是:$$C_a(T_t)=C(T_t)+\alpha|T_t|$$<br>当$\alpha=0$以及充分小时,有不等式$C_a(T_t)\leq C_a(t)$<br>当$\alpha$增大时,在某一$\alpha$有:$C_a(T_t)=C_a(t)$<br>当$\alpha$再增大时,不等式反向,只要$\alpha=\frac{C(t)-C(T_t)}{|T_t|-1}$,$T_t$与$t$有相同的损失值,而$t$的结点少,因此$t$比$T_t$更可取,因此对$t$进行修剪。<br>为此,对$T_0$中每一内部结点$t$,计算<br>$$g(t)=\frac{C(t)-C(T_t)}{|T_t|-1}$$<br>它表示剪枝后整体损失函数减少的程度,在$T_0$中剪去$g(t)$最小的$T_t$,得到的子树作为$T_1$,同时将最小的$g(t)$设置为$\alpha_1$,$T_1$为$[\alpha_1,\alpha_{2}]$的最优子树<br>如此剪枝,直到跟根结点,这一过程,不断增大$\alpha$,产生新的区间。</li><li>在剪枝得到的子树序列$\lbrace T_0,T_1,T_2,…,T_n \rbrace$中通过交叉验证选取最优子树$T_a$<br>利用独立的验证集测试子树序列中各个子树的平方误差或者基尼指数。</li></ol><p>算法:<br>输入:CART算法生成的决策树$T_0$<br>输出:最优决策树$T_\alpha$</p><ol><li>设$k=0,T=T_0,\alpha=+\infty$</li><li>自底而上地对内部结点$t$计算$C(T_t),|T_t|$以及$g(t)=\frac{C(t)-C(T_t)}{|T_t|-1},\alpha=min(\alpha,g(t))$</li><li>对$g(t)=\alpha$的内部结点进行剪枝,并对叶结点$t$以多数表决法决定其类得到树$T$</li><li>设$k=k+1,T_k=T,\alpha_k=\alpha$</li><li>如果$T_k$不是由根结点及两个叶子结点构成的树,则回到步骤2.否则另$T_k=T_n$</li><li>采用交叉验证法在子树序列$\lbrace T_0,T_1,T_2,…,T_n \rbrace$中选取最优子树$T_\alpha$</li></ol><h4 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h4><hr><p>整理后加入</p><hr><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>CART大部分内容与决策树的一致,主要不同点是分类树和决策树的生成过程使用的标准以及剪枝过程,在简单决策树的基础上理解CART会更容易,所以推荐先阅读《决策树的理解与应用》</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> 决策树 </tag>
<tag> ML </tag>
<tag> CART </tag>
<tag> 基尼指数 </tag>
<tag> 平方和误差 </tag>
</tags>
</entry>
<entry>
<title>决策树的理解与应用</title>
<link href="/2019/02/28/%E5%86%B3%E7%AD%96%E6%A0%91%E7%9A%84%E7%90%86%E8%A7%A3/"/>
<url>/2019/02/28/%E5%86%B3%E7%AD%96%E6%A0%91%E7%9A%84%E7%90%86%E8%A7%A3/</url>
<content type="html"><![CDATA[<h4 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h4><p>决策树🌲是一种基本的分类和回归的方法【以前总是下意识以为决策树只能用于分类,事实上还可以用于回归】。在分类问题中,决策树基于特征对实例进行分类,这个分类过程可以认为是if-then的规则集合,也可以认为是特征空间与类空间上的条件概率分布。</p><p><strong>NOTE:</strong><br>if—then规则集合具有一个重要的特征:互斥且完备,即每个实例都被一条路径或者一条规则所覆盖,而且只能被一条路径或一条规则所覆盖</p><p><strong>优点</strong>:简单易理解、分类速度快</p><p><strong>过程</strong>:利用损失函数最小化原则对训练集进行建模,再利用建立好的模型进行分类。决策树的学习算法通常是递归地选择最优特征,并根据特征对训练集进行分割,最终形成从【根结点->叶子结点】的树模型,<strong>但是这样生成的树可以容易发生过拟合,所以需要自底向上修剪✋</strong></p><p><strong>决策树学习包括三个步骤:特征选择、决策树生成、决策树修剪</strong><br>1.当特征数量较多时,在学习之前先进行特征选择<br>2.决策树生成对应局部最优<br>3.决策树修剪对应全局最优</p><p><strong>目标</strong>:选择一个与训练数据矛盾较小的决策树,同时具有很好的泛化能力。</p><hr><h4 id="特征选择"><a href="#特征选择" class="headerlink" title="特征选择"></a>特征选择</h4><p>通常,特征选择的准则是<strong>信息增益或者信息增益比</strong></p><p>先介绍基本概念:</p><ol><li><p><strong>熵</strong><br>熵用来表示随机变量不确定的程度,熵越大,不确定程度越大。<br>设$X$是一个取有限值的随机变量,概率分布为$P(X=x_i)=p_i,i=1,2,…,n$<br>那么熵定义为:<br>$$H(X)=-\sum_{i=1}^{n}p_ilogp_i,i=1,2,…,n$$<br>NOTE:<br>熵只依赖$X$的分布,与$X$的取值无关,定义$0log0=0$。</p></li><li><p><strong>条件熵</strong><br>条件熵$H(Y|X)$表示在已知随机变量$X$的条件下随机变量$Y$的不确定性。<br>定义为:$$H(Y|X)=\sum_{i=1}^{n}P(X=x_i)H(Y|X=x_i),i=1,2,…,n$$</p></li><li><p><strong>经验熵和经验条件熵</strong><br>当熵和条件熵中的概率是由数据估计而得到的,所对应的熵和条件熵被称为经验熵和经验条件熵</p></li><li><p><strong>信息增益</strong><br>特征$A$对训练集$D$的信息增益$g(D,A)$,定义为集合$D$的经验熵与在给定条件$A$下$D$的经验条件熵H(D|A)之差,即<br>$$g(D,A)=H(D)-H(D|A)$$<br><strong>特征选择过程</strong>:对训练集计算每个特征的信息增益,并比较信息增益的大小,选择信息增益最大是特征。<br>INPUT:训练数据集$D$和特征$A$<br>OUTPUT:特征$A$对训练数据$D$的信息增益$g(D,A)$<br>#计算数据集$D$的经验熵<br>$$H(D)=-\sum_{k=1}^{K}\frac{|C_k|}{|D|}log_2\frac{|C_k|}{|D|}$$<br>#计算特征$A$对训练数据$D$的经验条件熵$H(D|A)$:<br>$$H(D|A)=\sum_{i=1}^{n}\frac{|D_i|}{|D|}H(D_i)=-\sum_{i=1}^{n}\frac{|D_i|}{|D|}\sum_{k=1}^{K}\frac{|D_{ik}|}{|D_i|}log_2\frac{|D_{ik}|}{|D_i|}$$<br>#计算信息增益<br>$$g(D,A)=H(D)-H(D|A)$$</p></li><li><p><strong>信息增益比</strong><br>由于以<strong>信息增益进行选择,那么会趋于选择取值较多的特征</strong>,所以提出使用信息增益比。<br>信息增益比定义为:其信息增益$g(D,A)$与训练集$D$关于特征$A$的值的熵$H_A(D)$,即<br>$$g_R(D,A)=\frac{g(D,A)}{H_A(D)}$$<br>其中${H_A(D)}=-\sum_{i=1}^{n}\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|}$,$n$是特征值$A$的个数。</p></li></ol><h4 id="决策树生成"><a href="#决策树生成" class="headerlink" title="决策树生成"></a>决策树生成</h4><ol><li><p><strong>ID3算法</strong><br>核心:在决策树各个结点上应用信息增益准则选择特征,然后递归地构建决策树。<br>过程:从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点,再对子结点递归地调用以上方法,构建决策树,直到所有的特征信息增益均很小或者没有特征可以选择为止。<br><strong>ID3相当于用极大似然法进行概率模型的选择</strong><br>NOTE:<br>由于ID3算法只有树的生成,所以生成的树模型容易产生过拟合现象。</p></li><li><p><strong>C4.5算法</strong><br>过程与ID3相似,只是对ID3进行了改进,使用信息增益比来选择特征。</p></li></ol><hr><h4 id="决策树剪枝"><a href="#决策树剪枝" class="headerlink" title="决策树剪枝"></a>决策树剪枝</h4><p>决策树的生成过程仅考虑到对训练数据集分类的准确性,这样生成的树模型容易出现过拟合且构建的树过于复杂,所以有必要对其进行剪枝。</p><p><strong>剪枝</strong>:从已生成的树上裁掉一些子树或者叶结点,并将其根结点或者父结点作为新的叶结点,从而简化分类树模型。<strong>剪枝往往是通过极小化决策树的整体损失函数来实现的</strong></p><p><strong>定义损失函数</strong>:<br>设树$T$的叶结点个数为$|T|$,$t$是树的叶结点,该叶结点有$N_t$个样本点,其中$k$类的样本点有$N_{tk},k=1,2,…,K$,其中$H_t(T)$是叶子结点$t$的经验熵,$\alpha\geq 0$为参数,决策树学习的损失函数为:<br>$$C_a(T)=\sum_{t=1}^{|T|}N_tH_t(T)+\alpha|T|$$<br>其中$H_t(T)=-\sum_{k=1}^{K}\frac{N_{tk}}{N_t}log\frac{N_{tk}}{N_t}$<br>所以最终的损失函数表示为:<br>$$C_a(T)=-\sum_{t=1}^{|T|}\sum_{k=1}^{K}N_{tk}log\frac{N_{tk}}{N_t}+\alpha|T|$$</p><p>公式解释:$-\sum_{t=1}^{|T|}\sum_{k=1}^{K}N_{tk}log\frac{N_{tk}}{N_t}$是表示模型对训练集的预测误差,即模型与训练集的拟合程度,$|T|$表示模型的复杂度,叶子节点数越大模型越复杂,$\alpha$是调节参数,控制模型的拟合和复杂程度。<br>当$\alpha$确定时,选择损失函数最小的模型,这里定义的损失函数其实等价于正则化的极大似然估计。</p><p><strong>算法:</strong><br>INPUT: 生成算法产生的整个树$T$,参数$\alpha$<br>OUPUT: 修剪后的子树$T_a$<br>1.计算每个结点的经验熵<br>2.递归地从树的叶结点向上回缩<br>回缩前后整体树的损失函数比较,如果回缩前的损失函数大于回缩后,进行剪枝。<br>3.重复2,直到不能继续为止,得到损失函数最小的子树$T_a$</p><hr><h4 id="python-代码实现"><a href="#python-代码实现" class="headerlink" title="python 代码实现"></a>python 代码实现</h4><hr><p>后期加入</p><hr><p>总结:决策树是一种简单快速的分类算法,本文不仅把熵相关的概念给整理了一遍,文中信息增益和信息增益比也可以用于其他模型的特征选择,而最后剪枝部分提到的决策树的损失函数是我之前在专门写的《详述机器学习中的损失函数》博客中没有提到的,这里也是一个补充。</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> 决策树 </tag>
<tag> ML </tag>
<tag> python </tag>
<tag> 熵、条件熵 </tag>
<tag> 信息增益、信息增益比 </tag>
<tag> CART </tag>
<tag> ID3/C4.5 </tag>
</tags>
</entry>
<entry>
<title>如何使python代码更pythonic</title>
<link href="/2019/02/26/%E5%A6%82%E4%BD%95%E6%98%AFpython%E4%BB%A3%E7%A0%81%E6%9B%B4pythonic/"/>
<url>/2019/02/26/%E5%A6%82%E4%BD%95%E6%98%AFpython%E4%BB%A3%E7%A0%81%E6%9B%B4pythonic/</url>
<content type="html"><![CDATA[<h4 id="理解python与c语言的不同"><a href="#理解python与c语言的不同" class="headerlink" title="理解python与c语言的不同"></a>理解python与c语言的不同</h4><p><strong>变量替换</strong></p><p>在python中两个变量不需要引入中间替换量,利用python的packing/unpacking机制,替换只需:<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">a</span>,b= <span class="selector-tag">b</span>,a</span><br></pre></td></tr></table></figure></p><p><strong>安全关闭文件描述符</strong><br>需要安全关闭文件,使用with语句:</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">with</span> <span class="keyword">open</span>(<span class="keyword">path</span>,<span class="string">'r'</span>,<span class="keyword">mode</span>=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line">do_sth_with(f)</span><br></pre></td></tr></table></figure><p><strong>list倒序排列</strong></p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line">print <span class="type">list</span>(reversed(a))</span><br></pre></td></tr></table></figure><p><strong>字符串格式化法</strong><br>使用str.format()</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span> <span class="string">'{great} from {language}'</span>.<span class="built_in">format</span>{great=<span class="string">'hello world'</span>,language=<span class="string">'python'</span>}</span><br></pre></td></tr></table></figure><p><strong>flask框架的学习</strong></p><p><strong>检查程序PEP8的使用</strong></p><figure class="highlight nsis"><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="variable">$pip</span> install -U pep8</span><br><span class="line"><span class="comment">#检查代码</span></span><br><span class="line"><span class="variable">$pep8</span> --文件名.py</span><br><span class="line"><span class="comment">#使用--show-source参数让PEP8显示每个错误和警告对应的代码</span></span><br><span class="line"><span class="variable">$pep8</span> --<span class="literal">show</span>-source --<span class="literal">show</span>-pep8 name.py</span><br><span class="line"><span class="comment">#甚至可以检查一个项目的质量,并生成报表</span></span><br></pre></td></tr></table></figure><p><strong>缩进、{}、单引号和双引号</strong></p><p>与c/c++/java使用{}来分割代码不同,python中使用严格的代码缩进方式分割代码块。python 中单引号和双引号没有明显区别,而使用上有小区别。<br><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">string_1</span> = <span class="string">"He said, \"hello\""</span></span><br><span class="line"><span class="attr">string_2</span> = <span class="string">'He said, "hello"'</span></span><br></pre></td></tr></table></figure></p><p><strong>三元操作符</strong></p><p>python2.5之前不支持三元操作符<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#三元操作符写法</span></span><br><span class="line">X <span class="keyword">if</span> C <span class="keyword">else</span> Y</span><br><span class="line"><span class="builtin-name">print</span> x <span class="keyword">if</span> x<y <span class="keyword">else</span> y</span><br></pre></td></tr></table></figure></p><p><strong>没有swith…case</strong></p><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> **:</span><br><span class="line"><span class="keyword">elif</span> **:</span><br><span class="line"><span class="keyword">elif</span> **:</span><br><span class="line"><span class="keyword">else</span>:</span><br></pre></td></tr></table></figure><p><strong>将常量集中到一个文件</strong><br>提倡把常量放在一个文件里,这样有利于维护,一旦需要修改常量值可以直接修改</p><p><strong>利用assert语句来发现问题</strong></p><p><strong>充分利用lazy evaluation的特性</strong><br>常被翻译为延迟计算或者懒性计算,指仅仅在真正需要执行的时候才计算的表达式</p>]]></content>
<categories>
<category> book </category>
</categories>
<tags>
<tag> python </tag>
</tags>
</entry>
<entry>
<title>剑指offer编程题(python版)</title>
<link href="/2019/02/25/%E5%89%91%E6%8C%87offer%E7%BC%96%E7%A8%8B%E9%A2%98/"/>
<url>/2019/02/25/%E5%89%91%E6%8C%87offer%E7%BC%96%E7%A8%8B%E9%A2%98/</url>
<content type="html"><![CDATA[<hr><p>校招准备ing</p><hr><h4 id="二维数组中的查找"><a href="#二维数组中的查找" class="headerlink" title="二维数组中的查找"></a>二维数组中的查找</h4><p>在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。<br><strong>思路:</strong><br>数组特点,从左到右,从上到下均为递增,所以从最右上方第一个开始比较,如果大于这个数,数组下移,因为该行没有比目标值更大的数。从最左下方开始,思路一样。<br><strong>代码:</strong><br><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="comment"># array 二维列表</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">Find</span><span class="params">(self, target, array)</span>:</span></span><br><span class="line"> rowcount = len(array) <span class="comment"># 获取行数</span></span><br><span class="line"> colcount = len(array[<span class="number">0</span>]) <span class="comment"># 获取列数</span></span><br><span class="line"> <span class="keyword">if</span> colcount == <span class="number">0</span>:<span class="comment">#这里要考虑到二维数组为空的情况,如[[]]</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(colcount<span class="number">-1</span>,<span class="number">-1</span>,<span class="number">-1</span>): <span class="comment">#起始为colcount-1行,末尾行为第0行,步长为-1</span></span><br><span class="line"> <span class="keyword">if</span> target > array[<span class="number">0</span>][i]: <span class="comment">#要查找的数字大于右上角的数字</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(rowcount): <span class="comment">#下移比较</span></span><br><span class="line"> <span class="keyword">if</span> target == array[j][i]: <span class="comment">#找到,返回True</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"> <span class="keyword">elif</span> target == array[<span class="number">0</span>][i]: <span class="comment">#要查找的数字等于右上角的数字,返回True</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"> <span class="comment">#否则上移</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">False</span></span><br></pre></td></tr></table></figure></p><h4 id="替换空格"><a href="#替换空格" class="headerlink" title="替换空格"></a>替换空格</h4><p>请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。<br><strong>思路:</strong><br>考察字符串替换问题,如果是11替换就可以直接遍历,但是题目要求是13替换,即将” “替换为3个字符,那么字符串长度会发生变化。最好的办法是从字符串最末端进行替换。<br><strong>代码:</strong><br><figure class="highlight ruby"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">## 第一次实现代码,不是最佳👌</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="comment"># s 源字符串</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">replaceSpace</span><span class="params">(<span class="keyword">self</span>, s)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="comment"># write code here</span></span><br><span class="line"> old_s_list = list(s)</span><br><span class="line"> new_s_list = []</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="symbol">old_s_list:</span></span><br><span class="line"> <span class="keyword">if</span> i == <span class="string">" "</span><span class="symbol">:</span></span><br><span class="line"> new_s_list.append(<span class="string">"%20"</span>)</span><br><span class="line"> <span class="symbol">else:</span> </span><br><span class="line"> new_s_list.append(i)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>.join(new_s_list)</span><br></pre></td></tr></table></figure></p><h4 id="从头到尾打印链表"><a href="#从头到尾打印链表" class="headerlink" title="从头到尾打印链表"></a>从头到尾打印链表</h4><p>输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。<br><strong>思路:</strong><br>将链表中的值记录到list之中,然后利用list语句[::-1]或者list(reversed(new_list) 翻转list<br><strong>代码:</strong><br><figure class="highlight ruby"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding:utf-8 -*-</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ListNode</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>, x)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.val = x</span><br><span class="line"> <span class="keyword">self</span>.<span class="keyword">next</span> = None</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="comment"># 返回从尾部到头部的列表值序列,例如[1,2,3]</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">printListFromTailToHead</span><span class="params">(<span class="keyword">self</span>, listNode)</span></span><span class="symbol">:</span></span><br><span class="line"> new_list=[]</span><br><span class="line"> <span class="keyword">while</span> <span class="symbol">listNode:</span></span><br><span class="line"> new_list.append(listNode.val)</span><br><span class="line"> listNode=listNode.<span class="keyword">next</span></span><br><span class="line"> <span class="keyword">return</span> new_list[<span class="symbol">:</span><span class="symbol">:-</span><span class="number">1</span>]</span><br></pre></td></tr></table></figure></p><h4 id="重建二叉树"><a href="#重建二叉树" class="headerlink" title="重建二叉树"></a>重建二叉树</h4><p>输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。<br><strong>思路:</strong><br><strong>代码:</strong><br><figure class="highlight clean"><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><br><span class="line"></span><br><span class="line">#### 用两个栈实现队列</span><br><span class="line">用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。</span><br><span class="line">**思路:**</span><br><span class="line">**代码:**</span><br></pre></td></tr></table></figure></p><p><code>`</code></p>]]></content>
<categories>
<category> 校招 </category>
</categories>
<tags>
<tag> python </tag>
<tag> algorithm </tag>
</tags>
</entry>
<entry>
<title>逻辑回归和最大熵模型</title>
<link href="/2019/02/25/logistics%E5%9B%9E%E5%BD%92%E5%92%8C%E6%9C%80%E5%A4%A7%E7%86%B5%E6%A8%A1%E5%9E%8B/"/>
<url>/2019/02/25/logistics%E5%9B%9E%E5%BD%92%E5%92%8C%E6%9C%80%E5%A4%A7%E7%86%B5%E6%A8%A1%E5%9E%8B/</url>
<content type="html"><![CDATA[<h3 id="逻辑回归"><a href="#逻辑回归" class="headerlink" title="逻辑回归"></a>逻辑回归</h3><h4 id="逻辑分布"><a href="#逻辑分布" class="headerlink" title="逻辑分布"></a>逻辑分布</h4><p>在介绍逻辑回归之前,我先简单介绍一些logistic分布,在此之前,我只当其为一个简单的函数。</p><p><strong>logistic分布</strong><br>定义: 假设$X$为连续随机变量,$X$服从logistic分布,则$X$的分布函数和密度函数分别如下:<br>$$F(x)=P(X \leq x)=\frac{1}{1+e^{-(x-\mu)/\gamma}}$$</p><p>$$f(x)=F’(x)=\frac{e^{-(x-\mu)/\gamma}}{\gamma(1+e^{(x-\mu)/\gamma})}$$<br>其中$\mu$为位置参数,$\gamma>0$为形状参数,$\gamma$值越小,曲线在中心附近增长越快</p><p>对应的密度函数和分布函数的图如下:<br><img src="/images/pasted-0.png" alt="upload successful"></p><p>分布函数又叫logistic函数,由上图可以看到,它是呈现S型,该曲线以点$(\mu,\frac{1}{2})$为中心对称,满足<br>$$F(-x+\mu)-\frac{1}{2}=-F(x+\mu)+\frac{1}{2}$$<br>而标准的logistic函数,即当$\mu=0$,$\gamma=1$时就是我们常用的sigmoid函数,也是常用于神经网络中激活函数<br>且sigmoid函数的有一个非常好的特点,如下👌<br>$$f(x)=\frac{1}{1+e^{(-x)}}$$<br>$$f’(x) = f(x)(1-f(x))$$</p><hr><h4 id="二项逻辑回归-logistic-regression"><a href="#二项逻辑回归-logistic-regression" class="headerlink" title="二项逻辑回归(logistic regression)"></a>二项逻辑回归(logistic regression)</h4><p>逻辑回归是在线性模型的基础上增加了sigmoid函数,而Sigmoid函数引入了非线性因素,使得逻辑回归可以轻松处理0/1分类问题。<br>对于二项逻辑回归模型有如下的条件概率:<br>$$ P(y^{(i)}=1|x^{(i)})= \frac{1}{1+e^{-w^Tx^{(i)}}}=\frac{e^{w^Tx^{(i)}}}{1+e^{w^Tx^{(i)}}}$$<br>$$ P(y^{(i)}=0|x^{(i)})= 1- P(y^{(i)}=1|x^{(i)})=\frac{1}{1+e^{w^Tx^{(i)}}} $$<br>二项逻辑回归用于0/1分类问题是使用的损失函数为对数损失函数,即<br>$$L(y_i,f(x_i))=-log p(y_i|x_i)$$<br>那么最终的代价函数如下:<br>$$L(w,x)=-\frac{1}{N}\sum_{i=1}^N \lbrace y^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})\rbrace<br>$$</p><p>在<a href=""http://mmcwendy.info/2019/02/25/详述机器学习中的损失函数/"">《详述机器学习中的损失函数》</a>有详细举例介绍逻辑回归的推导过程。</p><p>NOTE:<br><strong>二项逻辑回归假设因变量$Y$为伯努力分布,而线性模型假设因变量服从高斯分布</strong></p><hr><h4 id="模型参数估计"><a href="#模型参数估计" class="headerlink" title="模型参数估计"></a>模型参数估计</h4><p><strong>用极大似然估计模型参数👀</strong><br>对于二项逻辑回归模型,假定概率分布服从伯努利分布【0-1分布】,其概率质量函数PMF为:$f(x)=p^x(1-p)^{(1-x)}$,其中$x$只能取0或者1,那么二项逻辑回归的似然函数可以表示:为$$L(w)=\prod_{i=1}^Np(y^{(i)})=1|w,x^{(i)})^{y^{(i)}}p(y^{(i)}=0|w,x^{(i)})^{1-y^{(i)}}$$</p><p>那么对上式取对数,得到对数似然函数为:<br>$$logL(w)=\sum_{i=1}^Ny^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})$$</p><p>则全体样本的代价函数为:<br>$$logL(w)=-\sum_{i=1}^N\lbrace y^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})\rbrace$$</p><p>因此,也可以从因变量$Y$为伯努力分布去理解二项逻辑回归的代价函数。那么对$w$的参数估计就变成了对代价函数求极小值,得到$w$的估计值,<strong>通常采用牛顿法和梯度下降法求解$w$</strong></p><hr><h4 id="多项逻辑回归"><a href="#多项逻辑回归" class="headerlink" title="多项逻辑回归"></a>多项逻辑回归</h4><p>二项逻辑回归用于二分类,当然可以对其进行推广,用于多分类,对应的模型叫做多项逻辑回归模型(multi-nominal logistic regression model)</p><p>假设变量$Y$取值为${1,2,…,K}$,那么多项逻辑回归模型如下:<br>$$P(Y=k|x)=\frac{e^{w^Tx}}{1+\sum_{k=1}^{K-1}e^{w^Tx}},k=1,2,…,K-1$$<br>$$P(Y=K|x)=\frac{1}{1+\sum_{k=1}^{K-1}e^{w^Tx}}$$</p><p>而二项逻辑回归的方法也可以用于多项式逻辑回归</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><hr><p>整理后再写入</p><hr><h3 id="最大熵模型"><a href="#最大熵模型" class="headerlink" title="最大熵模型"></a>最大熵模型</h3><h4 id="最大熵原理"><a href="#最大熵原理" class="headerlink" title="最大熵原理"></a>最大熵原理</h4><p>最大熵模型是概率模型学习的一个准则,学习概率模型时,在所有可能的概率模型(分布)中,熵最大的模型是最好的模型,通常用约束条件来确定概率模型的集合,所以,<strong>最大熵原理可以表述为在满足约束条件的模型集合中选择熵最大的模型</strong></p><p>熵是由信息论男神克劳德·艾尔伍德·香农(Claude Elwood Shannon )在1948年提出的“信息熵“,用来描述信息的不确定程度,<strong>熵越大,不确定程度越大,而系统的混乱程度越低</strong>,熵的单位通常为比特。</p><p>假设离散随机变量$X$的概率分布是 $P(X)$,其熵是<br>$$H(P)=-\sum_xP(x)logP(x)$$</p><p>且熵满足不等式$0\leq H(P)\leq log|X|$,$|X|$是$X$的取值个数,当且仅当$X$为均匀分布时,右边等号成立,即$X$服从均匀分布时,熵最大。当我们需要对一个事件的概率分布进行预测时,最大熵原理告诉我们所有的预测应当满足全部已知的条件,<strong>而对未知的情况不要做任何主观假设</strong>(不做主观假设这点很重要)。也就是让概率分布最均匀,预测的风险最小</p><h4 id="最大熵模型定义"><a href="#最大熵模型定义" class="headerlink" title="最大熵模型定义"></a>最大熵模型定义</h4><p>假设分类模型是一个条件概率分布$P(Y|X)$,$X$表示输入,$Y$表示输出,这个分类模型表示,给定一个输入$X$,以条件概率$P(Y|X)$输出$Y$。<br>给定训练集$T={(x_1,y_1),(x_2,y_2),…,(x_N,y_N)}$<br>对于给定的训练集可以确定联合分布$P(X,Y)$以及边缘分布$P(X)$的经验分布,确定方法都是通过频数(v)/样本总数(N),即</p><p>$$\tilde{P}(X=x,Y=y)=\frac{v(X=x,Y=y)}{N}$$</p><p>$$\tilde{P}(X=x)=\frac{v(X=x)}{N}$$</p><p>特征函数$f(x,y)$表示输入与输出之间的关系<br>$$<br>f(x,y) =<br>\begin{cases}<br>1, & \text{x与y满足某种关系} \\<br>0, & \text{else}<br>\end{cases} $$</p><p>那么特征函数$f(x,y)$关于训练集联合分布的期望值,用$E_\tilde{P}(f)$表示为:</p><p>$$E_\tilde{P}(f)=\sum_{x,y}\tilde{P}(x,y)f(x,y)$$</p><p>而特征函数$f(x,y)$关于模型$P(Y|X)$与经验分布$\tilde{P}(X)$的期望表示为:</p><p>$$E_P(f)=\sum_{x,y}\tilde{P}(x)P(y|x)f(x,y)$$</p><p>如果模型能够获取到训练集中到信息,那么就假设这两个期望值相等,即</p><p>$$\sum_{x,y}\tilde{P}(x,y)f(x,y)=\sum_{x,y}\tilde{P}(x)P(y|x)f(x,y)$$</p><p><strong>最大熵模型</strong></p><p>假设满足所有约束条件的模型集合为</p><p>$$C=\lbrace P\in\rho|E_P(f_i)=E_\tilde{P}(f_i),i=1,2,…,n\rbrace$$</p><p>定义在条件概率分布$P(Y|X)$的条件熵为:<br>$$H(Y|X)=-\sum_{x,y}\tilde{P}(x)P(y|x)logP(y|x)$$<br>则模型$C$中条件熵$H(Y|X)$最大的模型称为最大熵模型</p><p>NOTE<br><strong>⛽️条件熵推导:</strong><br>$$<br>\begin {align}<br>H(Y|X)&= \sum_{x\in X}\tilde{P}(x)H(Y|x) \\<br>& = -\sum_{x\in X}\tilde{P}(x)\sum_{y\in Y}P(y|x)logP(y|x) \\<br>& = -\sum_{x\in X,y\in Y}\tilde{P}(x)P(y|x)logP(y|x)<br>\end{align}<br>$$</p><h4 id="最大熵模型的学习"><a href="#最大熵模型的学习" class="headerlink" title="最大熵模型的学习"></a>最大熵模型的学习</h4><p>给定训练集以及特征函数$T={(x_1,y_1),(x_2,y_2),…,(x_N,y_N)}$以及特征函数$f_i(x,y),i=1,2,…,n$,最大熵模型等价于约束最优化问题<br>$$\begin{equation}<br> \mathop{\arg\max}\quad H(Y|X)=-\sum_{x,y}\tilde{P}(x)P(y|x)logP(y|x) \\<br> \begin{cases}<br> s.t.&\quad E_P(f_i)=E_\tilde{P}(f_i),i=1,2,…,n \\<br> &\quad\sum_{y}P(y|x)=1<br> \end{cases}<br>\end{equation}$$</p><p><strong>求解过程</strong></p><p>1.把最大值问题等价为求最小值问题</p><p>2.引入拉格朗日将有约束的问题转化为无约束的问题$L(P,w)$</p><p>3.基于构造的拉格朗日等式$L(P,w)$对$P(y|x)$求偏导</p><p>4.求出$P(y|x)$再带入$L(P,w)$对拉格朗日乘子$w$求偏导</p><p>打公式太麻烦,为就直接手写放照片来❤️<br>最大熵公式推导过程<br><img src="/images/pasted-2.png" alt="最大熵公式推导过程"><br>最终得到最大熵模型如下:<br>$$P_w(y|x)=\frac{1}{Z_w(x)}exp(\sum_i^nw_if_i(x,y))$$<br>其中<br>$$Z_w(x)=\sum_{y}exp(\sum_i^nw_if_i(x,y))$$</p><h4 id="极大似然估计"><a href="#极大似然估计" class="headerlink" title="极大似然估计"></a>极大似然估计</h4><p>极大似然是参数估计的一种方式,原理是利用已知样本去推导出最大概率出现该样本的参数。</p><hr><p>理解之后再写入</p><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>logistic回归和最大熵模型都是对数线性模型 它们的学习一般采用极大似然估计或者正则化极大似然估计,逻辑回归和最大熵模型学习可以转化为无约束最优化问题,求解该类最优化算法有改进的迭代尺度法、梯度下降法、拟牛顿法(具体最优化方法再单独介绍)。</p>]]></content>
<categories>
<category> learning </category>
</categories>
<tags>
<tag> ML </tag>
<tag> python </tag>
<tag> logistic 回归 </tag>
<tag> 最大熵模型 </tag>
</tags>
</entry>
<entry>
<title>3个linux 系统检测工具</title>
<link href="/2019/02/25/3%E4%B8%AAlinux-%E7%B3%BB%E7%BB%9F%E6%A3%80%E6%B5%8B%E5%B7%A5%E5%85%B7/"/>
<url>/2019/02/25/3%E4%B8%AAlinux-%E7%B3%BB%E7%BB%9F%E6%A3%80%E6%B5%8B%E5%B7%A5%E5%85%B7/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: 3个Linux系统检测工具<br>categories: Linux<br>description: linux,系统监测工具<br>keywords: linux,top,vmstat,w</p><hr><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>使用Linux系统也有很长一段时间,很少想着去监控服务器的性能,想要写这篇博客也是源于想要通过这种方式将这些碎片的知识记录下来,且试用一下其内置的命令和一些附加的工具。</p><p>这些工具提供了获取系统活动的相关指标,可以使用这些工具来查找新能问题的可能原因,接下来提到的是一些基本的命令,用于系统分析和服务器调试等,例如</p><ol><li><p>找出系统瓶颈</p></li><li><p>磁盘(存储)瓶颈</p></li><li><p>CPU和内存瓶颈</p></li><li><p>网络瓶颈</p></li></ol><hr><h4 id="top-进程活动监控命令"><a href="#top-进程活动监控命令" class="headerlink" title="top - 进程活动监控命令"></a>top - 进程活动监控命令</h4><p>top命令会显示Linux的进程,从图中可以看出它提供了一个运行中系统的实时动态图,显示了实际的进程活动,默认情况下,会显示服务器上运行的CPU占用率最高的任务,并且每五秒更新一次(可更改),top的详细命令和参数意思可以<a href="http://blog.csdn.net/sanshiqiduer/article/details/1933625" target="_blank" rel="noopener">参考这篇博客</a> 。</p><h2 id><a href="#" class="headerlink" title></a><img src="http://upload-images.jianshu.io/upload_images/5274272-8459d667cc7d8503.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure-1: linux top 命令"></h2><p><strong>主要说明我自己之前不了解的参数:</strong></p><pre><code>1. up 11:24 是系统运行时间,格式是时:分2. load average:0.07,0.05,0.01 系统负载,即任务队列的平均长度,是那个值分别是前1分钟、5分钟、15分钟到现在的平均值3. zombie 是僵尸进程4. Mem 是物理内存总量,buffers 是用作内存缓存的内存量5. Swap 是交换区的总量,cached是换成的交换区总量6. PR 优先级;NI nice值,负值表示高优先级,正值表示低优先级;VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES;RES j进程使用的、未被换出的物理内存大小,单位kb;SHR 共享内存大小,单位kb;S 进程状态:D=不可中断的睡眠状态、R=运行、S=睡眠、T=跟踪/停止、Z=僵尸进程</code></pre><p><strong>使用方法</strong><br><figure class="highlight scss"><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></pre></td><td class="code"><pre><span class="line"><span class="attribute">top</span> <span class="selector-attr">[-]</span> <span class="selector-attr">[d]</span> <span class="selector-attr">[p]</span> <span class="selector-attr">[q]</span> <span class="selector-attr">[c]</span> <span class="selector-attr">[C]</span> <span class="selector-attr">[S]</span> <span class="selector-attr">[s]</span> <span class="selector-attr">[n]</span></span><br><span class="line"></span><br><span class="line">d 指定屏幕信息刷新之间的时间间隔。当然用户可以使用s交互命令来改变。</span><br><span class="line"><span class="selector-tag">p</span> 通过指定监控进程ID来仅仅监控某个进程的状态。</span><br><span class="line"><span class="selector-tag">q</span> 该选项将使<span class="attribute">top</span>没有任何延迟的进行刷新。如果调用程序有超级用户权限,那么<span class="attribute">top</span>将以尽可能高的优先级运行。</span><br><span class="line">S 指定累计模式</span><br><span class="line">s 使<span class="attribute">top</span>命令在安全模式中运行。这将去除交互命令所带来的潜在危险。</span><br><span class="line"><span class="selector-tag">i</span> 使<span class="attribute">top</span>不显示任何闲置或者僵死进程。</span><br><span class="line">c 显示整个命令行而不只是显示命令名</span><br></pre></td></tr></table></figure></p><p><strong>快捷键</strong><br><figure class="highlight scss"><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></pre></td><td class="code"><pre><span class="line"><span class="attribute">top</span> <span class="selector-attr">[-]</span> <span class="selector-attr">[d]</span> <span class="selector-attr">[p]</span> <span class="selector-attr">[q]</span> <span class="selector-attr">[c]</span> <span class="selector-attr">[C]</span> <span class="selector-attr">[S]</span> <span class="selector-attr">[s]</span> <span class="selector-attr">[n]</span></span><br><span class="line"></span><br><span class="line">t显示汇总信息</span><br><span class="line">m是否显示内存信息</span><br><span class="line"><span class="selector-tag">A</span>根据各种系统资源的利用率对进程进行排序,有助于快速识别系统中性能不加的任务</span><br><span class="line">f进行<span class="attribute">top</span>交互式配置屏幕,根据需求设置<span class="attribute">top</span>的显示,默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、<span class="selector-tag">TIME</span>+、<span class="selector-tag">COMMAND</span> 列</span><br><span class="line">o交互式调地调整<span class="attribute">top</span>每一列的顺序</span><br><span class="line">r调整优先级(renice)</span><br><span class="line">k杀掉进程(kill)</span><br><span class="line">z切换到彩色或者黑白模式</span><br></pre></td></tr></table></figure></p><hr><h4 id="vmstat-虚拟内存统计"><a href="#vmstat-虚拟内存统计" class="headerlink" title="vmstat - 虚拟内存统计"></a>vmstat - 虚拟内存统计</h4><p>vmstat 虚拟内存统计,显示有关进程、内存、分页、块IO、中断和CPU活动等信息。具体信息可以<a href="http://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html" target="_blank" rel="noopener">参考这篇博客</a><br><img src="http://upload-images.jianshu.io/upload_images/5274272-afed3a4942fc74f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure-2: linux vmstat 命令"></p><p>注:一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数,如:<br><figure class="highlight lsl"><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></pre></td><td class="code"><pre><span class="line">vmstat <span class="number">3</span> <span class="number">2</span></span><br><span class="line">## 参数<span class="number">1</span>=<span class="number">3</span> 表示间隔<span class="number">2</span>秒;参数<span class="number">2</span>=<span class="number">2</span>,表示采样<span class="number">2</span>次</span><br><span class="line"></span><br><span class="line">vmstat <span class="number">5</span></span><br><span class="line">## 表示vmstat每<span class="number">2</span>秒采集数据,一直采集,直到我结束程序(如图figure<span class="number">-2</span>)</span><br></pre></td></tr></table></figure></p><p><strong>主要说明我自己之前不了解的参数:</strong></p><pre><code>1. r 表示运行队列(就是说多少个进程真的分配到CPU),当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高。2. b 表示阻塞的进程3. swpd 虚拟内存已使用的大小,如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器。4. free 空闲的物理内存的大小5. buff Linux系统是用来存储,目录里面有权限等的缓存6. cache cache直接用来记忆我们打开的文件,给文件做缓冲,把空闲的物理内存的一部分拿来做文件和目录的缓存,是为了提高程序执行的性能,当程序使用内存时,buffer/cached会很快地被使用。7. si 每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。8. so 每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上。9. bi 块设备每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备。10. bo 块设备每秒发送的块数量,例如我们读取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO过于频繁,需要调整。11.in 每秒CPU的中断次数,包括时间中断12.cs 每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目。13.us 用户CPU时间。14.sy 系统CPU时间,如果太高,表示系统调用时间长,例如是IO操作频繁。15.id 空闲 CPU时间,一般来说,id + us + sy = 100,一般我认为id是空闲CPU使用率,us是用户CPU使用率,sy是系统CPU使用率。16. wt 等待IO CPU时间。</code></pre><hr><p><strong>其他命令</strong><br><figure class="highlight clean"><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></pre></td><td class="code"><pre><span class="line">sudo vmstat -m</span><br><span class="line">##显示slab缓存的利用率</span><br><span class="line"></span><br><span class="line">vmstat -a</span><br><span class="line">## 获取有关活动和非活动内存页面的信息</span><br></pre></td></tr></table></figure></p><hr><h4 id="w-找出登录的用户以及他们在做什么"><a href="#w-找出登录的用户以及他们在做什么" class="headerlink" title="w - 找出登录的用户以及他们在做什么"></a>w - 找出登录的用户以及他们在做什么</h4><p>w 命令显示当前在该系统上的用户及其进程,具体<a href="http://www.linuxso.com/command/w.html" target="_blank" rel="noopener">参考这篇博客</a> </p><figure class="highlight markdown"><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></pre></td><td class="code"><pre><span class="line">语 法:w [<span class="string">-fhlsuV</span>][<span class="symbol">用户名称</span>]</span><br><span class="line"></span><br><span class="line">补充说明:执行这项指令可得知目前登入系统的用户有那些人,以及他们正在执行的程序。单独执行w</span><br><span class="line">指令会显示所有的用户,您也可指定用户名称,仅显示某位用户的相关信息。</span><br><span class="line"></span><br><span class="line">参 数:</span><br><span class="line"> -f 开启或关闭显示用户从何处登入系统。 </span><br><span class="line"> -h 不显示各栏位的标题信息列。 </span><br><span class="line"> -l 使用详细格式列表,此为预设值。 </span><br><span class="line"> -s 使用简洁格式列表,不显示用户登入时间,终端机阶段作业和程序所耗费的CPU时间。 </span><br><span class="line"> -u 忽略执行程序的名称,以及该程序耗费CPU时间的信息。 </span><br><span class="line"> -V 显示版本信息。</span><br></pre></td></tr></table></figure><p><img src="http://upload-images.jianshu.io/upload_images/5274272-a1bc7760fa4a62fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure-3: linux w 命令"></p>]]></content>
<categories>
<category> tool </category>
</categories>
<tags>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>IJCAI 2018 阿里妈妈广告预测算法大赛</title>
<link href="/2019/02/25/IJCAI-2018-%E9%98%BF%E9%87%8C%E5%A6%88%E5%A6%88%E5%B9%BF%E5%91%8A%E9%A2%84%E6%B5%8B%E7%AE%97%E6%B3%95%E5%A4%A7%E8%B5%9B/"/>
<url>/2019/02/25/IJCAI-2018-%E9%98%BF%E9%87%8C%E5%A6%88%E5%A6%88%E5%B9%BF%E5%91%8A%E9%A2%84%E6%B5%8B%E7%AE%97%E6%B3%95%E5%A4%A7%E8%B5%9B/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: IJCAI 2018 阿里妈妈广告预测算法<br>categories: Case<br>description: 利用CNN预测转化率<br>keywords: CNN、购买率、转化率</p><hr><p>IJCAI 2018 阿里妈妈广告预测算法</p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>本项目是天池的一个比赛,由阿里妈妈和天池大数据众智平台举办广告预测算法大赛,本次参赛人数多达5200多,而我们只取得了731的成绩,最遗憾的是当我们写好CNN预测结果准备上传,因为一些意外情况,发现队伍被强制解散,很无奈,又非常不甘心,但是这就是规则,我们只有遵循的权利,难过伤心之后还是需要把整个项目进行整理总结。</p><hr><h3 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h3><p>本次比赛以阿里电商广告为研究对象,提供了淘宝平台的海量真实交易数据,参赛选手通过人工智能技术构建预测模型预估用户的购买意向,即给定广告点击相关的用户(user)、广告商品(ad)、检索词(query)、上下文内容(context)、商店(shop)等信息的条件下预测广告产生购买行为的概率(pCVR),形式化定义为:pCVR=P(conversion=1/query, user, ad, context, shop)。</p><p>结合淘宝平台的业务场景和不同的流量特点,我们定义了以下两类挑战:</p><ul><li>(1)日常的转化率预估</li><li>(2)特殊日期的转化率预估</li></ul><p>评估指标, 公式如下:</p><p>$$L(w,x)=-\frac{1}{N}\sum_{i=1}^N \lbrace y^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})\rbrace<br>$$</p><p>通过logarithmic loss(记为logloss)评估模型效果(越小越好)<br>其中N表示测试集样本数量,yi表示测试集中第i个样本的真实标签,pi表示第i个样本的预估转化率。</p><hr><h3 id="数据说明"><a href="#数据说明" class="headerlink" title="数据说明"></a>数据说明</h3><p>本次比赛为参赛选手提供了5类数据(基础数据、广告商品信息、用户信息、上下文信息和店铺信息)。基础数据表提供了搜索广告最基本的信息,以及“是否交易”的标记。广告商品信息、用户信息、上下文信息和店铺信息等4类数据,提供了对转化率预估可能有帮助的辅助信息。</p><p><strong>1 . 基础数据</strong></p><table><thead><tr><th>字段</th><th style="text-align:left">解释</th></tr></thead><tbody><tr><td>instance_id</td><td style="text-align:left">样本编号,Long</td></tr><tr><td>is_trade</td><td style="text-align:left">是否交易的标记位,Int类型;取值是0或者1,其中1 表示这条样本最终产生交易,0 表示没有交易</td></tr><tr><td>item_id</td><td style="text-align:left">广告商品编号,Long类型</td></tr><tr><td>user_id</td><td style="text-align:left">用户的编号,Long类型</td></tr><tr><td>context_id</td><td style="text-align:left">上下文信息的编号,Long类型</td></tr><tr><td>shop_id</td><td style="text-align:left">店铺的编号,Long类型</td></tr></tbody></table><p><strong>2. 广告商品信息</strong></p><table><thead><tr><th>字段</th><th style="text-align:left">解释</th></tr></thead><tbody><tr><td>item_id</td><td style="text-align:left">广告商品编号,Long类型</td></tr><tr><td>item_category_list</td><td style="text-align:left">广告商品的的类目列表,String类型;从根类目(最粗略的一级类目)向叶子类目(最精细的类目)依次排列,数据拼接格式为 “category_0;category_1;category_2”,其中 category_1 是 category_0 的子类目,category_2 是 category_1 的子类目</td></tr><tr><td>item_property_list</td><td style="text-align:left">广告商品的属性列表,String类型;数据拼接格式为 “property_0;property_1;property_2”,各个属性没有从属关系</td></tr><tr><td>item_brand_id</td><td style="text-align:left">广告商品的品牌编号,Long类型</td></tr><tr><td>item_city_id</td><td style="text-align:left">广告商品的城市编号,Long类型</td></tr><tr><td>item_price_level</td><td style="text-align:left">广告商品的价格等级,Int类型;取值从0开始,数值越大表示价格越高</td></tr><tr><td>item_sales_level</td><td style="text-align:left">广告商品的销量等级,Int类型;取值从0开始,数值越大表示销量越大</td></tr><tr><td>item_collected_level</td><td style="text-align:left">广告商品被收藏次数的等级,Int类型;取值从0开始,数值越大表示被收藏次数越大</td></tr><tr><td>item_pv_level</td><td style="text-align:left">广告商品被展示次数的等级,Int类型;取值从0开始,数值越大表示被展示次数越大</td></tr></tbody></table><p><strong>3. 用户信息</strong></p><table><thead><tr><th>字段</th><th style="text-align:left">解释</th></tr></thead><tbody><tr><td>user_id</td><td style="text-align:left">用户的编号,Long类型</td></tr><tr><td>user_gender_id</td><td style="text-align:left">用户的预测性别编号,Int类型;0表示女性用户,1表示男性用户,2表示家庭用户</td></tr><tr><td>user_age_level</td><td style="text-align:left">用户的预测年龄等级,Int类型;数值越大表示年龄越大</td></tr><tr><td>user_occupation_id</td><td style="text-align:left">用户的预测职业编号,Int类型</td></tr><tr><td>user_star_level</td><td style="text-align:left">用户的星级编号,Int类型;数值越大表示用户的星级越高</td></tr></tbody></table><p><strong>4. 上下文信息</strong></p><table><thead><tr><th>字段</th><th style="text-align:left">解释</th></tr></thead><tbody><tr><td>context_id</td><td style="text-align:left">上下文信息的编号,Long类型</td></tr><tr><td>context_timestamp</td><td style="text-align:left">广告商品的展示时间,Long类型;取值是以秒为单位的Unix时间戳,以1天为单位对时间戳进行了偏移</td></tr><tr><td>context_page_id</td><td style="text-align:left">广告商品的展示页面编号,Int类型;取值从1开始,依次增加;在一次搜索的展示结果中第一屏的编号为1,第二屏的编号为2</td></tr><tr><td>predict_category_property</td><td style="text-align:left">根据查询词预测的类目属性列表,String类型;数据拼接格式为 “category_A:property_A_1,property_A_2,property_A_3;category_B:-1;category_C:property_C_1,property_C_2” ,其中 category_A、category_B、category_C 是预测的三个类目;property_B 取值为-1,表示预测的第二个类目 category_B 没有对应的预测属性</td></tr></tbody></table><p><strong>5. 店铺信息</strong></p><table><thead><tr><th>字段</th><th style="text-align:left">解释</th></tr></thead><tbody><tr><td>shop_id</td><td style="text-align:left">店铺的编号,Long类型</td></tr><tr><td>shop_review_num_level</td><td style="text-align:left">店铺的评价数量等级,Int类型;取值从0开始,数值越大表示评价数量越多</td></tr><tr><td>shop_review_positive_rate</td><td style="text-align:left">店铺的好评率,Double类型;取值在0到1之间,数值越大表示好评率越高</td></tr><tr><td>shop_star_level</td><td style="text-align:left">店铺的星级编号,Int类型;取值从0开始,数值越大表示店铺的星级越高</td></tr><tr><td>shop_score_service</td><td style="text-align:left">店铺的服务态度评分,Double类型;取值在0到1之间,数值越大表示评分越高</td></tr><tr><td>shop_score_delivery</td><td style="text-align:left">店铺的物流服务评分,Double类型;取值在0到1之间,数值越大表示评分越高</td></tr><tr><td>shop_score_description</td><td style="text-align:left">店铺的描述相符评分,Double类型;取值在0到1之间,数值越大表示评分越高</td></tr></tbody></table><hr><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>我们的实验思路如下:</p><p><strong>统计分析 -> 数据预处理 -> 特征抽取 -> 特征表示 -> 模型拟合和预测 -> 模型选择</strong></p><p>其实从实验思路我们可以明显看出特征工程在这次比赛尤为重要,只有刻画好特征,才能利用模型得到好的预测结果,接下来我将按照实验思路进行总结。</p><hr><h3 id="实验"><a href="#实验" class="headerlink" title="实验"></a>实验</h3><h4 id="1-统计分析"><a href="#1-统计分析" class="headerlink" title="1. 统计分析"></a>1. 统计分析</h4><p><strong>目的: 看清数据分布,了解广告、商品、店铺、用户与购买概率的关系</strong></p><p>基础数据的统计分析(饼图、柱状图和折线图结合) ,将数据按照is_trade属性分为两张子表,分别进行对比统计分析</p><ul><li><p>购买的用户分析:<br>单变量:性别分布、年龄分布、职业分布、星级分布<br>交叉变量:(重点)性别-年龄、性别-星级、年龄-星级、职业-星级,(参考)年龄-职业,性别-职业</p></li><li><p>购买的商品分布对比<br>(重点)标签分布、属性分布、品牌分布、价格分布、销量分布,展示次数(后四项需考虑粒度的粗细)<br>(参考)城市分布、收藏次数分布</p></li><li><p>上下文信息对比<br>(重点)时间戳分布<br>(参考)页面分布(看能否精确到类别)、预测类目的准确度(?)</p></li><li><p>购买的店铺分布对比<br>(重点)评论数分布,好评率分布、星级分布<br>(参考)服务评分、物流评分、描述评分</p></li></ul><p><strong>实施:利用R对数据分布进行了统计,代码在analysis目录下,图片在pic和pic2中</strong></p><p><strong>结果如下</strong></p><p>以在不同属性上is_trade=0/1为例, 简要分析</p><hr><ul><li>1.转化分布</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-126f6ced03f87190.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>从上图可以明显看出在给定情景下转化率很低,也就是说,<strong>我们的训练数据存在了极度平衡的现象,甚至是可以把购买理解成异常值,我们的算法要能够极好的检测出异常实例。</strong></p><hr><ul><li>2.年龄,性别,星级 分布</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-c467e22c64b0c0bd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-0c0a9b67b23c8ac2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>从图1可以明显看出,<strong>年龄越大,转化率先增加后减少</strong>(-1表示未知年龄),这个结果与我们常识一致,中间年龄段更具有消费能力, 性别转化分布没有贴出来,结果跟我们常识也是一致的,<strong>女性转化率高于男性</strong>。从图2中可以看出,星级越高购买率相对要更高一些,但是差距不太明显。</p><hr><ul><li>3.价格,收藏,展示 分布</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-ebd131b8e02cced0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-791b0f021b095122.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-629f4f0cf77c4452.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>图1,可以看出<strong>价格越高转化率先增加后降低,这与我们对电商平台的认知有关</strong>,价格太低必然会让人觉得物品质量不佳,但是随着价格增加,购买会带来更高的风险,转化率自然会降低。图2收藏次数越高,购买的可能性越大,<strong>收藏在电商市场的本质,就是商品入选了用户的购买集</strong>,对相关商品综合排序后,收藏的商品更有可能转化。图3,总体趋势是<strong>展示次数(广告效应)越多,购买率越高</strong>。</p><hr><ul><li>4.商店星级,评论数量 分布</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-6f3c32f540d9a5ee.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-5f1784960206943b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>图1.商店星级差异不明显。图2.<strong>评论数量居中的购买率更高</strong></p><ul><li>5 城市 | 商品标签 分布</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-c36d38d7eb21b420.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt><br><img src="https://upload-images.jianshu.io/upload_images/5274272-2ea9155e96d8d9fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>这两幅图是仅仅选择了高频的城市和商标分布,<strong>可以看出城市和商品图,都有集中表现类,而商品更为明显</strong>。</p><hr><p><strong>总结: 数据统计分析的目的是分析变量之间的关系,观察具体特征对转化率的影响,从而用于模型中初始化权重</strong></p><hr><h4 id="2-数据预处理"><a href="#2-数据预处理" class="headerlink" title="2. 数据预处理"></a>2. 数据预处理</h4><ol><li><p>处理缺失值<br>主要处理缺失值,以及属性值为-1的值,因为后期特征表示时,我们调用的sklearn借口进行one-hot表征,而借口要求输入数据不包括负数</p></li><li><p>特征映射<br>由于城市和商品的值字段太长,在表征时会出现错误,因此将他们分别映射,并更新原始数据,代码如下:</p></li></ol><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">def map_field(train_data, test_data, path):</span><br><span class="line"> train_data = <span class="keyword">set</span>(train_data.unique())</span><br><span class="line"> test_data = <span class="keyword">set</span>(test_data.unique())</span><br><span class="line"> all_property = <span class="keyword">list</span>(train_data.union(test_data))</span><br><span class="line"> print(<span class="keyword">len</span>(all_property))</span><br><span class="line"> map_data = {}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="keyword">range</span>(<span class="keyword">len</span>(all_property)):</span><br><span class="line"> map_data[<span class="keyword">str</span>(all_property[i])] = i</span><br><span class="line"> <span class="keyword">with</span> <span class="keyword">open</span>(<span class="keyword">path</span>, <span class="string">"w"</span>, <span class="keyword">encoding</span>=<span class="string">"utf-8"</span>) <span class="keyword">as</span> dump:</span><br><span class="line"> json.dump(map_data, dump)</span><br><span class="line"> <span class="keyword">return</span> map_data</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> update_data(raw_data, field_1, field_2, path_1, path_2):</span><br><span class="line"> <span class="keyword">with</span> <span class="keyword">open</span>(path_1, <span class="string">"r"</span>, <span class="keyword">encoding</span>=<span class="string">"utf-8"</span>) <span class="keyword">as</span> dump:</span><br><span class="line"> update_field_1 = json.load(dump)</span><br><span class="line"> <span class="keyword">with</span> <span class="keyword">open</span>(path_2, <span class="string">"r"</span>, <span class="keyword">encoding</span>=<span class="string">"utf-8"</span>) <span class="keyword">as</span> dump:</span><br><span class="line"> update_field_2 = json.load(dump)</span><br><span class="line"> raw_data[field_1] = raw_data[field_1].apply(lambda x: update_field_1[<span class="keyword">str</span>(x)])</span><br><span class="line"> raw_data[field_2] = raw_data[field_2].apply(lambda x: update_field_2[<span class="keyword">str</span>(x)])</span><br><span class="line"> <span class="keyword">return</span> raw_data</span><br></pre></td></tr></table></figure><h4 id="3-特征抽取"><a href="#3-特征抽取" class="headerlink" title="3. 特征抽取"></a>3. 特征抽取</h4><p>本小节主要涉及对特征的转化和抽取,比如在上下文中的时间轴数据,<strong>考虑到节假日流量问题(比赛提出的挑战解决方法)</strong>,我节假日和周末前后时间戳进行映射, 代码见下:</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><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">convert_interval_time</span><span class="params">(hour, size=<span class="number">3</span>)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 方法:把一天24小时按照力粒度为size大小进行分割</span></span><br><span class="line"><span class="string"> :param hour:</span></span><br><span class="line"><span class="string"> :param size:</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> interval_time = [list(range(i, i + size)) <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">0</span>, <span class="number">24</span>, size)]</span><br><span class="line"> interval_time_factor = {}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(interval_time)):</span><br><span class="line"> interval_time_factor[i] = interval_time[i]</span><br><span class="line"> <span class="keyword">for</span> factor, h <span class="keyword">in</span> interval_time_factor.items():</span><br><span class="line"> <span class="keyword">if</span> hour <span class="keyword">in</span> h:</span><br><span class="line"> <span class="keyword">return</span> factor</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">time_to_factor</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 方法:将时间戳转为区间因子</span></span><br><span class="line"><span class="string"> tips: add two features, is_weekend and is_holiday</span></span><br><span class="line"><span class="string"> :param data: 输入带时间戳的数据,</span></span><br><span class="line"><span class="string"> :param size:将原始时间戳转化为粒度为size个小时一个因子,默认为size=3</span></span><br><span class="line"><span class="string"> :return: 对于时间戳转为化为区间因子</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> data_time = self.raw_data[self.modify_features[<span class="string">"time"</span>]]</span><br><span class="line"> data_time[<span class="string">"format_time"</span>] = data_time[<span class="string">"context_timestamp"</span>].apply(<span class="keyword">lambda</span> x: time.localtime(x))</span><br><span class="line"> convert_data_time = pd.DataFrame(columns=[<span class="string">"interval_time"</span>, <span class="string">"is_weekends"</span>, <span class="string">"is_holidays"</span>])</span><br><span class="line"> convert_data_time[<span class="string">"is_weekends"</span>] = \</span><br><span class="line"> data_time[<span class="string">"format_time"</span>].apply(<span class="keyword">lambda</span> x: <span class="number">1</span> <span class="keyword">if</span> x[<span class="number">6</span>] <span class="keyword">in</span> self.weekends <span class="keyword">else</span> <span class="number">0</span>)</span><br><span class="line"> convert_data_time[<span class="string">"is_holidays"</span>] = \</span><br><span class="line"> data_time[<span class="string">"format_time"</span>].apply(<span class="keyword">lambda</span> x: <span class="number">1</span> <span class="keyword">if</span> str(x[<span class="number">1</span>]) + <span class="string">"."</span> + str(x[<span class="number">2</span>]) <span class="keyword">in</span> self.holidays <span class="keyword">else</span> <span class="number">0</span>)</span><br><span class="line"> convert_data_time[<span class="string">"interval_time"</span>] = \</span><br><span class="line"> data_time[<span class="string">"format_time"</span>].apply(<span class="keyword">lambda</span> x: self.convert_interval_time(hour=x[<span class="number">3</span>]))</span><br><span class="line"> <span class="keyword">return</span> convert_data_time</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">continuous_var_to_factor</span><span class="params">(self, size=<span class="number">0.01</span>)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 方法:将连续数据按照粒度为size进行转化</span></span><br><span class="line"><span class="string"> :param data_continuous: 输入带有连续变量的数据</span></span><br><span class="line"><span class="string"> :param properity: 指定属性</span></span><br><span class="line"><span class="string"> :param size: 粒度默认为0.01</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> data_continuous = self.raw_data[self.modify_features[<span class="string">'continuous'</span>]]</span><br><span class="line"> data_continuous = (data_continuous / size).round()</span><br><span class="line"> data_continuous = data_continuous.astype(<span class="string">'int64'</span>)</span><br><span class="line"> <span class="keyword">return</span> data_continuous</span><br></pre></td></tr></table></figure><h4 id="4-特征表示"><a href="#4-特征表示" class="headerlink" title="4. 特征表示"></a>4. 特征表示</h4><p>在这一部分,我们主要是是通过One-hot对所有数据特征进行表征,然后用One-hot的最大问题,尤其是在电商环境下特征表征,我们可以想象,这个数据维度非常巨大,所以,在处理这个高维数据时,我们先将其分为五个大的领域进行表征,再对其使用SVD进行降维处理。<br>One-hot表征代码如下:</p><figure class="highlight vim"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">def one_hot_represent(self, new_data, data_type=<span class="string">'value'</span>):</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> :param new_dat<span class="variable">a:</span> pd.DataFrame. The data used <span class="keyword">to</span> transform <span class="keyword">to</span> the one-hot form.</span><br><span class="line"> :param data_type: str, default <span class="string">'value'</span>, alternative <span class="string">'lst'</span>. Aimed at different forms, we can use this parameter <span class="keyword">to</span></span><br><span class="line"> specify the method of handling.</span><br><span class="line"> :<span class="keyword">return</span>:</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> <span class="keyword">if</span> data_type == <span class="string">'value'</span>:</span><br><span class="line"> df_one_hot = pd.DataFrame()</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">col</span> in new_data.column<span class="variable">s:</span></span><br><span class="line"> # <span class="keyword">print</span>(<span class="keyword">col</span>)</span><br><span class="line"> one_hot_matrix = self.one_hot_model.fit_transform(new_data[[<span class="keyword">col</span>]])</span><br><span class="line"> feature_names = [<span class="keyword">col</span> + str(attr) <span class="keyword">for</span> attr in self.one_hot_model.active_features_]</span><br><span class="line"> one_hot_matrix = pd.DataFrame(one_hot_matrix.toarray(), columns=feature_names)</span><br><span class="line"> df_one_hot = pd.concat([df_one_hot, one_hot_matrix], axis=<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> df_one_hot</span><br><span class="line"> # <span class="keyword">return</span> pd.DataFrame(df_one_hot.toarray(), columns=feature_names)</span><br><span class="line"> elif data_type == <span class="string">'lst'</span>:</span><br><span class="line"> cols = new_data.columns</span><br><span class="line"> df_one_hot = pd.DataFrame()</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">col</span> in <span class="keyword">col</span><span class="variable">s:</span></span><br><span class="line"> # <span class="keyword">print</span>(<span class="keyword">col</span>)</span><br><span class="line"> data = new_data[<span class="keyword">col</span>]</span><br><span class="line"> all_values = <span class="keyword">list</span>(reduce(lambda <span class="keyword">x</span>, <span class="keyword">y</span>: <span class="keyword">x</span> | <span class="keyword">y</span>, data, <span class="keyword">set</span>()))</span><br><span class="line"> one_hot_dim = <span class="built_in">len</span>(all_values)</span><br><span class="line"> one_hot_matrix = []</span><br><span class="line"> <span class="keyword">for</span> <span class="built_in">line</span> in dat<span class="variable">a:</span></span><br><span class="line"> one_hot_vec = np.zeros(one_hot_dim)</span><br><span class="line"> <span class="keyword">for</span> value in <span class="built_in">line</span>:</span><br><span class="line"> one_hot_vec[all_values.<span class="built_in">index</span>(value)] = <span class="number">1</span></span><br><span class="line"> one_hot_matrix.<span class="keyword">append</span>(one_hot_vec)</span><br><span class="line"> one_hot_matrix = pd.DataFrame(one_hot_matrix, columns=all_values)</span><br><span class="line"> df_one_hot = pd.concat([df_one_hot, one_hot_matrix], axis=<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> df_one_hot</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> raise ValueError(<span class="string">'Can\'</span>t recognize the <span class="built_in">type</span>, please enter \<span class="string">'value\'</span> <span class="built_in">or</span> \<span class="string">'lst\'</span><span class="string">')</span></span><br></pre></td></tr></table></figure><p>SVD降维代码如下:</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><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SVDReduce</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> The class is used to reduce the dimension of the data outputed from the class DataPreprocess with SVD method.</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, data, dimension=<span class="number">500</span>)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Initialize the class with the parameters.</span></span><br><span class="line"><span class="string"> :param data: pd.DataFrame, the output data from the class DataPreprocess.</span></span><br><span class="line"><span class="string"> :param dimension: int, default 500. To specify the output dimension.</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> self.data = data</span><br><span class="line"> self.target_dim = dimension</span><br><span class="line"> self.format_data_path = <span class="string">'../../data/format_2/'</span></span><br><span class="line"> self.field = [<span class="string">'user'</span>, <span class="string">'product'</span>, <span class="string">'context'</span>, <span class="string">'shop'</span>]</span><br><span class="line"> <span class="comment"># self.field = ['product']</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">judge</span><span class="params">(self, data)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Abandon</span></span><br><span class="line"><span class="string"> 方法:判读大领域的维度</span></span><br><span class="line"><span class="string"> 标准维度,判断:不足补零,大于转为svd()</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> logger.info(<span class="string">"judge the dimension..."</span>)</span><br><span class="line"> field_matrix_shape = data.shape</span><br><span class="line"> dimension = field_matrix_shape[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> dimension > self.target_dim:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">svd</span><span class="params">(self, field_matrix)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 方法:对大的领域数据进行降维</span></span><br><span class="line"><span class="string"> :param field_matrix: list(2d) or np.array, 每一行(list)表示一条record</span></span><br><span class="line"><span class="string"> :return: 返回领域的降维矩阵</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> logger.info(<span class="string">"use svd to reduce the dimension"</span>)</span><br><span class="line"> indices = field_matrix.index</span><br><span class="line"> fm = field_matrix</span><br><span class="line"> field_matrix = np.array(field_matrix)</span><br><span class="line"> field_matrix_dim = field_matrix.shape</span><br><span class="line"> print(field_matrix_dim)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 对维度进行判断是否需要降维</span></span><br><span class="line"> <span class="keyword">if</span> field_matrix_dim[<span class="number">1</span>] <= self.target_dim:</span><br><span class="line"> logger.info(<span class="string">'Filed_matrix_dim if smaller than the target, no need to perform reduction, thus we'</span></span><br><span class="line"> <span class="string">'only add extra zero element to make up the dimension.'</span>)</span><br><span class="line"> dim_make_up = self.target_dim - field_matrix_dim[<span class="number">1</span>]</span><br><span class="line"> matrix_make_up = np.zeros([field_matrix_dim[<span class="number">0</span>], dim_make_up])</span><br><span class="line"> matrix_make_up = pd.DataFrame(matrix_make_up, index=indices)</span><br><span class="line"> <span class="keyword">return</span> pd.concat([fm, matrix_make_up], axis=<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> svd = TruncatedSVD(n_components=self.target_dim)</span><br><span class="line"> <span class="keyword">return</span> pd.DataFrame(svd.fit_transform(field_matrix), index=indices)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 1. Extract the one-hot-form data from the self.new_data_one_hot according to the field-instruction.</span></span><br><span class="line"><span class="string"> 2. Based on the given self.target_dimension, judge the field matrix whether satisfy the dimension requirement.</span></span><br><span class="line"><span class="string"> 3. If so, do the svd method, else add extra zero element to achieve the self.target_dimension.</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> output_matrix = []</span><br><span class="line"> <span class="keyword">for</span> i, field_data <span class="keyword">in</span> enumerate(self.data):</span><br><span class="line"> <span class="comment"># field_data = self.split_field(field=item)</span></span><br><span class="line"> svd_matrix = self.svd(field_matrix=field_data)</span><br><span class="line"> svd_matrix.to_csv(self.format_data_path + <span class="string">'svd_'</span> + self.field[i] + <span class="string">'.csv'</span>)</span><br><span class="line"> output_matrix.append(svd_matrix)</span><br><span class="line"> <span class="keyword">return</span> output_matrix</span><br></pre></td></tr></table></figure><p>除了通过分领域和SVD降维以外,商品的属性上高达10多万类,所以我们还对<strong>商品属性计算了信息增益</strong>从而筛选了部分重要的商品属性。</p><figure class="highlight vim"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">def feature_selection_with_info_gain(self, data, num_feature=<span class="number">500</span>, feature=<span class="string">'item_property_list'</span>):</span><br><span class="line"> <span class="keyword">print</span>(os.path.<span class="built_in">exists</span>(<span class="string">'../../data/format_2/infomation_gain.txt'</span>))</span><br><span class="line"> <span class="keyword">if</span> os.path.<span class="built_in">exists</span>(<span class="string">'../../data/format_2/infomation_gain.txt'</span>):</span><br><span class="line"> with <span class="keyword">open</span>(<span class="string">'../../data/format_2/infomation_gain.txt'</span>, <span class="string">'r'</span>, encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> r:</span><br><span class="line"> selected_feature = []</span><br><span class="line"> <span class="keyword">for</span> i in <span class="built_in">range</span>(num_feature):</span><br><span class="line"> <span class="built_in">line</span> = r.readline().replace(<span class="string">'\ufeff'</span>, <span class="string">''</span>).strip().<span class="keyword">split</span>(<span class="string">','</span>)</span><br><span class="line"> selected_feature.<span class="keyword">append</span>(<span class="built_in">line</span>[<span class="number">0</span>])</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> fea_s = <span class="keyword">list</span>(data.columns)</span><br><span class="line"> fea_s.<span class="built_in">remove</span>(feature)</span><br><span class="line"></span><br><span class="line"> property = []</span><br><span class="line"> <span class="keyword">for</span> lst in data[feature]:</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">pro</span> in <span class="keyword">ls</span><span class="variable">t:</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">pro</span> not in property:</span><br><span class="line"> property.<span class="keyword">append</span>(<span class="keyword">pro</span>)</span><br><span class="line"></span><br><span class="line"> info_gain = pd.Series()</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">pro</span> in property:</span><br><span class="line"> series = pd.Series([<span class="number">1</span> <span class="keyword">if</span> <span class="keyword">pro</span> in lst <span class="keyword">else</span> <span class="number">0</span> <span class="keyword">for</span> lst in data[feature]], <span class="built_in">index</span>=data.<span class="built_in">index</span>, name=<span class="keyword">pro</span>)</span><br><span class="line"> concat_data = pd.concat([series, self.raw_data[<span class="string">'is_trade'</span>]], axis=<span class="number">1</span>)</span><br><span class="line"> info_gain[<span class="keyword">pro</span>] = self.cal_info_gain(data=concat_data, independent_variable=<span class="keyword">pro</span>,</span><br><span class="line"> dependent_variable=<span class="string">'is_trade'</span>)</span><br><span class="line"></span><br><span class="line"> info_gain = info_gain.sort_values(ascending=False)</span><br><span class="line"> info_gain.to_csv(<span class="string">'../../data/format_2/infomation_gain.txt'</span>, encoding=<span class="string">'utf-8'</span>)</span><br><span class="line"> selected_feature = <span class="keyword">list</span>(info_gain.<span class="built_in">index</span>[: num_feature])</span><br><span class="line"></span><br><span class="line"> new_feature = []</span><br><span class="line"> <span class="keyword">for</span> lst in data[feature]:</span><br><span class="line"> new_fea = []</span><br><span class="line"> <span class="keyword">for</span> <span class="keyword">pro</span> in <span class="keyword">ls</span><span class="variable">t:</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">pro</span> in selected_feature:</span><br><span class="line"> new_fea.<span class="keyword">append</span>(<span class="keyword">pro</span>)</span><br><span class="line"> new_feature.<span class="keyword">append</span>(<span class="keyword">set</span>(new_fea))</span><br><span class="line"> data[feature] = new_feature</span><br><span class="line"> <span class="keyword">return</span> data</span><br></pre></td></tr></table></figure><hr><p><strong>总结:这几小节主要是对特征的映射、筛选、表征,遇到的最大困难就是数据维度太高以致于服务器多次出现memory error,所以我们对原始表征数据时按照它给定的基础数据、广告商品信息、用户信息、上下文信息和店铺信息5大块分别onehot,并通过信息增益和SVD进行降维处理,所有代码均在data_helper.py中</strong></p><hr><h4 id="5-模型拟合和预测"><a href="#5-模型拟合和预测" class="headerlink" title="5.模型拟合和预测"></a>5.模型拟合和预测</h4><p>在模型过程中,我们考虑了很多个模型,首先是在广告预测领域用得最多且效果还可以的逻辑回归、Field-aware Factorization Machines、卷积神经网络,以及非常常用的分类方法:随机森林、提升数、简单的感知器等等,最终表现效果最好的是卷积神经网络。</p><p><strong>实验框架如下:</strong></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-90201af539935504.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>一定是我写累了,因为喜欢花花绿绿,图上颜色就觉得特别开心幸福,O(∩_∩)O哈哈哈~</p><p><strong>实验过程:</strong></p><p>我们首先将原始训练数据和测试集,将比赛提供的loss评估指标作为我们的损失函数,通过卷积神经网络进行训练,事实上因为CNN就自带降维效果,所以,输入CNN的数据是没有用SVD进行降维的。</p><p>NN方法代码如下:</p><figure class="highlight rust"><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><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">class CNN1(object):</span><br><span class="line"></span><br><span class="line"> def __init__(<span class="keyword">self</span>, n_input, n_output, x_shape, batch_size, load=<span class="number">0</span>):</span><br><span class="line"> <span class="keyword">if</span> load == <span class="number">1</span>:</span><br><span class="line"> saver = tf.train.import_meta_graph(<span class="string">"../../data/model/cnn_model.ckpt.meta"</span>)</span><br><span class="line"> <span class="keyword">self</span>.sess = tf.Session()</span><br><span class="line"> saver.restore(<span class="keyword">self</span>.sess, <span class="string">"../../data/model/cnn_model.ckpt"</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> logger.info(<span class="symbol">'building</span> the graph...')</span><br><span class="line"></span><br><span class="line"> <span class="keyword">self</span>.kb = <span class="number">0.8</span></span><br><span class="line"> <span class="keyword">self</span>.batch_size = batch_size</span><br><span class="line"></span><br><span class="line"> <span class="keyword">self</span>.x = tf.placeholder(tf.float32, [<span class="literal">None</span>, n_input], name=<span class="symbol">'input</span>')</span><br><span class="line"> <span class="keyword">self</span>.y = tf.placeholder(tf.float32, [<span class="literal">None</span>, n_output], name=<span class="symbol">'true_label</span>')</span><br><span class="line"> <span class="keyword">self</span>.x_ = tf.reshape(<span class="keyword">self</span>.x, shape=x_shape)</span><br><span class="line"></span><br><span class="line"> # define the first convolution layer</span><br><span class="line"> <span class="keyword">self</span>.W_conv1 = <span class="keyword">self</span>.weight_variable([<span class="number">2</span>, <span class="number">2</span>, <span class="number">1</span>, <span class="number">16</span>])</span><br><span class="line"> <span class="keyword">self</span>.b_conv1 = <span class="keyword">self</span>.bias_variable([<span class="number">16</span>])</span><br><span class="line"> <span class="keyword">self</span>.h_conv1 = tf.nn.relu(<span class="keyword">self</span>.conv2d(<span class="keyword">self</span>.x_, <span class="keyword">self</span>.W_conv1) + <span class="keyword">self</span>.b_conv1)</span><br><span class="line"> <span class="keyword">self</span>.h_pool1 = <span class="keyword">self</span>.max_pool_2x2(<span class="keyword">self</span>.h_conv1)</span><br><span class="line"></span><br><span class="line"> # define the second convolution layer</span><br><span class="line"> <span class="keyword">self</span>.W_conv2 = <span class="keyword">self</span>.weight_variable([<span class="number">2</span>, <span class="number">2</span>, <span class="number">16</span>, <span class="number">32</span>])</span><br><span class="line"> <span class="keyword">self</span>.b_conv2 = <span class="keyword">self</span>.bias_variable([<span class="number">32</span>])</span><br><span class="line"> <span class="keyword">self</span>.h_conv2 = tf.nn.relu(<span class="keyword">self</span>.conv2d(<span class="keyword">self</span>.h_pool1, <span class="keyword">self</span>.W_conv2) + <span class="keyword">self</span>.b_conv2)</span><br><span class="line"> <span class="keyword">self</span>.h_pool2 = <span class="keyword">self</span>.max_pool_2x2(<span class="keyword">self</span>.h_conv2)</span><br><span class="line"></span><br><span class="line"> # transform the result of h_pool2 into <span class="number">1</span>D-form</span><br><span class="line"> <span class="keyword">self</span>.h_pool2_ = tf.reshape(<span class="keyword">self</span>.h_pool2, [-<span class="number">1</span>, (x_shape[<span class="number">1</span>] <span class="comment">// 4) * (x_shape[2] // 4) *32])</span></span><br><span class="line"> h_pool2_shape = <span class="keyword">self</span>.h_pool2_.get_shape()</span><br><span class="line"> <span class="keyword">self</span>.W_fc1 = <span class="keyword">self</span>.weight_variable([h_pool2_shape[<span class="number">1</span>].value, <span class="number">500</span>])</span><br><span class="line"> <span class="keyword">self</span>.b_fc1 = <span class="keyword">self</span>.bias_variable([<span class="number">500</span>])</span><br><span class="line"> <span class="keyword">self</span>.h_fc1 = tf.nn.relu(tf.matmul(<span class="keyword">self</span>.h_pool2_, <span class="keyword">self</span>.W_fc1) + <span class="keyword">self</span>.b_fc1)</span><br><span class="line"></span><br><span class="line"> # add a dropout layer</span><br><span class="line"> <span class="keyword">self</span>.keep_prob = tf.placeholder(tf.float32, name=<span class="symbol">'keep</span>')</span><br><span class="line"> <span class="keyword">self</span>.h_fc1_drop = tf.nn.dropout(<span class="keyword">self</span>.h_fc1, <span class="keyword">self</span>.keep_prob)</span><br><span class="line"></span><br><span class="line"> # add a softmax layer, and get the final probability</span><br><span class="line"> <span class="keyword">self</span>.W_fc2 = <span class="keyword">self</span>.weight_variable([<span class="number">500</span>, n_output])</span><br><span class="line"> <span class="keyword">self</span>.b_fc2 = <span class="keyword">self</span>.bias_variable([n_output])</span><br><span class="line"> <span class="keyword">self</span>.pred = tf.nn.softmax(tf.matmul(<span class="keyword">self</span>.h_fc1_drop, <span class="keyword">self</span>.W_fc2) + <span class="keyword">self</span>.b_fc2, name=<span class="symbol">'pred</span>')</span><br><span class="line"></span><br><span class="line"> # <span class="keyword">self</span>.loss_func = tf.reduce_mean(- <span class="keyword">self</span>.y * tf.log(<span class="keyword">self</span>.pred), name=<span class="symbol">'loss_func</span>')</span><br><span class="line"> <span class="keyword">self</span>.loss_func = tf.reduce_mean(- <span class="keyword">self</span>.y * tf.log(<span class="keyword">self</span>.pred), name=<span class="symbol">'loss_func</span>') + \</span><br><span class="line"> <span class="number">0.001</span> * tf.nn.l2_loss(<span class="keyword">self</span>.W_conv1) + \</span><br><span class="line"> <span class="number">0.001</span> * tf.nn.l2_loss(<span class="keyword">self</span>.W_conv2) + \</span><br><span class="line"> <span class="number">0.001</span> * tf.nn.l2_loss(<span class="keyword">self</span>.W_fc1) + \</span><br><span class="line"> <span class="number">0.001</span> * tf.nn.l2_loss(<span class="keyword">self</span>.W_fc2)</span><br><span class="line"> <span class="keyword">self</span>.optm = tf.train.AdadeltaOptimizer(<span class="number">0.005</span>).minimize(<span class="keyword">self</span>.loss_func)</span><br><span class="line"> <span class="keyword">self</span>.init_op = tf.global_variables_initializer()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">self</span>.sess = tf.Session()</span><br><span class="line"> <span class="keyword">self</span>.sess.run(<span class="keyword">self</span>.init_op)</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def weight_variable(shape):</span><br><span class="line"> <span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> the method used to define the weight variables of the convolution layers</span></span><br><span class="line"><span class="string"> :param shape:tuple or list, 该权重的形状</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> initial = tf.truncated_normal(shape, stddev=<span class="number">0.1</span>)</span><br><span class="line"> <span class="keyword">return</span> tf.Variable(initial)</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def bias_variable(shape):</span><br><span class="line"> <span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> the method used to define the weight variables of the bias of each convolution layer</span></span><br><span class="line"><span class="string"> :param shape:</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> initial = tf.constant(<span class="number">0.1</span>, shape=shape)</span><br><span class="line"> <span class="keyword">return</span> tf.Variable(initial)</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def conv2d(x, W):</span><br><span class="line"> <span class="keyword">return</span> tf.nn.conv2d(x, W, strides=[<span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>], padding=<span class="symbol">'SAME</span>')</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def max_pool_2x2(x):</span><br><span class="line"> <span class="keyword">return</span> tf.nn.max_pool(x, ksize=[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">1</span>], strides=[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">1</span>], padding=<span class="symbol">'SAME</span>')</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def get_batch_data(batch_size, train_data, label_data):</span><br><span class="line"> total = len(train_data)</span><br><span class="line"> <span class="keyword">if</span> batch_size > <span class="number">1</span>:</span><br><span class="line"> chose_samples = random.sample(range(total), batch_size)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> chose_samples = random.randint(<span class="number">0</span>, total)</span><br><span class="line"> <span class="keyword">return</span> train_data[chose_samples], label_data[chose_samples]</span><br><span class="line"></span><br><span class="line"> def train(<span class="keyword">self</span>, train_data, label_data, epoches):</span><br><span class="line"> train_data = np.array(train_data)</span><br><span class="line"> label_data = np.array(label_data)</span><br><span class="line"> # <span class="keyword">for</span> i <span class="keyword">in</span> range(epoches):</span><br><span class="line"> # logger.info(<span class="symbol">'running</span> the {}-th round of training process...'.format(i))</span><br><span class="line"> # attr_data, labe_data = <span class="keyword">self</span>.get_batch_data(<span class="keyword">self</span>.batch_size, train_data, label_data)</span><br><span class="line"> # _, loss = <span class="keyword">self</span>.sess.run([<span class="keyword">self</span>.optm, <span class="keyword">self</span>.loss_func],</span><br><span class="line"> # feed_dict={<span class="keyword">self</span>.x: attr_data, <span class="keyword">self</span>.y:labe_data, <span class="keyword">self</span>.keep_prob: <span class="keyword">self</span>.kb})</span><br><span class="line"> # <span class="keyword">if</span> i + <span class="number">1</span> == epoches:</span><br><span class="line"> # logger.info(<span class="symbol">'finish</span> training process and the loss is {}'.format(loss))</span><br><span class="line"> # elif (i + <span class="number">10</span>) % <span class="number">10</span> == <span class="number">0</span>:</span><br><span class="line"> # logger.info(<span class="symbol">'running</span> the {}-th epoch and the loss is {}.'.format(i, loss))</span><br><span class="line"> with tf.device(<span class="string">"/gpu:0"</span>):</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(epoches):</span><br><span class="line"> logger.info(<span class="symbol">'running</span> the {}-th round of training process...'.format(i))</span><br><span class="line"> attr_data, labe_data = <span class="keyword">self</span>.get_batch_data(<span class="keyword">self</span>.batch_size, train_data, label_data)</span><br><span class="line"> _, loss = <span class="keyword">self</span>.sess.run([<span class="keyword">self</span>.optm, <span class="keyword">self</span>.loss_func],</span><br><span class="line"> feed_dict={<span class="keyword">self</span>.x: attr_data, <span class="keyword">self</span>.y:labe_data, <span class="keyword">self</span>.keep_prob: <span class="keyword">self</span>.kb})</span><br><span class="line"> <span class="keyword">if</span> i + <span class="number">1</span> == epoches:</span><br><span class="line"> logger.info(<span class="symbol">'finish</span> training process and the loss is '.format(loss))</span><br><span class="line"> elif (i + <span class="number">100</span>) % <span class="number">100</span> == <span class="number">0</span>:</span><br><span class="line"> logger.info(<span class="symbol">'running</span> the {}-th epoch and the loss is {}.'.format(i, loss))</span><br><span class="line"></span><br><span class="line"> def predict(<span class="keyword">self</span>, test_data, test_label, mode=<span class="symbol">'test</span>'):</span><br><span class="line"> logger.info(<span class="symbol">'predicting</span> the result...')</span><br><span class="line"> <span class="keyword">if</span> mode == <span class="symbol">'test</span>':</span><br><span class="line"> pred, loss = <span class="keyword">self</span>.sess.run([<span class="keyword">self</span>.pred, <span class="keyword">self</span>.loss_func], feed_dict={<span class="keyword">self</span>.x: test_data, <span class="keyword">self</span>.y: test_label, <span class="keyword">self</span>.keep_prob: <span class="keyword">self</span>.kb})</span><br><span class="line"> <span class="keyword">return</span> pred, loss</span><br><span class="line"> elif mode == <span class="symbol">'predict</span>':</span><br><span class="line"> result = <span class="keyword">self</span>.sess.run(<span class="keyword">self</span>.pred, feed_dict={<span class="keyword">self</span>.x: test_data, <span class="keyword">self</span>.keep_prob: <span class="keyword">self</span>.kb})</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"> def load_model_predict(<span class="keyword">self</span>, test_data, test_label, mode=<span class="symbol">'test</span>'):</span><br><span class="line"> <span class="keyword">if</span> mode == <span class="symbol">'test</span>':</span><br><span class="line"> result = <span class="keyword">self</span>.sess.run([<span class="symbol">'pred</span>: <span class="number">0</span>', <span class="symbol">'loss_func</span>: <span class="number">0</span>'], feed_dict={<span class="symbol">'input</span>: <span class="number">0</span>': test_data, <span class="symbol">'true_label</span>: <span class="number">0</span>': test_label, <span class="symbol">'keep</span>: <span class="number">0</span>': <span class="number">0.8</span>})</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"> elif mode == <span class="symbol">'predict</span>':</span><br><span class="line"> result = <span class="keyword">self</span>.sess.run(<span class="symbol">'pred</span>: <span class="number">0</span>', feed_dict={<span class="symbol">'input</span>: <span class="number">0</span>': test_data, <span class="symbol">'keep</span>: <span class="number">0</span>': <span class="number">0.8</span>})</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"> def save_cnn_model(<span class="keyword">self</span>, path):</span><br><span class="line"> saver = tf.train.Saver()</span><br><span class="line"> saver.save(<span class="keyword">self</span>.sess, path)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def data_matrix(all_field_path, user_file, product_file, context_file, shop_file, mode=<span class="number">0</span>):</span><br><span class="line"> user_field = list(pd.read_csv(user_file, sep=<span class="string">','</span>, nrows=<span class="number">3</span>).columns)</span><br><span class="line"> product_field = list(pd.read_csv(product_file, sep=<span class="string">','</span>, nrows=<span class="number">3</span>).columns)</span><br><span class="line"> context_field = list(pd.read_csv(context_file, sep=<span class="string">','</span>, nrows=<span class="number">3</span>).columns)</span><br><span class="line"> shop_field = list(pd.read_csv(shop_file, sep=<span class="string">','</span>, nrows=<span class="number">3</span>).columns)</span><br><span class="line"> all_field_data = pd.read_csv(all_field_path, sep=<span class="string">','</span>)</span><br><span class="line"></span><br><span class="line"> all_field_attrs = list(all_field_data.columns)</span><br><span class="line"> # exclude_attrs = [<span class="symbol">'user_id</span>', <span class="symbol">'item_id</span>', <span class="symbol">'context_id</span>', <span class="symbol">'shop_id</span>']</span><br><span class="line"> attrs = [user_field, product_field, context_field, shop_field]</span><br><span class="line"> <span class="keyword">for</span> field <span class="keyword">in</span> attrs:</span><br><span class="line"> <span class="keyword">for</span> attr <span class="keyword">in</span> field:</span><br><span class="line"> <span class="keyword">if</span> attr not <span class="keyword">in</span> all_field_attrs:</span><br><span class="line"> field.remove(attr)</span><br><span class="line"></span><br><span class="line"> max_length = max([len(attr) <span class="keyword">for</span> attr <span class="keyword">in</span> attrs]) + <span class="number">1</span></span><br><span class="line"> label = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> field <span class="keyword">in</span> attrs:</span><br><span class="line"> diff = max_length - len(field)</span><br><span class="line"> <span class="keyword">if</span> diff > <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(label, label + diff):</span><br><span class="line"> field.append(<span class="string">'x'</span> + <span class="built_in">str</span>(i))</span><br><span class="line"> all_field_data[<span class="string">'x'</span> + <span class="built_in">str</span>(i)] = <span class="number">0</span></span><br><span class="line"> label += diff</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> pass</span><br><span class="line"></span><br><span class="line"> attrs_orders = reduce(lambda x, y: x + y, attrs, [])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> mode == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> all_field_data[attrs_orders], max_length</span><br><span class="line"> elif mode == <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">return</span> all_field_data[attrs_orders], all_field_data.index</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def split_train_test(data, label_data, ratio):</span><br><span class="line"> data, label_data = np.array(data), np.array(label_data)</span><br><span class="line"> total = len(data)</span><br><span class="line"> train_chosen_samples = random.sample(range(total), int(ratio * total))</span><br><span class="line"> test_chosen_samples = []</span><br><span class="line"> <span class="keyword">for</span> ind <span class="keyword">in</span> range(total):</span><br><span class="line"> <span class="keyword">if</span> ind not <span class="keyword">in</span> train_chosen_samples:</span><br><span class="line"> test_chosen_samples.append(ind)</span><br><span class="line"> train_set_attrs, train_set_target = data[train_chosen_samples], label_data[train_chosen_samples]</span><br><span class="line"> test_set_attrs, test_set_target = data[test_chosen_samples], label_data[test_chosen_samples]</span><br><span class="line"> <span class="keyword">return</span> train_set_attrs, train_set_target, test_set_attrs, test_set_target</span><br></pre></td></tr></table></figure><p>除了上述的神经网络的方法,我也通过Sklean调取相关API计算了LR、贝叶斯分类器、随机森林、提升树、感知器与上诉方法进行对比</p><figure class="highlight ruby"><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><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Data_Preprocess</span>(<span class="title">object</span>):</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>, train_path, test_path, raw_train_path, raw_test_path)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> Read the data including the train_data/test_data of one hot, raw_train_data/test_data, and the label of</span></span><br><span class="line"><span class="string"> raw_train_data.</span></span><br><span class="line"><span class="string"> :param train_path:</span></span><br><span class="line"><span class="string"> :param test_path:</span></span><br><span class="line"><span class="string"> :param raw_train_path:</span></span><br><span class="line"><span class="string"> :param raw_test_path:</span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> <span class="keyword">self</span>.raw_train_data = <span class="keyword">self</span>.read_data(raw_train_path, data_type=<span class="string">"raw"</span>) <span class="comment"># 获取is_trade</span></span><br><span class="line"> <span class="comment"># 需要把她它分为测试集和训练集</span></span><br><span class="line"> <span class="keyword">self</span>.X_data = <span class="keyword">self</span>.read_data(train_path, data_type=<span class="string">"one-hot"</span>).drop(<span class="string">"instance_id"</span>, axis=<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">self</span>.Y_label = <span class="keyword">self</span>.raw_train_data[<span class="string">"is_trade"</span>]</span><br><span class="line"> <span class="keyword">self</span>.predict_data = <span class="keyword">self</span>.read_data(test_path, data_type=<span class="string">"one-hot"</span>)</span><br><span class="line"> <span class="keyword">self</span>.predict_x = <span class="keyword">self</span>.alignment_data()</span><br><span class="line"> <span class="keyword">self</span>.predict_index = <span class="keyword">self</span>.read_data(raw_test_path, data_type=<span class="string">"raw"</span>)[<span class="string">"instance_id"</span>]</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 交叉验证数据集</span></span><br><span class="line"> <span class="keyword">self</span>.X_train, <span class="keyword">self</span>.X_test, <span class="keyword">self</span>.Y_train, <span class="keyword">self</span>.Y_test = <span class="keyword">self</span>.cross_data()</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">read_data</span><span class="params">(path, data_type)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> Read data according to the path of data</span></span><br><span class="line"><span class="string"> :param data_type:</span></span><br><span class="line"><span class="string"> :param path:</span></span><br><span class="line"><span class="string"> :return:</span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> <span class="keyword">if</span> data_type == <span class="string">"raw"</span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">return</span> pd.read_csv(path, sep=<span class="string">" "</span>)</span><br><span class="line"> elif data_type == <span class="string">"one-hot"</span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">return</span> pd.read_csv(path, sep=<span class="string">","</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">alignment_data</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"数据对齐..."</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">self</span>.predict_data.reindex(columns=<span class="keyword">self</span>.X_data.columns, fill_value=<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">save_model</span><span class="params">(obj, path)</span></span><span class="symbol">:</span></span><br><span class="line"> pickle.dump(obj, open(path, <span class="string">"wb"</span>))</span><br><span class="line"> logger.info(<span class="string">'The model has been saved to '</span> + path + <span class="string">'...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">cross_data</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> X_train, X_test, Y_train, Y_test = train_test_split(<span class="keyword">self</span>.X_data, <span class="keyword">self</span>.Y_label, test_size=<span class="number">0</span>.<span class="number">1</span>, random_state=<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> X_train, X_test, Y_train, Y_test</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LR_Model</span>(<span class="title">object</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y, <span class="keyword">self</span>.test_x, <span class="keyword">self</span>.test_y = X_train, Y_train, X_test, Y_test</span><br><span class="line"> <span class="keyword">self</span>.predict_x = predict_x</span><br><span class="line"> <span class="keyword">self</span>.predict_index = predict_index</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">lr_model</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="string">""</span><span class="string">"</span></span><br><span class="line"><span class="string"> Method: logisticRegression</span></span><br><span class="line"><span class="string"> :return: return the probability of test data with list format</span></span><br><span class="line"><span class="string"> "</span><span class="string">""</span></span><br><span class="line"> logger.info(<span class="string">'LR_model beginning ...'</span>)</span><br><span class="line"> classifier = LogisticRegression(solver=<span class="string">"sag"</span>, class_weight=<span class="string">"balanced"</span>)</span><br><span class="line"> classifier.fit(<span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y)</span><br><span class="line"> index = list(classifier.classes<span class="number">_</span>).index(<span class="number">1</span>)</span><br><span class="line"> test_y_predict = pd.DataFrame(classifier.predict_proba(<span class="keyword">self</span>.test_x), columns=list(classifier.classes<span class="number">_</span>))</span><br><span class="line"> test_y_predict[index] = test_y_predict[index].apply(lambda <span class="symbol">x:</span> <span class="number">0</span> <span class="keyword">if</span> x <= <span class="number">0</span>.<span class="number">01</span> <span class="keyword">else</span> x)</span><br><span class="line"> predict_y = list(map(lambda <span class="symbol">x:</span> x[index], classifier.predict_proba(<span class="keyword">self</span>.predict_x)))</span><br><span class="line"> data_results.save_model(obj=classifier, path=<span class="string">"../../data/results_2/lr_model.pk"</span>)</span><br><span class="line"> <span class="keyword">return</span> test_y_predict, predict_y</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">evaluate</span><span class="params">(y_true, y_pred)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"LR_model evaluating..."</span>)</span><br><span class="line"> logloss = log_loss(y_true, np.array(y_pred))</span><br><span class="line"> logger.info(<span class="string">"The value of logloss:"</span> + str(logloss))</span><br><span class="line"> <span class="keyword">return</span> logloss</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">write_result</span><span class="params">(<span class="keyword">self</span>, predict_pro, path=<span class="string">"../../data/results_2/lr_results.txt"</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Write_result finishing ...'</span>)</span><br><span class="line"> with open(path, <span class="string">"w"</span>, encoding=<span class="string">"utf-8"</span>) as <span class="symbol">f:</span></span><br><span class="line"> f.write(<span class="string">"instance_id"</span> + <span class="string">" "</span> + <span class="string">"predicted_score"</span> + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(predict_pro))<span class="symbol">:</span></span><br><span class="line"> <span class="keyword">if</span> predict_pro[i] > <span class="number">0</span>.<span class="number">01</span><span class="symbol">:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(predict_pro[i]) + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(<span class="number">0</span>.<span class="number">0</span>) + <span class="string">"\r"</span>)</span><br><span class="line"> logger.info(<span class="string">'Write_result finished ...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> test_y_predict, predict_y = <span class="keyword">self</span>.lr_model()</span><br><span class="line"> <span class="keyword">self</span>.evaluate(<span class="keyword">self</span>.test_y, test_y_predict)</span><br><span class="line"> <span class="keyword">self</span>.write_result(predict_pro=predict_y)</span><br><span class="line"> logger.info(<span class="string">'lr_model finished ...'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bayes_Model</span>(<span class="title">object</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y, <span class="keyword">self</span>.test_x, <span class="keyword">self</span>.test_y = X_train, Y_train, X_test, Y_test</span><br><span class="line"> <span class="keyword">self</span>.predict_x = predict_x</span><br><span class="line"> <span class="keyword">self</span>.predict_index = predict_index</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">bayes_model</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Bayes_model beginning ...'</span>)</span><br><span class="line"> classifier = BernoulliNB()</span><br><span class="line"> classifier.fit(<span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y)</span><br><span class="line"> index = list(classifier.classes<span class="number">_</span>).index(<span class="number">1</span>)</span><br><span class="line"> test_y_predict = pd.DataFrame(classifier.predict_proba(<span class="keyword">self</span>.test_x), columns=list(classifier.classes<span class="number">_</span>))</span><br><span class="line"> test_y_predict[index] = test_y_predict[index].apply(lambda <span class="symbol">x:</span> <span class="number">0</span> <span class="keyword">if</span> x <= <span class="number">0</span>.<span class="number">01</span> <span class="keyword">else</span> x)</span><br><span class="line"> predict_y = list(map(lambda <span class="symbol">x:</span> x[index], classifier.predict_proba(<span class="keyword">self</span>.predict_x)))</span><br><span class="line"> data_results.save_model(obj=classifier, path=<span class="string">"../../data/results_2/bayes_model.pk"</span>)</span><br><span class="line"> <span class="keyword">return</span> test_y_predict, predict_y</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">evaluate</span><span class="params">(y_true, y_pred)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"Bayes_model evaluating..."</span>)</span><br><span class="line"> logloss = log_loss(y_true, np.array(y_pred))</span><br><span class="line"> logger.info(<span class="string">"The value of logloss:"</span> + str(logloss))</span><br><span class="line"> <span class="keyword">return</span> logloss</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">write_result</span><span class="params">(<span class="keyword">self</span>, predict_pro, path=<span class="string">"../../data/results_2/bayes_results.txt"</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Write_result finishing ...'</span>)</span><br><span class="line"> with open(path, <span class="string">"w"</span>, encoding=<span class="string">"utf-8"</span>) as <span class="symbol">f:</span></span><br><span class="line"> f.write(<span class="string">"instance_id"</span> + <span class="string">" "</span> + <span class="string">"predicted_score"</span> + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(predict_pro))<span class="symbol">:</span></span><br><span class="line"> <span class="keyword">if</span> predict_pro[i] > <span class="number">0</span>.<span class="number">01</span><span class="symbol">:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(predict_pro[i]) + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(<span class="number">0</span>.<span class="number">0</span>) + <span class="string">"\r"</span>)</span><br><span class="line"> logger.info(<span class="string">'Write_result finished ...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> test_y_predict, predict_y = <span class="keyword">self</span>.bayes_model()</span><br><span class="line"> <span class="keyword">self</span>.evaluate(<span class="keyword">self</span>.test_y, test_y_predict)</span><br><span class="line"> <span class="keyword">self</span>.write_result(predict_pro=predict_y)</span><br><span class="line"> logger.info(<span class="string">'bayes_model finished ...'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RandomTree</span>(<span class="title">object</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y, <span class="keyword">self</span>.test_x, <span class="keyword">self</span>.test_y = X_train, Y_train, X_test, Y_test</span><br><span class="line"> <span class="keyword">self</span>.predict_x = predict_x</span><br><span class="line"> <span class="keyword">self</span>.predict_index = predict_index</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">randomtree_model</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'RandomTree_model beginning ...'</span>)</span><br><span class="line"> classifier = RandomForestClassifier(class_weight=<span class="string">"balanced"</span>)</span><br><span class="line"> classifier.fit(<span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y)</span><br><span class="line"> index = list(classifier.classes<span class="number">_</span>).index(<span class="number">1</span>)</span><br><span class="line"> test_y_predict = pd.DataFrame(classifier.predict_proba(<span class="keyword">self</span>.test_x), columns=list(classifier.classes<span class="number">_</span>))</span><br><span class="line"> test_y_predict[index] = test_y_predict[index].apply(lambda <span class="symbol">x:</span> <span class="number">0</span> <span class="keyword">if</span> x <= <span class="number">0</span>.<span class="number">01</span> <span class="keyword">else</span> x)</span><br><span class="line"> predict_y = list(map(lambda <span class="symbol">x:</span> x[index], classifier.predict_proba(<span class="keyword">self</span>.predict_x)))</span><br><span class="line"> data_results.save_model(obj=classifier, path=<span class="string">"../../data/results_2/random_tree_model.pk"</span>)</span><br><span class="line"> <span class="keyword">return</span> test_y_predict, predict_y</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">evaluate</span><span class="params">(y_true, y_pred)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"Random_tree_model evaluating..."</span>)</span><br><span class="line"> logloss = log_loss(y_true,np.array(y_pred))</span><br><span class="line"> logger.info(<span class="string">"The value of logloss:"</span> + str(logloss))</span><br><span class="line"> <span class="keyword">return</span> logloss</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">write_result</span><span class="params">(<span class="keyword">self</span>, predict_pro, path=<span class="string">"../../data/results_2/random_tree_results.txt"</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Write_result finishing ...'</span>)</span><br><span class="line"> with open(path, <span class="string">"w"</span>, encoding=<span class="string">"utf-8"</span>) as <span class="symbol">f:</span></span><br><span class="line"> f.write(<span class="string">"instance_id"</span> + <span class="string">" "</span> + <span class="string">"predicted_score"</span> + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(predict_pro))<span class="symbol">:</span></span><br><span class="line"> <span class="keyword">if</span> predict_pro[i] > <span class="number">0</span>.<span class="number">01</span><span class="symbol">:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(predict_pro[i]) + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(<span class="number">0</span>.<span class="number">0</span>) + <span class="string">"\r"</span>)</span><br><span class="line"> logger.info(<span class="string">'Write_result finished ...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> test_y_predict, predict_y = <span class="keyword">self</span>.randomtree_model()</span><br><span class="line"> <span class="keyword">self</span>.evaluate(<span class="keyword">self</span>.test_y, test_y_predict)</span><br><span class="line"> <span class="keyword">self</span>.write_result(predict_pro=predict_y)</span><br><span class="line"> logger.info(<span class="string">'random_tree_model finished ...'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">GTB</span>(<span class="title">object</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y, <span class="keyword">self</span>.test_x, <span class="keyword">self</span>.test_y = X_train, Y_train, X_test, Y_test</span><br><span class="line"> <span class="keyword">self</span>.predict_x = predict_x</span><br><span class="line"> <span class="keyword">self</span>.predict_index = predict_index</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">gtb_model</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'GTB_model beginning ...'</span>)</span><br><span class="line"> classifier = GradientBoostingClassifier()</span><br><span class="line"> classifier.fit(<span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y)</span><br><span class="line"> index = list(classifier.classes<span class="number">_</span>).index(<span class="number">1</span>)</span><br><span class="line"> test_y_predict = pd.DataFrame(classifier.predict_proba(<span class="keyword">self</span>.test_x), columns=list(classifier.classes<span class="number">_</span>))</span><br><span class="line"> test_y_predict[index] = test_y_predict[index].apply(lambda <span class="symbol">x:</span> <span class="number">0</span> <span class="keyword">if</span> x <= <span class="number">0</span>.<span class="number">01</span> <span class="keyword">else</span> x)</span><br><span class="line"> predict_y = list(map(lambda <span class="symbol">x:</span> x[index], classifier.predict_proba(<span class="keyword">self</span>.predict_x)))</span><br><span class="line"> data_results.save_model(obj=classifier, path=<span class="string">"../../data/results_2/gtb_model.pk"</span>)</span><br><span class="line"> <span class="keyword">return</span> test_y_predict, predict_y</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">evaluate</span><span class="params">(y_true, y_pred)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"GTB_model evaluating..."</span>)</span><br><span class="line"> logloss = log_loss(y_true, np.array(y_pred))</span><br><span class="line"> logger.info(<span class="string">"The value of logloss:"</span> + str(logloss))</span><br><span class="line"> <span class="keyword">return</span> logloss</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">write_result</span><span class="params">(<span class="keyword">self</span>, predict_pro, path=<span class="string">"../../data/results_2/gtb_results.txt"</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Write_result finishing ...'</span>)</span><br><span class="line"> with open(path, <span class="string">"w"</span>, encoding=<span class="string">"utf-8"</span>) as <span class="symbol">f:</span></span><br><span class="line"> f.write(<span class="string">"instance_id"</span> + <span class="string">" "</span> + <span class="string">"predicted_score"</span> + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(predict_pro))<span class="symbol">:</span></span><br><span class="line"> <span class="keyword">if</span> predict_pro[i] > <span class="number">0</span>.<span class="number">01</span><span class="symbol">:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(predict_pro[i]) + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(<span class="number">0</span>.<span class="number">0</span>) + <span class="string">"\r"</span>)</span><br><span class="line"> logger.info(<span class="string">'Write_result finished ...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> test_y_predict, predict_y = <span class="keyword">self</span>.gtb_model()</span><br><span class="line"> <span class="keyword">self</span>.evaluate(<span class="keyword">self</span>.test_y, test_y_predict)</span><br><span class="line"> <span class="keyword">self</span>.write_result(predict_pro=predict_y)</span><br><span class="line"> logger.info(<span class="string">'GTB_model finished ...'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NeuralNetwork</span>(<span class="title">object</span>):</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> <span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y, <span class="keyword">self</span>.test_x, <span class="keyword">self</span>.test_y = X_train, Y_train, X_test, Y_test</span><br><span class="line"> <span class="keyword">self</span>.predict_x = predict_x</span><br><span class="line"> <span class="keyword">self</span>.predict_index = predict_index</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">nn_model</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'NN_model beginning ...'</span>)</span><br><span class="line"> classifier = MLPClassifier(solver=<span class="string">"sgd"</span>, hidden_layer_sizes=(<span class="number">500</span>, <span class="number">3</span>))</span><br><span class="line"> classifier.fit(<span class="keyword">self</span>.train_x, <span class="keyword">self</span>.train_y)</span><br><span class="line"> index = list(classifier.classes<span class="number">_</span>).index(<span class="number">1</span>)</span><br><span class="line"> test_y_predict = pd.DataFrame(classifier.predict_proba(<span class="keyword">self</span>.test_x), columns=list(classifier.classes<span class="number">_</span>))</span><br><span class="line"> test_y_predict[index] = test_y_predict[index].apply(lambda <span class="symbol">x:</span> <span class="number">0</span> <span class="keyword">if</span> x <= <span class="number">0</span>.<span class="number">01</span> <span class="keyword">else</span> x)</span><br><span class="line"> predict_y = list(map(lambda <span class="symbol">x:</span> x[index], classifier.predict_proba(<span class="keyword">self</span>.predict_x)))</span><br><span class="line"> data_results.save_model(obj=classifier, path=<span class="string">"../../data/results_2/nn_model.pk"</span>)</span><br><span class="line"> <span class="keyword">return</span> test_y_predict, predict_y</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">evaluate</span><span class="params">(y_true, y_pred)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">"NN_model evaluating..."</span>)</span><br><span class="line"> logloss = log_loss(y_true, np.array(y_pred))</span><br><span class="line"> logger.info(<span class="string">"The value of logloss:"</span> + str(logloss))</span><br><span class="line"> <span class="keyword">return</span> logloss</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">write_result</span><span class="params">(<span class="keyword">self</span>, predict_pro, path=<span class="string">"../../data/results_2/nn_results.txt"</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> logger.info(<span class="string">'Write_result beginning ...'</span>)</span><br><span class="line"> with open(path, <span class="string">"w"</span>, encoding=<span class="string">"utf-8"</span>) as <span class="symbol">f:</span></span><br><span class="line"> f.write(<span class="string">"instance_id"</span> + <span class="string">" "</span> + <span class="string">"predicted_score"</span> + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(predict_pro))<span class="symbol">:</span></span><br><span class="line"> <span class="keyword">if</span> predict_pro[i] > <span class="number">0</span>.<span class="number">01</span><span class="symbol">:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(predict_pro[i]) + <span class="string">"\r"</span>)</span><br><span class="line"> <span class="symbol">else:</span></span><br><span class="line"> f.write(str(<span class="keyword">self</span>.predict_index[i]) + <span class="string">" "</span> + str(<span class="number">0</span>.<span class="number">0</span>) + <span class="string">"\r"</span>)</span><br><span class="line"> logger.info(<span class="string">'Write_result finished ...'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(<span class="keyword">self</span>)</span></span><span class="symbol">:</span></span><br><span class="line"> test_y_predict, predict_y = <span class="keyword">self</span>.nn_model()</span><br><span class="line"> <span class="keyword">self</span>.evaluate(<span class="keyword">self</span>.test_y, test_y_predict)</span><br><span class="line"> <span class="keyword">self</span>.write_result(predict_pro=predict_y)</span><br><span class="line"> logger.info(<span class="string">'NN_model finished ...'</span>)</span><br></pre></td></tr></table></figure><p>对于不同的模型,我们使用自己分的测试集对其进行预测,并计算相关的损失函数,损失函数的结果如下:</p><p><strong>【注意:结果值越小越好】</strong></p><table><thead><tr><th style="text-align:center">Mehod</th><th style="text-align:center">LR</th><th style="text-align:center">Bayes</th><th style="text-align:center">Random_T</th><th style="text-align:center">GTB</th><th style="text-align:center">NN</th><th style="text-align:center">CNN</th></tr></thead><tbody><tr><td style="text-align:center">Loss</td><td style="text-align:center">4.10158</td><td style="text-align:center">1.015423</td><td style="text-align:center">0.539459</td><td style="text-align:center">0.09011</td><td style="text-align:center">0.089561</td><td style="text-align:center">0.046641</td></tr></tbody></table><p><img src="https://upload-images.jianshu.io/upload_images/5274272-a2dcd08a04ef3118.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="2018-05-02-2.png"></p><p><strong>从上表可以看到逻辑回归、贝叶斯分类器、随机森林、简单感知器、CNN的结果,而我们提出的CNN算法在测试集上的效果为0.046641明显优于其他方法,然后我们却没能够得到最终的验证,哭死哭死。</strong></p><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>虽然这次比赛比较遗憾和难过,但是不得不说,真的学习了很多很多,不论是在对数据处理上、方法上还是码代码上,虽然遇到很多问题,但是都通过努力,跟小伙伴一起解决了,在此非常感谢小伙伴阿文,许埕秸同学。</p><p>其实,对于很多事,除了【努力】、【机遇】、【幸运】,还是要注意细节,一直都喜欢对自己说,把每件小事做好了,那么结果一定不会太差,那么,未来,请继续努力吧! </p><p>毕竟海贼王的女人是不会认输的,O(∩_∩)O哈哈哈~,下面奉上今日新作《海贼王 路飞》</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-b13a88a46fa9d291.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="海贼王 路飞"></p><p><strong>【注意更多更完整的代码详见github】</strong></p><pre><code>用户名:DWJWendy链接:https://github.com/DWJWendy/IJCAI_2018_CTR.git</code></pre>]]></content>
<categories>
<category> 算法大赛 </category>
</categories>
<tags>
<tag> python </tag>
<tag> cnn </tag>
</tags>
</entry>
<entry>
<title>数据类型与数据质量介绍</title>
<link href="/2019/02/25/%E6%95%B0%E6%8D%AE/"/>
<url>/2019/02/25/%E6%95%B0%E6%8D%AE/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: 数据类型与数据质量介绍<br>categories: Course<br>description: 数据类型、数据质量<br>keywords: 数据、类型、质量</p><hr><p>参考书:Pang-Ning Tan《数据挖掘导论》 –人民邮电出版社</p><h4 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h4><pre><code>数据集可以看成是数据对象的集合,数据对象有时也叫做记录、点、向量、模式、事件、案例、样本、观测或者实体,其实怎么叫它并不重要,你需要知道数据对象用一组刻画对象基本特性的属性描述的,属性有时候也叫做变量、特性、字段、特征、或者维。在数据挖掘中我们比较习惯叫它特征。</code></pre><hr><p>一、属性与度量<br>属性是对象的性质或特性,因对象而异,随时间变化。注意:属性并非数字或者符号,而是为了精分对象特性,我们为它赋予了数字和符号。</p><p>测量标度:是将数值和符号值与对象的属性相关联的规则,简而言之就是给属性值赋值。</p><hr><p>二、 属性类型<br>属性类型分为四类:标称(nominal)、序数(ordinal)、区间(interval)、比率(radio),常常用相异性(=,≠)、序(<,≤,>,≥,)、加法(+、-)、乘法(*、/),标称和序数属性统称为分类的或是定性的属性,区间和比率属性统称为定量的或者数值的。</p><hr><table><thead><tr><th style="text-align:center">属性类型</th><th style="text-align:center">描述</th><th style="text-align:center">例子</th><th style="text-align:center">操作</th><th style="text-align:center">变换</th></tr></thead><tbody><tr><td style="text-align:center">标称</td><td style="text-align:center">分类定性(=,≠)</td><td style="text-align:center">性别、id、眼球颜色</td><td style="text-align:center">众数、熵、列联相关、卡方检验</td><td style="text-align:center">一对一变换</td></tr><tr><td style="text-align:center">序数</td><td style="text-align:center">分类定性(<>)</td><td style="text-align:center">【好、较好、最好】、矿石硬度</td><td style="text-align:center">中值、百分位、轶相关、游程检验、符号检验</td><td style="text-align:center">保序变换new=f(old),f是单调的</td></tr><tr><td style="text-align:center">区间</td><td style="text-align:center">数值定量(+—)</td><td style="text-align:center">温度、</td><td style="text-align:center">均值、标准差、皮尔逊相关、t和F检验</td><td style="text-align:center">new=a*old+b(a,b为常数)</td></tr><tr><td style="text-align:center">比率</td><td style="text-align:center">数值定量(*/)</td><td style="text-align:center">质量,长度、计数</td><td style="text-align:center">几何平均、算术平均、百分比变差</td><td style="text-align:center">new=a*old</td></tr></tbody></table><p><strong>注:事实上最常用的属性分类是:离散的或者是连续的</strong></p><hr><p>三、数据集的类型<br>数据集的类型主要分为三类:记录数据、基于图形的数据、有序的数据。数据集的一般特性:维度(dimension)、稀疏性(sparsity)、分辨率(resolution)。</p><p><strong>首先解释数据的三个一般特性</strong></p><ol><li>维度:不同维度的数据往往具有不同的特征,高维数据的分析往往会陷入维度灾难,所以在数据预处理中有时会进行降维处理,简称维归约,常用的方法:PCA、LDA、矩阵分解</li><li>稀疏性:在文本表征时,bag-of-words是一个常用的方法,但是这个方法会造成数据稀疏,表征效果不好。但是有时候稀疏性也是一个有点,尤其是对于只用存储和处理非零值而言,也有一些数据挖掘的算法仅适合处理稀疏数据。</li><li>分辨率:不同的分辨率下数据的性质不同,数据的模式也依赖于分辨率。比如图片,但是我目前接触到的机器学习任务还没有涉及到分辨率的。</li></ol><p><strong>介绍三类数据</strong></p><h5 id="gt-记录数据"><a href="#gt-记录数据" class="headerlink" title="> 记录数据"></a>> 记录数据</h5><p>在数据挖掘中比较常见的是记录数据,每个记录包含了固定的数据字段集(属性集),除了最基本的记录数据还有很多基于记录数据的变种,比如数据矩阵、文档-词矩阵(稀疏的数据矩阵)</p><h5 id="gt-基于图形的数据"><a href="#gt-基于图形的数据" class="headerlink" title="> 基于图形的数据"></a>> 基于图形的数据</h5><p>有时候图形可以有效地表示数据,两种特殊的情况:图形捕获数据对象之间的联系;数据对象本身用图形表示。基于图形的数据一般是将数据对象表示为图的结点,对象之间的关系用链接或者方向、权值等表示出来,比如网页之间的链接可以用图形表示出来,化合物的分子结构以及社交网络朋友之间的关系等等等等,然而,很多时间,我们将数据用图形表示出来,而真正在数据挖掘中很多时候将数据以及数据之间的关系用邻接矩阵的给表示出来,再利用矩阵理论相关知识进行操作。</p><h5 id="gt-有序数据"><a href="#gt-有序数据" class="headerlink" title="> 有序数据"></a>> 有序数据</h5><p>有序数据,顾名思义数据是数据之间可以排序的,往往有序数据会涉及到时间或者空间,比如顾客在一年的购买记录,温度变化等等</p><p><strong>总结</strong><br>大部分数据挖掘算法都是为记录数据或者其变体设计的,通过从数据中抽取特征,并用这些特征创建对应于每个对象的记录,而针对于记录数据的技术也可以用于非记录数据,而无论是记录数据或者非记录数据的处理都是需要从数据中抽取有效特征,所以挖掘效果好不好,<strong>特征工程非常重要</strong>。</p><hr><h4 id="数据质量"><a href="#数据质量" class="headerlink" title="数据质量"></a>数据质量</h4><p>数据挖掘使用的数据往往是根据其他用途收集的,或者在收集时未明确目标的,因此数据挖掘着眼于两个方面:(1)数据质量问题的检测和纠正–>被称为<strong>数据清理</strong>(2)使用可以容忍低质量数据的算法</p><p>在讨论数据质量,我们往往关注数据测量和收集方面的数据质量问题,先定义测量误差和数据收集错误,然后考虑涉及测量误差的各种问题:噪声、伪像、偏倚、精度和准确率,最后讨论可能同时涉及测量和数据收集的数据质量问题:离群点、遗漏和不一致的值、重复的值。接下来按上面的逻辑依次介绍:</p><h5 id="gt-1-测量误差和数据收集错误"><a href="#gt-1-测量误差和数据收集错误" class="headerlink" title="-> 1. 测量误差和数据收集错误"></a>-> 1. 测量误差和数据收集错误</h5><p><strong>测量误差</strong>:是指测量过程中导致记录值和实际值不同;<strong>数据收集错误</strong>是指诸如遗漏数据对象或者属性值,或不当地包含了其他数据对象等错误。在某些特定领域,常常有很好的技术来检测和纠正这些错误,eg 人工输入数据时键盘录入错误非常常见,因此许多数据输入程序具有检测技术,并且通过人工干预纠正这类错误。</p><h5 id="gt-2-噪声和伪像"><a href="#gt-2-噪声和伪像" class="headerlink" title="-> 2. 噪声和伪像"></a>-> 2. 噪声和伪像</h5><p><strong>噪声</strong>是测量误差的随机部分,比如figure-1 在时间序列上加入噪声,形状就会消失,术语“噪声”通常用于包含时间或者空间的数据,在这种情况下可以使用信号或者图像处理的方式降低噪声。事实上,除噪通常比较困难,所以数据挖掘比较关注<strong>鲁棒算法</strong>,即在噪声干扰的情况下,也能产生可以接受的结果。</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-5835b17fef723137.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure-1"></p><p><strong>伪像</strong>:比如一组照片在同一地方出现条纹,数据这种确定性失真就叫伪像。</p><h5 id="gt-3-精度、偏倚和准确率"><a href="#gt-3-精度、偏倚和准确率" class="headerlink" title="-> 3. 精度、偏倚和准确率"></a>-> 3. 精度、偏倚和准确率</h5><p>在统计学和实验科学中,测量过程和结果数据的质量用精度和偏倚度量。<br><strong>精度</strong> (同一个两的)重复测量值之间的接近程度<br><strong>偏倚</strong>测量值和被测量值之间的系统的变差<br><strong>准确率</strong>被测量的测量值与实际值之间的接近度<br>Note:这是对数据集衡量的指标,与我们在分类过程中的指标(精度和准确率)不同</p><h5 id="gt-4-离群点"><a href="#gt-4-离群点" class="headerlink" title="-> 4. 离群点"></a>-> 4. 离群点</h5><p><strong>离群点</strong>也被称为异常,数据挖掘很多方法可以用于异常检测,这里需要<strong>明白的是噪声与离群点不同</strong>,离群点本身是合法的数据对象或者值。</p><h5 id="gt-5-遗漏值"><a href="#gt-5-遗漏值" class="headerlink" title="-> 5. 遗漏值"></a>-> 5. 遗漏值</h5><p>数据集出现遗漏值很常见。而更加重要的是我们如何处理遗漏值,这里提出了一些策略:(1)删除遗漏的数据对象或者属性(2)估计遗漏值(eg 用临近值、平均值、最常见值等等)(3)忽略遗漏值</p><h5 id="gt-6-不一致的值"><a href="#gt-6-不一致的值" class="headerlink" title="-> 6. 不一致的值"></a>-> 6. 不一致的值</h5><p>数据可能包含不一致的值,比如邮编与城市名之间不一致等等,需要检测并纠正这种错误。</p><h5 id="gt-7-重复数据"><a href="#gt-7-重复数据" class="headerlink" title="-> 7. 重复数据"></a>-> 7. 重复数据</h5><p>在数据预处理时,需要检测并删除重复(deduplication)的数据,而去重过程也可以在数据爬取阶段完成。</p>]]></content>
<categories>
<category> learning </category>
</categories>
<tags>
<tag> ML </tag>
<tag> Data </tag>
</tags>
</entry>
<entry>
<title>基于社交媒体的企业行为事件挖掘-1</title>
<link href="/2019/02/25/%E5%9F%BA%E4%BA%8E%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93%E7%9A%84%E4%BC%81%E4%B8%9A%E8%A1%8C%E4%B8%BA%E4%BA%8B%E4%BB%B6%E6%8C%96%E6%8E%98/"/>
<url>/2019/02/25/%E5%9F%BA%E4%BA%8E%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93%E7%9A%84%E4%BC%81%E4%B8%9A%E8%A1%8C%E4%B8%BA%E4%BA%8B%E4%BB%B6%E6%8C%96%E6%8E%98/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: 基于社交媒体的企业行为事件挖掘–系列[1]<br>categories: Case<br>description: 利用word2vec+触发器识别企业事件<br>keywords: word2vec、企业事件</p><hr><p>利用Word2vec+trigger的方式识别企业事件</p><hr><h4 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h4><p>企业事件挖掘是我自大四的毕业设计到现在依旧跟进的研究内容,从微博数据抓取–> 数据预处理 –>模型对比–>事件演化分析均是一步一步探索而来,刚刚开始学习自然语言处理,过程还是有点艰辛,第一期的任务早已经完成了,甚至可以基于社交媒体企业事件挖掘写一系列文章,万事开头难,先从第一期的内容开始。</p><p>接下来文章的将从 <strong>研究背景 - 研究方法 - 研究结果 </strong>三大部分进行介绍。</p><hr><h4 id="研究背景"><a href="#研究背景" class="headerlink" title="研究背景"></a>研究背景</h4><p><strong>研究背景的逻辑框架通过下面的图给表示出来:</strong></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-c0b8cf047a9045b6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="研究背景的逻辑框架"></p><p>在信息技术和移动互联网技术快速发展的同时,信息资源也呈现指数增长,基于传统的统计方法进行数据分析面临巨大挑战,从海量数据中挖掘有价值的信息成为一种必然趋势。社交媒体(Social Media,又称社会化媒体)作为目前最重要的信息源之一,它在社会舆论、信息传播、企业营销等方面发挥着其他媒介不可替代的作用。据新浪《2016微博企业白皮书》统计,截至2016年12月底,微博企业账号注册量已达到130万,越来越多的企业利用社交媒体塑造企业品牌、产品营销推广、客户关系管理,由于社交媒体具有先天媒体属性,对比传统的信息传播方式(比如电视、报刊杂志、新闻网站、企业官网),企业加入社交媒体平台,不仅可以通过平台获取及时有用的信息,更重要的是可以发布大量与企业经营活动相关信息,逐渐,企业信息在社交媒体平台中累积,更重要的是,这些信息中隐含了大量的企业行为,具有重要的研究价值和应用价值(如图1.1-1华为在其官方账号发布与英特尔进行全球HPC合作的相关信息),因此,如何从海量社交媒体数据中识别企业行为成为了一个非常有意义的研究主题。</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-86e24687833e5545.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="华为企业账号发布合作信息"></p><p>然而,从海量社交媒体数据中识别企业行为并非易事。这里主要有三个挑战:</p><ul><li><p>第一, 在社交媒体中,用户生成内容(User-generated Content,简称UGC)多为短文本,这些短文本具有表达类型多样、表意模糊不清、噪音多、主题多等特点,它严重阻碍了企业行为识别的有效性;</p></li><li><p>第二, 识别方法,传统的自然语言处理方法并不能有效地从企业信息中识别企业行为,比如词袋模型3(Bag of Words,简称BOW),它是基于词频统计方法,所以表征文档也仅仅表征了文档中的词语频率,忽略了词语间的语义和位置关系;</p></li><li><p>第三, 企业行为一般是由一系列动词触发(如上图触发动词有合作、携手、联合等),由于人工标注动词需要结合动词的使用语境,所以人工对标记所有触发企业行为动词非常耗时耗力;</p></li></ul><p>为了克服这些挑战,笔者利用浅层神经网络模型训练词向量,将企业行为刻画成可以计算的高维向量,只需要标记部分触发企业行为的种子数据,再利用已经标注的种子数据中的动词对未知动词进行同义词识别,从而形成企业行为触发器,再利用触发器和种子数据表征企业行为,从而对新文档进行企业行为识别。</p><hr><h4 id="研究方法"><a href="#研究方法" class="headerlink" title="研究方法"></a>研究方法</h4><h4 id="1-企业定义"><a href="#1-企业定义" class="headerlink" title="1 企业定义"></a>1 企业定义</h4><p><strong>企业行为</strong>是指企业为了追求一定目标而进行的相关商业或社会活动。<strong>社交媒体中的企业行为</strong>是指企业利用社交媒体平台发布企业相关信息从而达到产品发布、销售、推广以及粉丝(客户)关系管理等目标的一系列行为。本文, <strong>企业行为主要由动词刻画, </strong>因此,本文主要是通过抽取文本中的动词对企业行为进行表征。</p><h4 id="2-研究框架"><a href="#2-研究框架" class="headerlink" title="2 研究框架"></a>2 研究框架</h4><ul><li>研究方法的框架如下:</li></ul><p><img src="https://upload-images.jianshu.io/upload_images/5274272-53c435b9fa195284.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="研究方法的框架"></p><p>企业行为识别方法框架如上图表示,此框架分为两部分,右边是主要企业行为识别分类器,左边是待识别的新文档。<br>针对右边的企业行为识别分类器介绍如下:(1)对原始数据进行预处理;(2)用预处理后数据训练词表征;(3)从预处理后的数据中选择具有代表性的种子数据,并为种子数据打上企业行为标签;(4)将种子数据抽取动词序列,并基于词表征计算种子数据集中企业行为向量(5)根据企业行为对语料库中剩余动词进行相似度识别,从而行为企业行为触发器;(6)基于触发器形成企业行为向量进行企业行为识别。</p><p>针对左边的待识别的新文档,对于一篇新的文档,首先进行数据预处理,再抽取动词语序,然后用动词向量表征新的文档。最后根据已有的企业行为向量与新的文档向量进行相似度计算,取相似度的最大值所对应的企业行为,所以企业行为事件挖掘问题可以通过下图表示出来:<br><img src="https://upload-images.jianshu.io/upload_images/5274272-3cb6196a8c73e9ea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><h4 id="数据预处理"><a href="#数据预处理" class="headerlink" title="数据预处理"></a>数据预处理</h4><ul><li><p>1.数据抓取,微博数据抓取的代码可以参考我的github项目 <a href="https://github.com/DWJWendy/Weibo_Spider" target="_blank" rel="noopener">Weibo_Spider</a> </p></li><li><p>2.数据清洗,使用Python3.5中Beautifulsoup1对数据集中html5标签进行解析,并利用Python编写程序,删除重复记录,最后得到可利用的文本数据。</p></li><li><p>3.分词处理,使用Jieba1对文本进行分词,jieba分词可以确定词性,也便于后续实验抽取动词序列</p></li><li><p>4.删除一字词和停用词,由于中文文本中经常包含大量无(一字词和停用词)的词,为了获得更好的实验效果,所以必须删除这些无意义的词</p></li><li><p>5.Word2vec 训练词向量, Word2vec是google 2013年提出的词表征工具,将语料库中所有文本分词、删除一字词和停用词之后将词序列放入Word2vec模型训练词向量,这样可以将词映射到高维向量中,词均能通过向量进行表征。</p></li></ul><h4 id="触发器识别"><a href="#触发器识别" class="headerlink" title="触发器识别"></a>触发器识别</h4><p><img src="https://upload-images.jianshu.io/upload_images/5274272-226bf1e1b0158c87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>首先利用Word2ve训练的词向量表征人工标注的种子词,再对语料库中剩余的高频动词进行触发器识别,同义或经常共同出现的词他们的相似度会很高。</p><h4 id="企业行为识别"><a href="#企业行为识别" class="headerlink" title="企业行为识别"></a>企业行为识别</h4><p><img src="https://upload-images.jianshu.io/upload_images/5274272-4c6e6bd727c994de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt></p><p>首先对于一个微博文章用动词的平均向量进行表征,得到每一条微博的向量表征,再计算企业行为向量与微博中心向量的cosine相似度,如果最大的相似度大于阈值,那么该条微博的企业行为属于对应的最大相似度的企业行为。</p><hr><h4 id="研究结果"><a href="#研究结果" class="headerlink" title="研究结果"></a>研究结果</h4><ul><li><strong>数据</strong><br>本次的实验数据来自微博网站1,数据对象是国内知名手机企业的官方微博账号(包括华为、小米、魅族、中兴、联想、酷派、OPPO、VIVO、HTC和TCL十家企业),下图展示了四家企业账号发布信息具体实例。<br><img src="https://upload-images.jianshu.io/upload_images/5274272-b8fc5f6c771f7437.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="实例"></li></ul><p>下表是具体的每个企业的微博账号对应的微博数量以及从开微博起到2016年08月的时间间隔数据</p><table><thead><tr><th>微博名(ID:<strong><strong>**</strong></strong>)</th><th style="text-align:left">微博总数(条)</th><th style="text-align:left">时间间隔</th></tr></thead><tbody><tr><td>联想(ID:2183473425)</td><td style="text-align:left">17690</td><td style="text-align:left">2011/07/15 - 2016/08/07</td></tr><tr><td>酷派官方微博(ID: 1689575103)</td><td style="text-align:left">13485</td><td style="text-align:left">2010/06/04 - 2016/08/05</td></tr><tr><td>中兴通讯(ID:1689575103)</td><td style="text-align:left">10372</td><td style="text-align:left">2010/12/22 - 2016/08/10</td></tr><tr><td>vivo智能手机(ID:1809745371)</td><td style="text-align:left">10238</td><td style="text-align:left">2010/09/03 - 2016/08/10</td></tr><tr><td>小米公司(ID:1771925961)</td><td style="text-align:left">7964</td><td style="text-align:left">2011/02/28 - 2016/08/05</td></tr><tr><td>TCL通讯中国(ID:1807956030)</td><td style="text-align:left">7376</td><td style="text-align:left">2011/01/01 - 2016/08/14</td></tr><tr><td>OPPO(ID:1710173801)</td><td style="text-align:left">6168</td><td style="text-align:left">2010/03/22 - 2016/08/09</td></tr><tr><td>华为中国区(ID: 2557129567)</td><td style="text-align:left">6046</td><td style="text-align:left">2012/02/10 - 2016/08/1</td></tr><tr><td>HTC官方微博(ID: 1890174912)</td><td style="text-align:left">5917</td><td style="text-align:left">2010/11/28 - 2016/08/10</td></tr><tr><td>魅族科技(ID: 2683843043)</td><td style="text-align:left">3618</td><td style="text-align:left">2014/02/17 - 2016/08/07</td></tr></tbody></table><ul><li><strong>参数实验结果</strong></li></ul><ol><li>Word2vec 参数实验结果:</li></ol><p><img src="https://upload-images.jianshu.io/upload_images/5274272-c4de7d6a13f7958b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Word2vec 参数实验"></p><ol start="2"><li>触发器参数实验结果</li></ol><p>a. 高频动词影响结果:</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-361a35e926962e70.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="前top个高频动词"></p><p>b.相似度阈值以及触发器影响结果:</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-b642d561b684b40e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="相似度阈值以及触发器效果"></p><ol start="3"><li>分类器参数实验</li></ol><p>a. 分类器阈值实验结果:<br><img src="https://upload-images.jianshu.io/upload_images/5274272-e21fa1837b571482.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="分类器阈值"></p><ul><li><strong>分类预测效果</strong></li></ul><p>为了验证我们提出的企业行为识别模型的有效性,我们比较了其他四种方法,这四种方法分别是词袋(Bag of words,简称BOW),TFIDF(term frequency–inverse document frequency)+BOW、TFIDF加权以及LDA(Latent Dirichlet Allocation)。</p><p>对比他们的召回率、准确率和F_value得到如下结果:<br><img src="https://upload-images.jianshu.io/upload_images/5274272-c6e8d5de12c2fb9c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="方法对比"></p><p>从上图可以明显看出,我们的模型优于其他方法。</p><hr><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>后续企业行为事件挖掘会从企业行为演化角度分析,从而研究每个企业不同企业行为的演化过程,包括某一企业的行为对比演化分析,每一个行为不同企业的对比分析。</p><p><strong>关于这个主题,我在中文信息学报发表了文章《基于社交媒体的企业行为事件挖掘》</strong></p><p>引用❤️:<br><strong>邓文君, 袁华, 钱宇. 基于社交媒体的企业行为事件挖掘[J]. 中文信息学报, 2018, 32(10).</strong></p>]]></content>
<categories>
<category> 案例分析 </category>
</categories>
<tags>
<tag> event </tag>
<tag> social media </tag>
</tags>
</entry>
<entry>
<title>详述机器学习中的损失函数</title>
<link href="/2019/02/25/%E8%AF%A6%E8%BF%B0%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E7%9A%84%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/"/>
<url>/2019/02/25/%E8%AF%A6%E8%BF%B0%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E7%9A%84%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/</url>
<content type="html"><![CDATA[<hr><table><thead><tr><th style="text-align:left">Class</th><th style="text-align:left">Content</th></tr></thead><tbody><tr><td style="text-align:left">layout</td><td style="text-align:left">post</td></tr><tr><td style="text-align:left">title</td><td style="text-align:left">详解机器学习中的损失函数</td></tr><tr><td style="text-align:left">categories</td><td style="text-align:left">Blog</td></tr><tr><td style="text-align:left">description</td><td style="text-align:left">机器学习中常见的损失函数以及它们的特点和适用场景</td></tr><tr><td style="text-align:left">keywords</td><td style="text-align:left">机器学习 损失函数 风险函数</td></tr></tbody></table><hr><h4 id="1-前言"><a href="#1-前言" class="headerlink" title="1. 前言"></a>1. 前言</h4><p>我们知道机器学习的三要素是:方法= 模型+策略+算法, 如何从假设空间中选择最优模型,这涉及到我们需要用什么样的准则进行学习,这就是三要素中的”策略”问题。</p><p>在假设空间中选择模型$y(x_n,w)$作为决策函数,给定输入$x_n$,由模型得到输出$y(x_n,w)$,而预测的$y(x_n,w)$与真实值$t_n$之间可能不一致,如图1-1 可以看出预测值$y(x_n,w)$与真实值$t_n$存在不一致情况,他们之间的差的绝对值为$|y(x_n,w)-t_n|$为绿色线部分, 而损失函数是定义在单个样本上的,算的是一个样本的误差。因此选用损失函数来度量预测误差。<br><img src="https://upload-images.jianshu.io/upload_images/5274272-1cf03d36a2499644.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-1 预测值与真实值的误差"></p><p>损失函数(loss function)是用来度量模型的预测值与真实值的不一致程度,是一个非负实值函数,损失函数越小,预测正确程度越高,表示为:$$L(y_i,f(x_i))$$</p><ul><li><p>损失函数是<strong>经验风险函数</strong>的核心部分,也是<strong>结构风险函数</strong>重要组成部分。模型的<strong>结构风险函数包括了经验风险项和正则项</strong>,可以表示为:$$R_{srm}(f)= \frac{1}{N}\sum_{i=1}^NL(y_i,f(x_i))+\lambda J (f)$$<br>这个公式为结构风险函数,其中,包括前一部分的经验风险项以及后一部分的正则化项,正则化项用于控制模型复杂度,$\lambda$则是用于权衡经验风险和模型复杂度之间的关系.<br>所以,通过最小化结构风险的策略找到最优模型,求解最优模型就是求解如下最优化问题:$$min_{f\in\digamma}\frac{1}{N}\sum_{i=1}^NL(y_i,f(x_i))+\lambda J(f)$$</p></li><li><p>当然,除了让结构风险最小化寻找最优模型外,还可以直接最小化经验风险,即<br>$$min_{f\in\digamma}\frac{1}{N}\sum_{i=1}^NL(y_i,f(x_i))$$<br>在样本足够的情况下,经验风险最小化可以达到很好的学习效果,但是样本容量有限时,容易产生过拟合现象,所以在才有上面结构风险最小化求最优模型的策略.</p></li></ul><hr><h4 id="2-区别损失函数-风险函数-代价函数-目标函数"><a href="#2-区别损失函数-风险函数-代价函数-目标函数" class="headerlink" title="2. 区别损失函数 风险函数 代价函数 目标函数"></a>2. 区别损失函数 风险函数 代价函数 目标函数</h4><ul><li><strong>损失函数</strong>:衡量单个样本预测值与真实值的误差【不赘述】.</li><li><strong>代价函数</strong>:定义在训练集上,是模型关于训练集的平均损失,它也叫经验风险,表示为:$$\frac{1}{N}\sum_{i=1}^NL(y_i,f(x_i))$$</li><li><strong>风险函数</strong>:是指损失函数的期望,又叫期望损失,由于输入$X$和输出$Y$是随机变量,那么可求得联合分布$P(X,Y)$,所以可以表示为:$$R_{exp}(f)=E_p[L(Y,f(X))] = \int_{X,Y}L(y,f(x))p(x,y)dxdy$$</li><li><strong>目标函数</strong>:是一个更为广的概念,比如最小化结构风险求最优模型时,结构化风险函数就是目标函数,而最小化经验风险求最优模型时,经验风险函数就是目标函数,简单地讲,目标函数就是需要优化的函数。</li></ul><p><strong>Note:</strong></p><ul><li>a.通常,我们没有细分损失函数和代价函数,经常将两个概念混用。</li><li>b.由于$P(Y,X)$未知,所以风险函数无法计算,经验风险$R_{emp}(f)$是模型关于训练集的平均损失,<strong>根据大数定律,当样本容量$N$趋于无穷时,经验风险$R_{emp}(f)$趋于风险函数$R_{exp}(f)$</strong>,这也说明了训练集容量越大,选择的最优模型越逼近真实模型。</li></ul><hr><h4 id="3-常见的损失函数"><a href="#3-常见的损失函数" class="headerlink" title="3. 常见的损失函数"></a>3. 常见的损失函数</h4><ul><li><p><strong>(1) 0-1损失函数(Zero-one Loss)</strong><br>$$<br>L(y_i,f(x_i)) =<br>\begin{cases}<br>1, & \text{$y_i \neq f(x_i)$} \\<br>0, & \text{$y_i = f(x_i)$}<br>\end{cases} $$</p></li><li><p>0-1 损失函数简单易理解,<strong>用于分类</strong>,如果预测的标签和数据标注的标签一致,那么就为0,否则就为1,当然, 如果认为相等的要求太严苛,可以放宽要求,<strong>用于回归</strong>中,如果他们的绝对值小于某个阈值,即为0,否则为1,表示为<br>$$<br>L(y_i,f(x_i)) =<br>\begin{cases}<br>1, & \text{$|y_i-f(x_i)| \geq t$} \\<br>0, & \text{$|y_i-f(x_i)| < t$}<br>\end{cases} $$</p></li><li><p><strong>(2) 平方损失函数(Square Loss)</strong><br>$$L(y_i,f(x_i))=(y_i-f(x_i))^2$$<br>由于其计算的优越性,所以常常<strong>用于回归</strong>中, 权重由可以直接初始化,再通过梯度下降不断更新。</p></li><li><p><strong>举例说明</strong>,一个线性回归,假设输入有$n$个特征,为了方便表示用$n+1$表示输入向量为$x=[0,x_1,x_2,…,x_n]^T$,模型参数为$w=[w_0,w_1,…,w_n]^T$,那么线性回归的模型表示为$$f(x)=w_0+w_1x_1+,…,w_nx_n=w^Tx$$<br>那么它的代价函数可以表示为$$L(w,x)=\frac{1}{2N}\sum_{i=1}^N(y^{(i)}-w^Tx^{(i)})+\frac{\lambda}{2}||w||^2$$<br>注意:在这里都使用$\frac{1}{2}$的目的是方便在后续求导中计算,$\lambda$是正则项前面的参数。<br>对$w_i$求导:<br>$$\frac{dL(w,x)}{dw_i} = \frac{1}{N}\sum_{i=1}^N(y_i-w^Tx)x_i+\lambda<br>w_i$$<br>由于这是目标函数是一个有最小值的凸函数,所以是沿着梯度的反方向进行更新,表示为$$w_i = w_i -\eta\frac{dL(w,x)}{dw_i}$$<br>注:权重矩阵$w$最开始可以随机初始,再不断更新.</p></li><li><p><strong>(3) 绝对损失函数(Absolute loss)</strong><br>$$L(y_i,f(x_i))=|(y_i-f(x_i))|$$<br>绝对值损失函数也经常<strong>用于回归中</strong>,而用于分类就等价于0-1损失函数,在sklearn中有Huber损失函数,它是平方损失函数和绝对值损失函数的结合,详细介绍请参考 <a href="http://sklearn.apachecn.org/cn/stable/modules/ensemble.html#f2001" target="_blank" rel="noopener">[F2001]</a>,比较简单【不再赘述】。</p></li><li><p><strong>(4) 对数损失函数(Log Loss or Cross-entropy Loss)</strong><br>$$L(y_i,f(x_i))=-logP(y_i|x_i)$$<br>对数损失函数适<strong>用于逻辑回归</strong>,那什么是逻辑回归呢?<br><strong>举例说明:</strong>其实就是在线性回归的基础上增加了逻辑函数$h(x)= \frac{1}{1+e^{-x}}$,那么对于在线性回归基础上加上逻辑函数,则逻辑回归模型可以表示为$$p(1|w,x^{(i)})=h(f(x^{(i)}))=\frac{1}{1+e^{-f(x^{(i)})}}=\frac{1}{1+e^{-w^Tx^{(i)}}}$$<br>即上式表示,给定输入,该实例为类别1的概率,由于逻辑回归是二分类,所以为类别0的概率为$p(0|w,x^{(i)})=1-p(1|w,x^{(i)})$<br>而在逻辑回归中,由于提供了模型的概率估计,所以使用的损失函数为对数损失函数,表示如下:<br>$$<br>L(y^{(i)},f(x^{(i)})) =<br>\begin{cases}<br>-logp(1|w,x^{(i)}), & \text{$y^{(i)}=1$} \\<br>-log(1-p(w|x^{(i)})), & \text{$y^{(i)}=0$}<br>\end{cases} $$</p></li></ul><p>那么最终的代价函数可以表示为<br>$$L(w,x)=-\frac{1}{N}\sum_{i=1}^N \lbrace y^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})\rbrace<br>$$<br>接下来就从另外一个角度说明,已知逻辑回归模型表示为:$$p(1|w,x^{(i)})=h(f(x^{(i)}))=\frac{1}{1+e^{-f(x^{(i)})}}=\frac{1}{1+e^{-w^Tx^{(i)}}}$$<br>在模型的数学形式确定后,剩下的就是如何去求解模型中的参数$w$,而在已知模型和一定样本的情况下,估计模型的参数,在统计学中常用的是极大似然估计方法。即找到一组参数$w$,使得在这组参数下,样本数据的似然度(概率)最大.<br>对于逻辑回归模型,假定概率分布服从伯努利分布【0-1分布】,其概率质量函数PMF为:$f(x)=p^x(1-p)^{(1-x)}$,其中$x$只能取0或者1,那么似然函数可以表示:为$$L(w)=\prod_{i=1}^Np(y^{(i)}=1|w,x^{(i)})^{y^{(i)}}p(y^{(i)}=0|w,x^{(i)})^{1-y^{(i)}}$$<br>那么对上式取对数,得到对数似然函数为:<br>$$logL(w)=\sum_{i=1}^Ny^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})$$<br>则全体样本的代价函数为:<br>$$logL(w)=-\sum_{i=1}^N\lbrace y^{(i)}logp(y^{(i)}=1|w,x^{(i)})+(1-y^{(i)})logp(y^{(i)}=0|w,x^{(i)})\rbrace$$<br>由此可以看出<strong>对数损失函数与极大似然估计的对数似然函数本质上是等价的</strong>.</p><ul><li><strong>(5) 合页损失函数(Hinge Loss)</strong><br>$$L(m_i)=max(0,1-m_i(w))$$<br>铰链损失函数<strong>常用于支持向量机(SVM)中</strong>,它名字来源于它的损失函数图像为一个折线图像,如果模型分类正确,损失为0,否则损失为$1-m_i(w)$,在SVM损失函数表示为:$$L(y^{(i)},x^{(i)})=max(0,1-y^{(i)}f(x^{(i)}))$$,<br><strong>举例说明:</strong>在SVM中,最终的支持向量机的分类模型是能最大化分类间隔,又减少错误分类的样本数目,意味着一个好的支持向量机的模型,需要满足以上两个条件:<strong>1、最大化分类间隔,2、错误分类的样本数目</strong>。如图说明,$f(x^{(i)})$是预测值,且预测值在-1到1之间,$y^{(i)}$为目标值取值为-1或者1,如果分类正确,$L(y^{(i)},x^{(i)})=0$,如果分类错误,$L(y^{(i)},x^{(i)})=1-y^{(i)}f(x^{(i)})$,$\xi$是引入的松弛变量,错误分类的样本数目,就回到了损失函数的范畴。<br><img src="https://upload-images.jianshu.io/upload_images/5274272-cd3776e65ca5cbc4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="SVM分类">综上所述推导SVM的代价函数,最初的SVM优化函数如下: </li></ul><p>$$\begin{equation}<br> \mathop{\arg\min}_{(w,\xi_i)} | \frac{1}{2} \Vert w \Vert^2+C\sum_i\xi_i \\<br> \begin{cases}<br> & s.t.\quad \forall y^{(i)}f(x^{(i)}) \geq 0 \\<br> & \quad\quad\quad \xi_i \geq 0<br> \end{cases}<br>\end{equation}$$</p><p>将约束条件变形为$$\xi_i>1-y^{(i)}f(x^{(i)})$$<br>最终SVM的代价函数可以表示为:$$L(w,x^{(i)})=C \sum_{i=0}^{N}max(0,1-y^{(i)}f(x^{(i)}))+\frac{1}{2} \Vert w \Vert^2$$</p><ul><li><strong>(6) 指数损失函数(Exponential loss)</strong><br>$$L(y_i,f(x_i)) = exp(-y_if(x_i))$$指数损失函数,<strong>主要应用于 Boosting 算法中</strong><br>在Adaboost 算法中,经过$m$次迭代后,可以得到 $f_m(x^{(i)})$,表示为:$$f_m(x^{(i)})=f_{m−1}(x^{(i)})+α_mG_m(x^{(i)})$$<br>Adaboost 每次迭代时的目的都是找到最小化下列式子的参数$α$和$G$:<br>$$argmin_{(α,G)} \quad \sum_{i=1}^{N}exp(-y^i(f_{m−1}(x^{(i)})+αG(x^{(i)})))$$<br>易知,Adaboost应用了指数损失函数$L(y^i,f(x^i))=exp(-y^if(x^i))$<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4>看了很多资料和网页,结合自己的理解写出了这一篇博客,以前只知道有这些损失函数,并没有探讨过损失函数的适用性以及该如何去推导这些公式。继续加油O(∩_∩)O~~<br>如有问题联系<a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</a></li></ul>]]></content>
<categories>
<category> learning </category>
</categories>
<tags>
<tag> ML </tag>
<tag> loss function </tag>
<tag> cost function </tag>
</tags>
</entry>
<entry>
<title>统计学习方法基础概念</title>
<link href="/2019/02/25/%E7%BB%9F%E8%AE%A1%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/"/>
<url>/2019/02/25/%E7%BB%9F%E8%AE%A1%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/</url>
<content type="html"><![CDATA[<hr><table><thead><tr><th style="text-align:left">Class</th><th style="text-align:left">Content</th></tr></thead><tbody><tr><td style="text-align:left">layout</td><td style="text-align:left">post</td></tr><tr><td style="text-align:left">title</td><td style="text-align:left">第一章 统计学习方法概论</td></tr><tr><td style="text-align:left">categories</td><td style="text-align:left">Course</td></tr><tr><td style="text-align:left">description:</td><td style="text-align:left">李航 《统计学习方法》的学习, 主要介绍基本概念,详细叙述了监督学习,提出统计学习的三要素:模型\策略\算法\,另外还介绍了模型选择:包括正则化\交叉验证与学习的泛化能力,此外还介绍了生成模型和判别模型.</td></tr><tr><td style="text-align:left">keywords</td><td style="text-align:left">监督学习 模型三要素 模型选择 生成模型 判别模型</td></tr></tbody></table><hr><h4 id="统计学习"><a href="#统计学习" class="headerlink" title="统计学习"></a>统计学习</h4><p><strong>a. ~概念:</strong></p><p>又叫统计机器学习,人们提到的机器学习往往指统计机器学习, 它是利用<strong>计算机</strong>对数据<strong>构建的概论统计模型</strong>,并运行模型<strong>对新的数据进行预测和分析</strong></p><p><strong>b. ~特点:</strong><br>(1)平台[计算机及网络] ;<br>(2)对象:数据;<br><strong>(3)目的:分析和预测</strong>;<br>(4)中心:统计学习方法;<br>(5)多领域交叉[概率论\统计学\信息论\最优化\计算理论\计算机科学等]</p><p><strong>c. ~前提假设:</strong></p><p><strong>同一类数据具有一定的统计规律性</strong>[因为它具有统计规律,所以可以用概率统计的方法进行处理,eg 用随机变量描述数据的特征,概论分布描述数据的统计规律]</p><p><strong>d. ~方法:</strong> </p><p>统计学习方法可以分为: 监督学习\非监督学习\半监督学习\强化学习等</p><p><strong>e. 统计学习方法三要素:</strong></p><p><strong>方法 = 模型+策略+算法</strong></p><p><strong>模型</strong>: 这里不再赘述<br><strong>策略</strong>: 按照什么准则学习或者选择最优模型,引用了损失函数(loss function)与风险函数(risk function),详细介绍见博文《详解机器学习中的损失函数》.<br><strong>算法</strong>:学习模型的具体计算方法,根据学习策略从假设空间中选择最优模型,最后需要考虑用什么方法计算最优模型,转化为最优化问题,可能出现有显式的解析解,也可能需要用数值计算的方法进行求解.</p><p>注: 假设训练集和测试集数据是独立同分布产生的</p><p><strong>f. ~步骤:</strong></p><ul><li>得到一个有限的训练数据集合;</li><li>确定包含所有可能的模型的<strong>假设空间</strong>,即学习模型的集合; </li><li>确定模型选择的<strong>准则</strong>,即学习的策略; </li><li>实现<strong>求解最优模型的算法</strong>,即学习的算法;</li><li>通过学习选择最优模型; </li><li>利用学习的最优模型对新数据进行分析和预测.</li></ul><p><strong>g. ~重要性</strong> : 统计学习是处理海量数据最强有力的工具,是计算机智能化的有效手段.</p><hr><h4 id="监督学习"><a href="#监督学习" class="headerlink" title="监督学习"></a>监督学习</h4><p><strong>a. 监督学习概念:</strong></p><p>是统计学习的方法之一, 它是学习一个模型,使得模型能对任意给定的输入,对其相应的输出做出一个好的预测. [最好的判断方式是看它<strong>是否有标签</strong>]</p><p><strong>b. 输入空间\特征空间\输出空间:</strong></p><p>输入与输出所有可能的取值的集合称为输入空间与输出空间,通常输出空间小于输入空间.特征空间表示所有特征存在的空间,而模型实际上是定义在特征空间上的.</p><p><strong>c.训练集和测试集的表示:</strong></p><p> $X$表示输入随机变量,$Y$表示输出随机变量,$x$和$y$是定义在输入和输出空间上随机变量的取值.<br><strong>训练集</strong>: $Train=\lbrace(x_1,y_1),(x_2,y_2),…,(x_n,y_n)\rbrace$<br><strong>测试集</strong>: $Test={(x_{1}^\ast,y_{1}^\ast),(x_{2}^\ast,y_{2}^\ast),…,(x_{n}^\ast,y_{n}^\ast)}$<br>输入和输出对又称为样本或样本点</p><p><strong>d. 不同预测任务的名称:</strong> </p><p>输入变量和输出变量均为连续的预测问题称为<strong>回归问题</strong>;输出变量为有限个离散变量的预测问题称为<strong>分类问题</strong>;输入变量和输出变量均为变量序列的预测问题被称为<strong>标注问题</strong>.</p><p><strong>注: 对于标注问题,目前还没有做过类似的项目,初步理解如下:</strong><br><strong>标注问题:</strong></p><ul><li>输入序列: $x_i = (x_{i}^{(1)},x_{i}^{(2)},…,x_{i}^{(n)})^T ,i = 1,…,N$</li><li>输出标记序列: $y_i = (y_{i}^{(1)},y_{i}^{(2)},…,y_{i}^{(n)})^T ,i = 1,…,N$<br>其中$n$为序列长度,不同的样本可以有不同的长度</li><li>条件概率分布为:$P(Y^{(1)},Y^{(2)},…,Y^{(n)}|X^{(1)},X^{(2)},…,X^{(n)})$</li><li>评价指标与分类问题的一致</li><li>常用的机器学习方法:隐马尔可夫模型\条件随机场等</li><li>应用场景:eg 自然语言词性标注.</li></ul><p>e. 监督学习的基本假设: <strong>监督学习假设输入和输出的随机变量$X$和$Y$遵循联合概率分布$P(X,Y)$</strong>,训练集和测试集被看做上依联合概率分布$P(X,Y)$独立同分布产生的.</p><p><strong>f. 假设空间:</strong></p><p>是指包含所有可能的模型的集合,以监督学习为例,假设空间包含所有可能的条件概率分布或决策函数, 它是有参数向量决定的函数族或者条件概率分布族,表示为<br>$\lbrace f|Y=f_\theta(X), \theta\in R^n\rbrace$ 或者 $\lbrace P|P(Y|X)), \theta\in R^n\rbrace$</p><p>而模型是输入到输出的映射,,学习的目的是找到最好的模型,所有假设空间就确定了学习范围.而监督学习的模型可以是概率模型($P(Y|X)$)也可以是非概率模型$Y=f(X)$,所以对于一特定的实例,输出预测为$P(y|x)$和$y=f(x)$.</p><p><strong>g. 监督学习形式化如下:</strong></p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-0cce7952ec884123.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-1 监督学习图"></p><p>阐释: 监督学习假设训练集和测试集都是依联合概率分布$P(X,Y)$独立同分布产生的.从训练集出发,学习系统先训练数据, 应用某个评价准则从假设空间里选择最佳的模型,使得模型对训练数据和新数据在给定的评价准则下有最优的预测,学习到的模型表示为$P(Y|X)$或者$Y=f(X)$,所以在预测过程,给定输入$x_{(n+1)}$,由模型得到$y_{(n+1)}^*$</p><hr><h4 id="模型评估与模型选择"><a href="#模型评估与模型选择" class="headerlink" title="模型评估与模型选择"></a>模型评估与模型选择</h4><p><strong>a. 训练误差\测试误差\泛化误差的概念:</strong></p><p>统计学习不仅要对训练数据有较好的拟合效果,还要对未知数据有较好的泛化能力. 对于给定的损失函数,基于损失函数的模型的训练误差[针对训练集]和模型的测试误差[针对测试集]是学习方法的评估标准. 测试误差反映模型对未知数据的预测能力,测试误差越小,预测能力,即泛化能力越强.</p><p>注: 1. 学习所采用的损失函数可以与预测采用的损失函数不同,但是一般是一致的.</p><ul><li>训练误差:$$R_{exp}(f) = \frac {1}{N}\sum_{i=1}^{N} L(y_i,y_i^*) $$<br>训练误差为模型$Y=f(X)$关于训练集的平均损失,$N$为训练样本容量</li><li>测试误差: $$R_{test}(f) = \frac {1}{N^{‘}}\sum_{i=1}^{N^{‘}} L(y_i,y_i^*) $$<br>测试误差为模型$Y=f(X)$关于测试集的平均损失,$N^{‘}$为训练样本容量</li><li>泛化误差: 泛化能力是指对未知数据的预测能力,而泛化误差反映了学习方法的泛化能力,泛化误差越小,方法越有效, <strong>它实际上就是模型的期望风险</strong>,可以表示为$$R_{exp}(f) = E_p[L(Y.f(X))]=\int_{X \times Y}L(y,f(x))P(x,y)$$</li></ul><p><strong>举例说明</strong><br>当损失函数为0-1损失时,测试误差为 $$e_{test} = \frac {1}{N^{‘}}\sum_{i=1}^{N^{‘}} I(y_i \neq y_i^\ast) $$ 其中$I$为指示函数,即$y_i \neq y_i^\ast$为1,否则为0.<br>相应地,测试集上的准确率为 $1-e_{test}$</p><p><strong>b. 过拟合和模型选择</strong></p><ul><li>模型选择: 由于假设空间含有不同复杂度的模型,模型选择的目的是选择尽可能最优的模型去逼近真模型.</li><li>过拟合: 为了追求训练集的预测能力,提高模型的复杂度[主要是模型包含过多参数],从而导致模型对<strong>训练集预测效果很好,对未知数据泛化能力很差</strong>.</li></ul><p><strong>举例说明:多项式曲线拟合</strong><br>给定一组训练集,表示为$T =\lbrace(x_1,y_1),(x_2,y_2),…,(x_N,y_N)\rbrace$, 对训练集我用下面的多项式进行拟合:<br>$$y^\ast(x,w)= w_0+w_1x+w_2x^2+…+w_Mx^M= \sum_{j=0}^Mw_j^{x_j}$$<br>$$L(w)=\frac{1}{2}\sum_{n=1}^N\lbrace(y^\ast(x_n,w)-y_n)\rbrace^2$$<br>其中$y^*(x_n,w)$是模型预测结果,$y^n$为原始的正确结果,通过最小二乘法可以求得拟合的多项式系数的唯一解.</p><p>拟合结果如(图1-2),图中给出了M=0,1,3,9的拟合效果,可以看出,当M=0时,多项式曲线是常数,拟合效果很差,M=1时,多项式曲线为直线,拟合效果依然很差,相反M=9,多项式曲线拟合了所以点.对于M=0和3的情况下,表现为欠拟合(即拟合不够), 而M=9为过拟合现象.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-76c6f77c05fa0acd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-2 不同阶数的多项式曲线,⽤红⾊曲线表⽰"></p><p>那么再看一下此时的训练误差和测试误差与模型复杂度关系如(图1-3),随着模型复杂度增加,训练误差和测试误差都先降低,但是随着复杂度变得更高的时候,训练误差变得更小甚至趋近于0,而测试误差陡然上升,此时出现了过拟合现象,模型对训练集过拟合,而对未知数据泛化能力下降.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-ad0a509d1f878c97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-3 预测误差与模型复杂度关系"><br>另外,我们在看一下参数与模型复杂度的关系, 随着模型复杂度增加$||w||$呈现增加趋势,这也是可以通过<strong>正则化控制模型过拟合</strong>的原因.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-b13906f0ccf143eb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-4 参数与模型复杂度关系"></p><p><strong>问题来了,那么如何防止过拟合呢?</strong></p><ul><li><strong>1. 增加训练集</strong><br>对于多项式曲线拟合的例子,通过增加训练集数量可以有效减缓过拟合, 可以看出N=15时,模型拟合效果很好,而增加数据,模型难以将每一个数据的都拟合到,所以增加训练集数量可以有效防止过拟合.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-0e3aa8f40386f5a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-5 增加数据集减缓过拟合"></li><li><p><strong>2. 正则化</strong><br>正则化是指在<strong>经验风险</strong>的基础上加上<strong>正则化项</strong>,正则化项可以取不同的形式,可以是参数向量的$L_2$范数,也可以是$L_1$范数,但是一般来说,<strong>正则化项是模型复杂度单调递增函数</strong><br>$$L(w)=\frac{1}{2}\sum_{n=1}^N\lbrace(y^\ast(x_n,w)-y_n)\rbrace^2+\frac{\lambda}{2}||w||^2$$<br>其中,公式前一部分是经验风险,公式后一部分$\frac{\lambda}{2}||w||^2$是正则化项,$||w||^2= w^Tw=w_0^2+w_1^2+…+w_M^2$,通常,系数$w_0$从正则化项中省略,因为包含$w_0$会使得结果依赖于⽬标变量原点的选择,<br>(Hastie et al., 2001), 而$\lambda$的作用是调节经验风险和正则化项关系的系数,而<strong>正则化的作用是选择经验风险和模型复杂度都较小的模型</strong><br>下图是M=9的模型,利用正则抑制过拟合的例子,图左通过加入正则化项,于$\ln\lambda$ = −18,过拟合现象被压制,而图右$\lambda$过大未能调节好经验风险和正则化项关系,模型拟合效果也差.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-fdc11c80f25065f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-6 M=9正则抑制过拟合"><br>⽤M = 9的多项式拟合,拟合的多项式的对应的系数在表1.7中给出,表明正则<br>化在减⼩系数的值⽅⾯产⽣了预期的效果.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-af4bbf5000e198c9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-7 λ控制参数"><br><strong>但是$\lambda$该取值多少呢?</strong><br>可以从下图1-8看出,$\lambda$控制了模型的复杂性,因此决定了过拟合的程度.<br><img src="https://upload-images.jianshu.io/upload_images/5274272-d0992528955d1496.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="1-8. 不同λ训练误差和测试误差的变化"><br>总结: 在损失函数中加入正则项可以有效避免过拟合,而正则项的$\lambda$决定了过拟合程度,因为起为高参,需要做参数实验取得最佳值.而从贝叶斯估计的角度看,正则化项对应于模型的先验概率,复杂的模型先验概率小,简单的模型先验概率大.</p></li><li><p><strong>3. 交叉验证</strong><br>交叉验证的基本思想是重复使用数据,把给定的数据切分成为训练集和测试集,在此基础上反复进行训练]测试以及模型选择.</p></li></ul><p><strong>详细的交叉验证方法以及如何交叉验证见博客《简述机器学习中模型评估方法》</strong></p><hr><h4 id="生成模型和判别模型"><a href="#生成模型和判别模型" class="headerlink" title="生成模型和判别模型"></a>生成模型和判别模型</h4><p>监督学习模型可以分为两种:生成模型(generative model)和判别模型(discriminative model).</p><ul><li>生成模型:由于模型给定了输入$X$和输出$Y$的关系,所以学习到联合概率分布P(X,Y),然后求出条件概率分布$P(Y|X)$作为预测,eg 朴素贝叶斯\隐马尔可夫模型.<br>生成模型表示为:$$P(Y|X)=\frac{P(X,Y)}{P(X)}$$</li><li>判别模型:由数据直接学出决策函数$f(X)$或者条件概率分布$P(Y|X)$,只关心给定输入$X$预测输出$Y$,eg.K-近邻\感知机\决策树\最大熵\SVM等.</li></ul><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>本章主要介绍了机器学习的基本概念,详细讲解了监督学习,训练误差\预测误差\泛化误差,生成模型和判别模型等,文章框架依据李航《统计学习方法》第一章而来,准备地说,是自己对其的归纳和简述,同时举例参考bishop的经典《模式识别和机器学习》书籍.</p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> ML </tag>
<tag> 模型评估 </tag>
<tag> 监督学习 </tag>
<tag> 生成模型 </tag>
<tag> 判别模型 </tag>
</tags>
</entry>
<entry>
<title>简述机器学习中模型评估方法</title>
<link href="/2019/02/25/%E7%AE%80%E8%BF%B0%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0%E6%96%B9%E6%B3%95/"/>
<url>/2019/02/25/%E7%AE%80%E8%BF%B0%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0%E6%96%B9%E6%B3%95/</url>
<content type="html"><![CDATA[<hr><table><thead><tr><th style="text-align:left">Class</th><th style="text-align:left">Content</th></tr></thead><tbody><tr><td style="text-align:left">layout</td><td style="text-align:left">post</td></tr><tr><td style="text-align:left">title</td><td style="text-align:left">简述机器学习中模型的评估方法</td></tr><tr><td style="text-align:left">categories</td><td style="text-align:left">Blog</td></tr><tr><td style="text-align:left">description</td><td style="text-align:left">模型评估方法主要用于对模型的泛化误差进行评估进而选择最优模型,主要的方法有留出法、S折交叉验证法、自助法</td></tr><tr><td style="text-align:left">keywords</td><td style="text-align:left">留出法 交叉验证法 自助法,以及对应的代码</td></tr></tbody></table><hr><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>机器学习的模型选择指如何从假设空间中选择泛化能力最大的模型,增加训练数据集、加正则项都能有效地抑制过拟合现象,而在实际应用中数据是不充足的,为了选择最优的模型还可以通过交叉验证方法。</p><p><strong>交叉验证的思想:</strong>重复使用给定的数据,把给定的数据切分为训练集和测试集,在此基础上反复地进行训练、测试以及模型选择。</p><p>当然,如果样本数量充足,可以随机地把数据切分成三部分:训练集用来训练模型,验证集用于模型选择合调参,测试集对最终模型的评估。</p><h4 id="主要方法"><a href="#主要方法" class="headerlink" title="主要方法"></a>主要方法</h4><p><strong>1. 留出法(简单交叉验证)</strong><br>方法:随机将样本分为测试集和训练集,然后用训练集训练模型,得到训练模型之后,在测试集上评价各个模型的测试误差,再选择测试误差最小的模型。</p><p><strong>Note:</strong><br>a. <strong>训练集和测试集的划分尽量保持数据分布的一致性</strong>,避免因为数据划分过程引入额外的偏差,例如在多分类时至少保证样本的类别比例相似,从采样的角度来看待数据划分,采样方式被称为“分层采样”。<br>b. <strong>使用留出法一般采用若干次随机划分、重复实验评估取平均值</strong>,单次使用留出法结果往往不够稳定。<br><figure class="highlight stata"><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></pre></td><td class="code"><pre><span class="line">def simple_cross(item, <span class="keyword">label</span>, k):</span><br><span class="line"> <span class="string">""</span>"</span><br><span class="line"> 对每类标签随机抽取相同的个数构造成测试集,样本中剩余的数据为训练集,要求数据为数据框结构,且标签的column为<span class="string">"Label"</span></span><br><span class="line"> :param item: <span class="keyword">sample</span> data</span><br><span class="line"> :param <span class="keyword">label</span>:data <span class="keyword">type</span> of <span class="keyword">list</span>. 标签名称列表,eg <span class="keyword">label</span>=[1,2,3,4,5,6]</span><br><span class="line"> :param k: <span class="keyword">sample</span> number of each <span class="keyword">label</span>. 每类标签的数量</span><br><span class="line"> :<span class="keyword">return</span>: train and <span class="keyword">test</span> data</span><br><span class="line"> <span class="string">""</span>"</span><br><span class="line"> label_indexs, all_indexs = {}, []</span><br><span class="line"> <span class="keyword">for</span> _i <span class="keyword">in</span> <span class="keyword">label</span>:</span><br><span class="line"> label_indexs[_i] = []</span><br><span class="line"> <span class="keyword">for</span> index <span class="keyword">in</span> item.index:</span><br><span class="line"> label_indexs[item.ix[index, <span class="string">"Label"</span>]].<span class="keyword">append</span>(index)</span><br><span class="line"> <span class="keyword">for</span> value <span class="keyword">in</span> label_indexs.values():</span><br><span class="line"> all_indexs.extend(random.<span class="keyword">sample</span>(value, k=k))</span><br><span class="line"> test_data = item.ix[all_indexs, ]</span><br><span class="line"> train_data = item.<span class="keyword">drop</span>(all_indexs)</span><br><span class="line"> <span class="keyword">return</span> train_data, test_data</span><br></pre></td></tr></table></figure></p><p><strong>2. S折交叉验证</strong><br>方法:随机将样本拆分成<strong>S</strong>个互不相交大小相同的子集,然后用<strong>S-1</strong>个子集作为训练集训练模型,用剩余的子集测试模型,对<strong>S</strong>中选择重复进行,最终选出<strong>S</strong>次测评中的平均测试误差最小的模型。</p><p><strong>Note:</strong><br>a. 这种方法用得最多,而交叉验证评估结果的稳定性很大程度取决于S.<br>b. 与留出法类似,划分为S折存在多种方式,所以为了减小样本划分不同而引入的误差,通常随机使用不同的划分重复P次,即为<strong>P次S折交叉验证</strong><br><figure class="highlight vim"><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></pre></td><td class="code"><pre><span class="line">def S_cross(item, S):</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> 将样本数据分为K-折,再将训练集和测试集组合成<span class="keyword">k</span>组返回.train_test为<span class="keyword">list</span>类型以元组形式表示</span><br><span class="line"> 例如[(test1,train1),(test2,train2),(test3,train),(test4.train4)],注意获取S组训练集和测试集</span><br><span class="line"> :param item: sample data</span><br><span class="line"> :<span class="keyword">return</span>: S-折 train <span class="built_in">and</span> test data</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> item = shuffle(item)</span><br><span class="line"> <span class="keyword">k</span> = math.<span class="built_in">floor</span>(<span class="built_in">len</span>(item) / S)</span><br><span class="line"> train_test = []</span><br><span class="line"> item_indexs = [item.<span class="built_in">index</span>[i:i + <span class="keyword">k</span>, ] <span class="keyword">for</span> i in <span class="built_in">range</span>(<span class="number">0</span>, <span class="built_in">len</span>(item.<span class="built_in">index</span>)-<span class="keyword">k</span>, <span class="keyword">k</span>)]</span><br><span class="line"> <span class="keyword">for</span> test_index in item_index<span class="variable">s:</span></span><br><span class="line"> train_test.<span class="keyword">append</span>((item.<span class="keyword">loc</span>[test_index], item.<span class="keyword">drop</span>(test_index)))</span><br><span class="line"> <span class="keyword">return</span> train_test</span><br></pre></td></tr></table></figure></p><p><strong>留一法</strong><br>方法:它是S折交叉验证的特殊情况,S=N,其中N为数据容量,划分样本方式唯一。<br>注:<br>a. <strong>数据缺乏时使用</strong>,当数据集很大时,<strong>计算开销很大</strong>。<br>b. 由于测试集只有一个样本,<strong>所以模型因样本规模不同而导致的估计偏差比前两种小</strong>。</p><p><strong>自助法</strong><br>方法:以自助采样为基础,对m个样本数据随机挑选1个,放回后再随机挑选1个,重复m次,这样得到了与样本规模一样大小的训练集,测试集中有一部分样本多次出现,有一部分样本不出现,可以做一个简单估计,样本在m次采样中始终没有被采样的$$\lim\limits_{n \rightarrow +\infty} (1-\frac{1}{m})^m \rightarrow \frac{1}{e} \approx 0.368$$,即大约36.8%的样本未出现在训练集中,未出现在训练集中的样本组合成测试集。</p><p><strong>Note:</strong><br>a. <strong>自助法在数据较小,难以划分测试集和训练集时有用</strong>,从初始数据集中产生多个不同的训练集,这对集成学习等方法有很多好处。<br>b.<strong>缺点:自助法产生的数据集改变了初始数据集的分布,引入估计误差。</strong><br><figure class="highlight vim"><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></pre></td><td class="code"><pre><span class="line">def bootstraping(item):</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> 自助法采样.对数据进行M=<span class="built_in">len</span>(item.<span class="built_in">index</span>)有放回采样.最后得到M个训练集,未被采样到的作为测试集</span><br><span class="line"> :param item:sample data</span><br><span class="line"> :<span class="keyword">return</span>:训练集和测试集</span><br><span class="line"> <span class="string">""</span><span class="comment">"</span></span><br><span class="line"> train_indexs = np.random.choice(item.<span class="built_in">index</span>, size=<span class="built_in">len</span>(item.<span class="built_in">index</span>), replace=True)</span><br><span class="line"> train_data = item.<span class="keyword">loc</span>[train_indexs, ]</span><br><span class="line"> test_data = item.<span class="keyword">drop</span>(<span class="keyword">list</span>(<span class="keyword">set</span>(item.<span class="built_in">index</span>) - <span class="keyword">set</span>(train_indexs)))</span><br><span class="line"> <span class="keyword">return</span> train_data, test_data</span><br></pre></td></tr></table></figure></p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>划分训练集和测试是机器学习的基础,在这些划分方法中最常用的就是S折交叉验证,为了以后使用方便,我附带了实现函数.</p><p>如有疑问,联系<a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</a></p>]]></content>
<categories>
<category> 统计学习方法 </category>
</categories>
<tags>
<tag> ML </tag>
<tag> python </tag>
<tag> 模型评估 </tag>
</tags>
</entry>
<entry>
<title>基于Kmean聚类分析航空公司客户价值</title>
<link href="/2019/02/25/%E5%9F%BA%E4%BA%8EKmean%E8%81%9A%E7%B1%BB%E5%88%86%E6%9E%90%E8%88%AA%E7%A9%BA%E5%85%AC%E5%8F%B8%E5%AE%A2%E6%88%B7%E4%BB%B7%E5%80%BC/"/>
<url>/2019/02/25/%E5%9F%BA%E4%BA%8EKmean%E8%81%9A%E7%B1%BB%E5%88%86%E6%9E%90%E8%88%AA%E7%A9%BA%E5%85%AC%E5%8F%B8%E5%AE%A2%E6%88%B7%E4%BB%B7%E5%80%BC/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: 基于Kmean聚类分析航空公司客户价值<br>categories: Case<br>description: 利用无监督方法–聚类分析客户价值<br>keywords: 聚类,客户价值分析</p><hr><p>利用无监督方法–聚类分析客户价值</p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>这次的分析课题是我研究生课程数据分析与决策的小组作业,首先感谢我的小伙伴们。<br>这一次数据分析完全是以研究问题驱动,也是我们几次小组讨论之后的结果。在拿到数据《某航空公司客户数据》时,我们计划以一个完整的数据挖掘流程去挖掘数据中的商业价值。流程如下:</p><hr><h5 id="数据预处理-gt-聚类探索-gt-数据可视化-gt-航空公司客户价值分析"><a href="#数据预处理-gt-聚类探索-gt-数据可视化-gt-航空公司客户价值分析" class="headerlink" title="数据预处理->聚类探索->数据可视化->航空公司客户价值分析"></a>数据预处理->聚类探索->数据可视化->航空公司客户价值分析</h5><hr><p>我们因为我主要负责实现客户聚类以及分析,所有还是打算把它写成一个完整的案例。</p><h3 id="建模"><a href="#建模" class="headerlink" title="建模"></a>建模</h3><h4 id="1-基础模型-RFM"><a href="#1-基础模型-RFM" class="headerlink" title="1.基础模型(RFM)"></a>1.基础模型(RFM)</h4><p>基于客户价值分析有一个基础模型,即RFM模型(如下图1-1:RFM模型), RFM是衡量客户价值和客户创利能力的重要工具和手段。在众多的客户关系管理(CRM)的分析模式中,RFM模型是被广泛使用的。该模型通过一个客户的近期购买行为、购买的总体频率以及花了多少钱3项指标来描述该客户的价值状况,从而识别高价值的客户,即:<br>Recency: 最近消费时间间隔<br>Frequency: 消费频率<br>Monetary: 消费金额</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-1b4941d43a457826.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="2018-05-01-1.png"></p><p>结合RFM模型我们选取了原始数据中的三个属性值[平均乘机间隔:AVG_INTERVAL,观测窗口内的飞行次数:FLIGHT_COUNT,总票价:SUM_PRICE]三个指标对用户进行聚类,其中总票价是一个新生成的特征:由两年票价总和而来,最终将客户聚为5类。对于RFM模型的聚类结果的类中心(如表1-1:RFM模型聚类的类中心)如下:<br>表1-1:RFM模型聚类的类中心</p><table><thead><tr><th style="text-align:center">Category</th><th style="text-align:center">AVG_INTERVAL</th><th style="text-align:center">FLIGHT_COUNT</th><th style="text-align:center">SUM_PRICE</th></tr></thead><tbody><tr><td style="text-align:center">C_1</td><td style="text-align:center">71.59704</td><td style="text-align:center">9.454219</td><td style="text-align:center">71189422</td></tr><tr><td style="text-align:center">C_2</td><td style="text-align:center">12.11986</td><td style="text-align:center">94</td><td style="text-align:center">1.29E+11</td></tr><tr><td style="text-align:center">C_3</td><td style="text-align:center">18.15115</td><td style="text-align:center">47.36056</td><td style="text-align:center">2.55E+09</td></tr><tr><td style="text-align:center">C_4</td><td style="text-align:center">7.213259</td><td style="text-align:center">108.8333</td><td style="text-align:center">2.55E+09</td></tr><tr><td style="text-align:center">C_5</td><td style="text-align:center">19.92913</td><td style="text-align:center">113.5</td><td style="text-align:center">2.14E+11</td></tr></tbody></table><p>通过对类中心进行列项归一化(归一化的方法为线性转换:y=(x-MinValue)/(MaxValue-MinValue)),然后基于归一化后的数据画出了雷达图(如图1-2:RFM模型的雷达图)。</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-44f0958840261762.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="2018-05-01-2.png"></p><p>从图中可以看到,每一类人数分别是:C_1:54292人,C_2:6人,C_3:3943人,C_4:32,C_5:2两人,从数据和图中可以看出,单纯依靠RFM三个指标分出的5类用户效果不佳,不仅每一类的人数分布差异很大,且C_2,C_5重叠很大。</p><hr><h4 id="2-拓展模型-1(LRFMC)"><a href="#2-拓展模型-1(LRFMC)" class="headerlink" title="2. 拓展模型-1(LRFMC)"></a>2. 拓展模型-1(LRFMC)</h4><p>虽然RFM模型可以衡量客户价值,但是对于这次的航空数据集,在聚类之后对于刻画不同的用户价值的效果并不理想,所以基于RFM模型可能不合适。由于同样的消费金额的不同旅客对航空公司的价值不同,例如买长航线、低等仓的旅客和买短航线、高等仓的旅客消费金额相同,但是价值却是不同的。显然后者更有价值。所以进一步地,选择客户在一定时间内的飞行里程M和乘坐舱位所对应的折扣系数C。同时,因为航空公司会员的加入时间一定程度上可以影响客户价值,所以我们在航空公司客户价值分析模型中添加客户关系长度 L,作为区分客户价值的另一个指标,所以我们构建出LRFMC 模型。</p><hr><p>L:会员入会时间距观测窗口结束的时间(TIME_INTERVAL)<br>R:客户最近一次乘坐公司分级距观测窗口结束的时间(月数)(LAST_TO_END)<br>F:客户在观测窗口内乘坐公司飞机的次数(FLIGHT_COUNT)<br>M:客户在观测窗口内累计的飞行里程(SEG_KM_SUM)<br>C:客户在观测窗口内乘坐舱位所对应的折扣系数的平均值(avg_discount)</p><hr><p>在LRFMC模型中,我们选择的特征包括了五类,分别是时间间隔:TIME_INTERVAL, 观测窗口内的飞行次数:FLIGHT_COUNT, 观测窗口总飞行公里数SEG_KM_SUM, 平均折扣率:avg_discount, 最后一次乘机时间至观测窗口结果时长(月)LAST_TO_END,其中时间间隔为会员入会时间距观测窗口结束的时间,聚类结果如下(表2-1 LRFMC聚类模型的类中心).</p><p>表2-1 LRFMC聚类模型的类中心</p><table><thead><tr><th style="text-align:center">Category</th><th style="text-align:center">TIME_INTERVAL</th><th style="text-align:center">FLIGHT_COUNT</th><th style="text-align:center">SEG_KM_SUM</th><th style="text-align:center">avg_discount</th><th style="text-align:center">LAST_TO_END</th></tr></thead><tbody><tr><td style="text-align:center">C_1</td><td style="text-align:center">1941.1565</td><td style="text-align:center">51.8939</td><td style="text-align:center">81022.5</td><td style="text-align:center">0.78842</td><td style="text-align:center">27.4025</td></tr><tr><td style="text-align:center">C_2</td><td style="text-align:center">1537.4712</td><td style="text-align:center">15.1758</td><td style="text-align:center">21362.8</td><td style="text-align:center">0.72559</td><td style="text-align:center">97.5557</td></tr><tr><td style="text-align:center">C_3</td><td style="text-align:center">1730.7709</td><td style="text-align:center">30.1751</td><td style="text-align:center">44550.5</td><td style="text-align:center">0.75299</td><td style="text-align:center">49.7244</td></tr><tr><td style="text-align:center">C_4</td><td style="text-align:center">1352.2401</td><td style="text-align:center">4.97864</td><td style="text-align:center">6373.01</td><td style="text-align:center">0.70832</td><td style="text-align:center">231.587</td></tr><tr><td style="text-align:center">C_5</td><td style="text-align:center">2130.6303</td><td style="text-align:center">76.5931</td><td style="text-align:center">152434.</td><td style="text-align:center">0.84164</td><td style="text-align:center">19.4043</td></tr></tbody></table><p>通过对LRFMC聚类结果的类中心进行归一化,我们得到了如下雷达图(图2-1: LRFMC模型雷达图):</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-404e1d4cc7946f3b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="2018-05-01-3.png"></p><p>通过对上图进行观察和分析,我们知道每一类别人数分别为:C_1:1867,C_2:14887,C_3:5831,C_4:35294,C_5:376, 其中C_5在时间间隔、观测窗口内的飞行次数、观测窗口总飞行公里数、平均折扣率、四个维度都比C_1、C_3、C_2更大,在最后一次乘机时间至观测窗口结果时长(月)这个维度上,C_4>C_2>C_3>C_1>C_5,根据雷达图的性质,面积越大,它的价值越大,所以价值大小排序为:C_5>C_1>C_3>C_2>C_4,依据客户价值排序我们可以将其分为重要保持客户、重要发展客户、重要挽留客户、普通价值客户、低价值客户:<br>表2-2:LRFMC模型的客户价值关系</p><table><thead><tr><th style="text-align:center">Category</th><th style="text-align:center">Value Rating</th><th style="text-align:center">Headcount</th><th style="text-align:center">客户价值</th></tr></thead><tbody><tr><td style="text-align:center">C_1</td><td style="text-align:center">2</td><td style="text-align:center">1867</td><td style="text-align:center">重要发展客户</td></tr><tr><td style="text-align:center">C_2</td><td style="text-align:center">4</td><td style="text-align:center">14887</td><td style="text-align:center">普通价值客户</td></tr><tr><td style="text-align:center">C_3</td><td style="text-align:center">3</td><td style="text-align:center">5831</td><td style="text-align:center">重要挽留客户</td></tr><tr><td style="text-align:center">C_4</td><td style="text-align:center">5</td><td style="text-align:center">35294</td><td style="text-align:center">低价值客户</td></tr><tr><td style="text-align:center">C_5</td><td style="text-align:center">1</td><td style="text-align:center">376</td><td style="text-align:center">重要保持客户</td></tr></tbody></table><hr><h4 id="3-拓展模型-2(LRFMC-2P模型)"><a href="#3-拓展模型-2(LRFMC-2P模型)" class="headerlink" title="3 拓展模型-2(LRFMC+2P模型)"></a>3 拓展模型-2(LRFMC+2P模型)</h4><p>在模型LRFMC模型中我们已经将基于五个指标(LRFMC)将用户划分为五类价值客户分别是重要发展客户、重要保持客户、重要挽留客户、普通价值客户、低价值客户,从雷达图可以比较清晰地观测和分析出客户价值,为了进一步探究是否其他属性会对客户价值聚类有正向作用,我们在LRFMC模型基础上增加了总积分Points_Sum和总票价SUM_PRICE两个属性从而提出了LRFMC+2P模型,以生活检验我们知道,总积分和总票价越高,那么客户在平台的消费力也越大,价值显然更高,因此我们提出的LRFMC+2P模型的参数如下:</p><hr><p>L:会员入会时间距观测窗口结束的时间(TIME_INTERVAL)<br>R:客户最近一次乘坐公司分级距观测窗口结束的时间(月数)(LAST_TO_END)<br>F:客户在观测窗口内乘坐公司飞机的次数(FLIGHT_COUNT)<br>M:客户在观测窗口内累计的飞行里程(SEG_KM_SUM)<br>C:客户在观测窗口内乘坐舱位所对应的折扣系数的平均值(avg_discount)<br>2P: 客户在观测期的总积分和总票价(”Points_Sum”, “SUM_PRICE”)</p><hr><p>基于我们提出的LRFMC+2P模型,结合航空数据的属性,我们对其进行聚类分析,得到了相应的聚类结果,其中每类的类中心(表3-4:LRFMC+2P模型的类中心),同时,对类中心进行归一化处理,然后画出了7个属性的雷达图(如图3-4:LRFMC+2P模型的雷达图):<br>表3-1:LRFMC+2P模型的类中心</p><table><thead><tr><th style="text-align:center">Category</th><th style="text-align:center">TIME_INTERVAL</th><th style="text-align:center">FLIGHT_COUNT</th><th style="text-align:center">SEG_KM_SUM</th><th style="text-align:center">avg_discount</th><th style="text-align:center">LAST_TO_END</th><th style="text-align:center">Points_Sum</th><th style="text-align:center">SUM_PRICE</th></tr></thead><tbody><tr><td style="text-align:center">C_1</td><td style="text-align:center">1424.</td><td style="text-align:center">9.5</td><td style="text-align:center">13534.7</td><td style="text-align:center">0.71191</td><td style="text-align:center">181.5091</td><td style="text-align:center">9259.56</td><td style="text-align:center">72586528</td></tr><tr><td style="text-align:center">C_2</td><td style="text-align:center">2215.167</td><td style="text-align:center">94</td><td style="text-align:center">257112.</td><td style="text-align:center">1.11308</td><td style="text-align:center">20</td><td style="text-align:center">323501</td><td style="text-align:center">1.29E+1</td></tr><tr><td style="text-align:center">C_3</td><td style="text-align:center">1860.25</td><td style="text-align:center">109</td><td style="text-align:center">196685.</td><td style="text-align:center">1.07389</td><td style="text-align:center">6.583333</td><td style="text-align:center">249070.</td><td style="text-align:center">7.68E+1</td></tr><tr><td style="text-align:center">C_4</td><td style="text-align:center">1971.286</td><td style="text-align:center">47.6</td><td style="text-align:center">69385.5</td><td style="text-align:center">0.83994</td><td style="text-align:center">29.41255</td><td style="text-align:center">59803.9</td><td style="text-align:center">2.57E+1</td></tr><tr><td style="text-align:center">C_5</td><td style="text-align:center">1894</td><td style="text-align:center">114</td><td style="text-align:center">353033</td><td style="text-align:center">1.09407</td><td style="text-align:center">17.5</td><td style="text-align:center">393372</td><td style="text-align:center">2.14E+1</td></tr></tbody></table><p><img src="https://upload-images.jianshu.io/upload_images/5274272-042204d3231b8708.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="2018-05-01-4.png"></p><p>通过对雷达图进行观察和分析,以及依据雷达图性质,我们可以得到五类客户价值以及人数分布(表3-5:LRFMC+2P模型的客户价值关系),可以明显看出每类价值分布太不均衡,因而并不适合用户刻画用户价值。<br>表3-2:LRFMC+2P模型的客户价值关系</p><table><thead><tr><th style="text-align:center">Category</th><th style="text-align:center">Value Rating</th><th style="text-align:center">Headcount</th><th style="text-align:center">客户价值</th></tr></thead><tbody><tr><td style="text-align:center">C_1</td><td style="text-align:center">5</td><td style="text-align:center">54326</td><td style="text-align:center">低价值客户</td></tr><tr><td style="text-align:center">C_2</td><td style="text-align:center">2</td><td style="text-align:center">6</td><td style="text-align:center">重要发展价值</td></tr><tr><td style="text-align:center">C_3</td><td style="text-align:center">3</td><td style="text-align:center">12</td><td style="text-align:center">重要挽留客户</td></tr><tr><td style="text-align:center">C_4</td><td style="text-align:center">4</td><td style="text-align:center">3909</td><td style="text-align:center">普通价值客户</td></tr><tr><td style="text-align:center">C_5</td><td style="text-align:center">1</td><td style="text-align:center">2</td><td style="text-align:center">重要价值客户</td></tr></tbody></table><p>综合以上三个模型,LRFMC的模型更具有实用性,LRFMC模型选择的三个用户属性不仅可以较好刻画用户价值,且每类用户分布较为合理。</p><h3 id="代码附录"><a href="#代码附录" class="headerlink" title="代码附录"></a>代码附录</h3><figure class="highlight haxe"><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><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/env python</span></span><br><span class="line"><span class="meta"># -*- coding: utf-8 -*-</span></span><br><span class="line">from sklearn.cluster <span class="keyword">import</span> KMeans</span><br><span class="line"><span class="keyword">import</span> pandas as pd</span><br><span class="line"><span class="keyword">import</span> datetime</span><br><span class="line"><span class="keyword">import</span> numpy as np</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot as plt</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">def read_data(path):<span class="type"></span></span><br><span class="line"><span class="type"> return pd</span>.read_csv(path, sep=<span class="string">","</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Model</span>(<span class="title">object</span>):</span></span><br><span class="line"><span class="class"> <span class="title">def</span> __<span class="title">init__</span>(<span class="title">self</span>, <span class="title">k</span>):</span></span><br><span class="line"><span class="class"> <span class="title">self</span>.<span class="title">train_data</span> = <span class="title">None</span></span></span><br><span class="line"><span class="class"> <span class="title">self</span>.<span class="title">k_cluster</span> = <span class="title">k</span></span></span><br><span class="line"><span class="class"> <span class="title">self</span>.<span class="title">feature</span> = </span>{<span class="string">"feature_3"</span>: <span class="type"></span>[<span class="string">"AVG_INTERVAL"</span>, <span class="string">"FLIGHT_COUNT"</span>, <span class="string">"SUM_PRICE"</span>],</span><br><span class="line"> <span class="string">"feature_5"</span>: <span class="type"></span>[<span class="string">"TIME_INTERVAL"</span>, <span class="string">"FLIGHT_COUNT"</span>, <span class="string">"SEG_KM_SUM"</span>, <span class="string">"avg_discount"</span>, <span class="string">"LAST_TO_END"</span>],</span><br><span class="line"> <span class="string">"feature_7"</span>: <span class="type"></span>[<span class="string">"TIME_INTERVAL"</span>, <span class="string">"FLIGHT_COUNT"</span>, <span class="string">"SEG_KM_SUM"</span>, <span class="string">"avg_discount"</span>, <span class="string">"LAST_TO_END"</span>,</span><br><span class="line"> <span class="string">"Points_Sum"</span>, <span class="string">"SUM_PRICE"</span>]}</span><br><span class="line"></span><br><span class="line"> def <span class="keyword">new</span><span class="type">_train_data</span>(self):<span class="type"></span></span><br><span class="line"><span class="type"> new_train_data </span>= self.train_data.drop(<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"SUM_PRICE"</span>] = <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"SUM_YR_1"</span>] + <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"SUM_YR_2"</span>]</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"LOAD_TIME"</span>] = <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"LOAD_TIME"</span>].apply(lambda x: <span class="type">x</span>.split(<span class="string">"/"</span>))</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"FFP_DATE"</span>] = <span class="keyword">new</span><span class="type">_train_data</span>[<span class="string">"FFP_DATE"</span>].apply(lambda x: <span class="type">x</span>.split(<span class="string">"/"</span>))</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="keyword">new</span><span class="type">_train_data</span>.index:<span class="type"></span></span><br><span class="line"><span class="type"> year</span>, month, day = int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"LOAD_TIME"</span>][<span class="number">0</span>]), int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"LOAD_TIME"</span>][<span class="number">1</span>]), \</span><br><span class="line"> int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"LOAD_TIME"</span>][<span class="number">2</span>])</span><br><span class="line"> year_2, month_2, day_2 = int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"FFP_DATE"</span>][<span class="number">0</span>]), \</span><br><span class="line"> int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"FFP_DATE"</span>][<span class="number">1</span>]), int(<span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"FFP_DATE"</span>][<span class="number">2</span>])</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span>.ix[i, <span class="string">"TIME_INTERVAL"</span>] = (datetime.datetime(year, month, day) -</span><br><span class="line"> datetime.datetime(year_2, month_2, day_2)).days</span><br><span class="line"> features = []</span><br><span class="line"> <span class="keyword">for</span> item <span class="keyword">in</span> self.feature.values():<span class="type"></span></span><br><span class="line"><span class="type"> for fea in item</span>:</span><br><span class="line"> <span class="keyword">if</span> fea not <span class="keyword">in</span> features:<span class="type"></span></span><br><span class="line"><span class="type"> features</span>.append(fea)</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span> = <span class="keyword">new</span><span class="type">_train_data</span>.dropna()</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span>.to_csv(<span class="string">"../data/raw/target_data.csv"</span>, sep=<span class="string">","</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span><span class="type">_train_data</span></span><br><span class="line"><span class="type"></span></span><br><span class="line"><span class="type"></span> def cluster(self, target, label):<span class="type"></span></span><br><span class="line"><span class="type"> kmean_model </span>= KMeans(self.k_cluster)</span><br><span class="line"> kmean_model.fit(target)</span><br><span class="line"> <span class="keyword">return</span> [kmean_model.labels_, kmean_model.cluster_centers_]</span><br><span class="line"></span><br><span class="line"> def graph(self, cluster_result, label, key):<span class="type"></span></span><br><span class="line"><span class="type"></span></span><br><span class="line"><span class="type"> </span># 使用ggplot的绘图风格</span><br><span class="line"> plt.style.use(<span class="string">'ggplot'</span>)</span><br><span class="line"> r1 = pd.Series(cluster_result[<span class="number">0</span>]).value_counts() <span class="meta"># 统计各个类别的数目</span></span><br><span class="line"> r2 = pd.DataFrame(cluster_result[<span class="number">1</span>])</span><br><span class="line"> r2 = r2.apply(lambda x: <span class="type"></span>(x - np.min(x)) / (np.max(x) - np.min(x))) <span class="meta"># 找出聚类中心</span></span><br><span class="line"> <span class="meta"># 所有簇中心坐标值中最大值和最小值</span></span><br><span class="line"> max = r2.values.max()</span><br><span class="line"> min = r2.values.min()</span><br><span class="line"> r = pd.concat([r2, r1], axis=<span class="number">1</span>) <span class="meta"># 横向连接(0是纵向),得到聚类中心对应的类别下的数目</span></span><br><span class="line"> r.columns = label + [u<span class="string">'类别数目'</span>] <span class="meta"># 重命名表头</span></span><br><span class="line"></span><br><span class="line"> <span class="meta"># 绘图</span></span><br><span class="line"> fig = plt.figure(figsize=(<span class="number">10</span>, <span class="number">8</span>))</span><br><span class="line"> ax = fig.add_subplot(<span class="number">111</span>, polar=True)</span><br><span class="line"> center_num = r.values</span><br><span class="line"> feature = label</span><br><span class="line"> N = len(feature)</span><br><span class="line"> <span class="keyword">for</span> i, v <span class="keyword">in</span> enumerate(center_num):<span class="type"></span></span><br><span class="line"><span class="type"> </span># 设置雷达图的角度,用于平分切开一个圆面</span><br><span class="line"> angles = np.linspace(<span class="number">0</span>, <span class="number">2</span> * np.pi, N, endpoint=False)</span><br><span class="line"> <span class="meta"># 为了使雷达图一圈封闭起来,需要下面的步骤</span></span><br><span class="line"> center = np.concatenate((v[:<span class="type">-1</span>], [v[<span class="number">0</span>]]))</span><br><span class="line"> angles = np.concatenate((angles, [angles[<span class="number">0</span>]]))</span><br><span class="line"> <span class="meta"># 绘制折线图</span></span><br><span class="line"> ax.plot(angles, center, <span class="string">'o-'</span>, linew<span class="type">idth</span>=<span class="number">2</span>, label=<span class="string">"category_%d : %d"</span> % (i + <span class="number">1</span>, v[<span class="number">-1</span>]))</span><br><span class="line"> <span class="meta"># 填充颜色</span></span><br><span class="line"> ax.fill(angles, center, alpha=<span class="number">0.25</span>)</span><br><span class="line"> <span class="meta"># 添加每个特征的标签</span></span><br><span class="line"> ax.set_thetagrids(angles * <span class="number">180</span> / np.pi, feature, fontsize=<span class="number">15</span>)</span><br><span class="line"> <span class="meta"># 设置雷达图的范围</span></span><br><span class="line"> ax.set_ylim(min - <span class="number">0.1</span>, max + <span class="number">0.1</span>)</span><br><span class="line"> <span class="meta"># 添加标题</span></span><br><span class="line"> plt.title(<span class="string">'The '</span> + key +<span class="string">' of users'</span>, fontsize=<span class="number">20</span>)</span><br><span class="line"> <span class="meta"># 添加网格线</span></span><br><span class="line"> ax.grid(True)</span><br><span class="line"> <span class="meta"># 设置图例</span></span><br><span class="line"> plt.legend(loc=<span class="string">'upper right'</span>, bbox_to_anchor=(<span class="number">1.3</span>, <span class="number">1.0</span>), ncol=<span class="number">1</span>, fancybox=True, shadow=True)</span><br><span class="line"> <span class="meta"># 显示图形</span></span><br><span class="line"> plt.show()</span><br><span class="line"></span><br><span class="line"> @staticmethod</span><br><span class="line"> def combine_results(target_data, cluster_result, filename):<span class="type"></span></span><br><span class="line"><span class="type"> path </span>= <span class="string">"../data/results/"</span></span><br><span class="line"> <span class="keyword">new</span><span class="type">_data</span> = pd.DataFrame()</span><br><span class="line"> <span class="keyword">new</span><span class="type">_data</span>[<span class="string">"Cluster_Results"</span>] = pd.Series(cluster_result[<span class="number">0</span>], index=target_data.index)</span><br><span class="line"> <span class="keyword">new</span><span class="type">_data</span> = target_data.join(<span class="keyword">new</span><span class="type">_data</span>)</span><br><span class="line"> <span class="keyword">new</span><span class="type">_data</span>.to_csv(path + filename + <span class="string">"_cluster.csv"</span>, sep=<span class="string">","</span>)</span><br><span class="line"> cluster_center = pd.DataFrame(cluster_result[<span class="number">1</span>])</span><br><span class="line"> cluster_center.to_csv(path + filename + <span class="string">"_center.csv"</span>, sep=<span class="string">","</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span><span class="type">_data</span></span><br><span class="line"><span class="type"></span></span><br><span class="line"><span class="type"></span> def run(self):<span class="type"></span></span><br><span class="line"><span class="type"> self</span>.train_data = read_data(<span class="string">"../data/raw/new_data.csv"</span>)</span><br><span class="line"> <span class="keyword">new</span><span class="type">_train_data</span> = self.<span class="keyword">new</span><span class="type">_train_data</span>()</span><br><span class="line"> <span class="keyword">for</span> key, value <span class="keyword">in</span> self.feature.items():<span class="type"></span></span><br><span class="line"><span class="type"> cluster_result </span>= self.cluster(target=<span class="keyword">new</span><span class="type">_train_data</span>[value], label=value)</span><br><span class="line"> self.graph(cluster_result, label=value, key=key)</span><br><span class="line"> self.combine_results(target_data=<span class="keyword">new</span><span class="type">_train_data</span>, cluster_result=cluster_result, filename=key)</span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:<span class="type"></span></span><br><span class="line"><span class="type"> mo </span>= Model(k=<span class="number">5</span>)</span><br><span class="line"> mo.run()</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本次用户聚类是基于最基础的模型RFM,在RFM模型上进行扩展,选择了第一种扩展模型(LRFMC),实际上,此次建模这是对数据的探索。</p><p>如需获取本次案例的数据或者更加详细的分析报告,请下方关注微信公众号</p><p>回复:某航空公司数据 | 某航空公司报告</p>]]></content>
<categories>
<category> 案例分析 </category>
</categories>
<tags>
<tag> ML </tag>
<tag> K-mean </tag>
</tags>
</entry>
<entry>
<title>git 的基本使用汇总</title>
<link href="/2019/02/25/git%20%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E6%B1%87%E6%80%BB/"/>
<url>/2019/02/25/git%20%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E6%B1%87%E6%80%BB/</url>
<content type="html"><![CDATA[<hr><p>layout: post<br>title: git 的基本使用汇总<br>categories: Git<br>description: git的使用方法汇总<br>keywords: git、 github平台和coding平台</p><hr><p>参考:<a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000" target="_blank" rel="noopener">廖雪峰git教程</a> </p><h4 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h4><p>版本控制这个概念不知道大家有没有听说过,不管你是软件开发还是平时写文章或者毕业设计的论文都要有版本管理这个意识,因为我自己在这个上面吃过不少亏。</p><p>git命令的学习可以使自己能够更好完成自己的工作以及版本的管理,这也是我自己最想总结git这个命令的原因。</p><hr><h4 id="git的简介"><a href="#git的简介" class="headerlink" title="git的简介"></a>git的简介</h4><p>Git是目前世界上最先进的分布式版本控制系统(没有之一),在Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至<strong>GitHub</strong>(国外的平台),国内也有这样的平台(<strong>Coding</strong>)。<br><br>注:可以了解一下<a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/001374027586935cf69c53637d8458c9aec27dd546a6cd6000" target="_blank" rel="noopener">了解分布式和集中式的区别</a><br></p>那怎么形容<strong>git的好处</strong>呢?比如你在写论文的时候会一直不停的更迭版本,如果手工操作,就会出现下面的情况:<br><br><img src="https://upload-images.jianshu.io/upload_images/5274272-b39f2a952d1c4b19.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure -2 手动版本管理"><br><br>甚至你必须使用一个文件来记录每个版本的变化,非常的不方便,对于涉及到几个人对一个项目的操作时,合并就更加麻烦,而git能够很好的解决和处理这些问题。<p></p><hr><h4 id="git的安装"><a href="#git的安装" class="headerlink" title="git的安装"></a>git的安装</h4><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">dwj@ec:~$ git</span><br><span class="line">The program <span class="string">'git'</span> <span class="keyword">is</span> currently <span class="keyword">not</span> installed. You can install <span class="literal">it</span> <span class="keyword">by</span> typing:</span><br><span class="line">sudo apt-get install git</span><br></pre></td></tr></table></figure><p>查看是否安装:直接在Linux终端输入git,如果没安装就继续输入:<strong>sudo apt-get install git</strong></p><p>安装完成后,还需要最后一步设置,在命令行输入:<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dwj@ec:~$ git<span class="built_in"> config </span>--global user.name <span class="string">"Your Name"</span></span><br><span class="line">dwj@ec:~$ git<span class="built_in"> config </span>--global user.email <span class="string">"[email protected]"</span></span><br></pre></td></tr></table></figure></p><p>注意git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址</p><hr><h4 id="git-仓库创建"><a href="#git-仓库创建" class="headerlink" title="git 仓库创建"></a>git 仓库创建</h4><p>仓库又叫版本库(repository),你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,包括:每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”<br>创建过程如下:<br><figure class="highlight elixir"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">## 首先选择一个合适的地方创建一个空目录:</span></span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>mkdir learngit</span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>cd learngit</span><br><span class="line"><span class="comment">## 查看目录路径</span></span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>pwd</span><br><span class="line">/dwj/home/learngit</span><br><span class="line"><span class="comment">## 初始化仓库</span></span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>git init</span><br><span class="line">Initialized empty Git repository <span class="keyword">in</span> /dwj/home/learngit/.git/</span><br></pre></td></tr></table></figure></p><p><strong>注:</strong></p><ol><li>mkdir +仓库名:mkdir可以简记make+dir,pwd是查看当前路径</li><li>建立了一个空仓库后,当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,千万不要手动修改这个目录里面的文件,不然很容易将其破坏;如果该目录是隐藏的,用<strong>ls -ah</strong>命令就可以看见。</li></ol><hr><p><strong> 区别工作区与版本库:</strong></p><p>工作区(working directory):就是你在电脑里能看到的目录<br>版本库(Repository):工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD.</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-9ba604fb4c25c481.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure -3 : 工作间与版本库的关系"></p><hr><h4 id="基本git命令"><a href="#基本git命令" class="headerlink" title="基本git命令"></a>基本git命令</h4><p>基本操作:<br><figure class="highlight elixir"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">## 将文件放到learngit目录下,添加文件,将文件加入缓存区(如上图)</span></span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>git add <file></span><br><span class="line"><span class="comment">## 用命令git commit告诉Git,把暂存区的所有内容提交到当前分支,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,以便能从历史记录里方便地找到改动记录()</span></span><br><span class="line">dwj<span class="variable">@ec</span><span class="symbol">:</span><span class="variable">$ </span>git commit -m <span class="string">"message"</span></span><br></pre></td></tr></table></figure></p><p>注: 每次修改,如果不add到暂存区,那就不会加入到commit中</p><hr><p><strong>其他命令:</strong></p><p><strong>1. git status</strong> 时刻掌握仓库当前的状态</p><p><strong>2. git diff</strong> 查看difference</p><p><strong>3. git log</strong> 查看历史记录,显示从最近到最远的提交日志,如果嫌输出信息太多,看得眼花缭乱的,可以试试加上–pretty=oneline参数,例如:<br><figure class="highlight livecodeserver"><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></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">log</span> <span class="comment">--pretty=oneline</span></span><br><span class="line"><span class="number">3628164</span>fb26d48395383f8f31179f24e0882e1e0 append GPL</span><br><span class="line">ea34578d5496d7dd233c827ed32a8cd576c5ee85 <span class="built_in">add</span> distributed</span><br><span class="line">cb926e7ea50ad11b8f9e909c05226233bf755030 wrote <span class="keyword">a</span> readme <span class="built_in">file</span></span><br></pre></td></tr></table></figure></p><p>注:类似3628164…882e1e0的是commit id(版本号)</p><p><strong>4.git reset –hard HEAD^</strong> 表示回到上一个版本<br>注:在Git中,用HEAD表示当前版本,用HEAD^表示上一个版本,HEAD^^是上上一个版本,更多版本eg:HEAD~100表示 上100个版本。且可以使用git reset –hard commit id(版本号)到指定版本,且版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位。</p><p><strong>5. git reflog</strong> 查看命令历史,重返未来,以便确定要回到未来的哪个版本</p><p><strong>6.git checkout – file</strong> 想直接丢弃工作区的修改,必须加–,没有–,就变成了“切换到另一个分支”的命令</p><p><strong>7.git reset HEAD file</strong> 改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令<strong>git reset HEAD file</strong>,就回到工作区,用6的方法修改。</p><p><strong>8.git rm <file></file></strong> 现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本<strong>git checkout –</strong>,其实是用版本库里的版本替换工作区的版本:</p><h4 id="远程仓库"><a href="#远程仓库" class="headerlink" title="远程仓库"></a>远程仓库</h4><p>省略注册【github】以及github的设置等等。</p><ol><li>增加远程仓库:</li></ol><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git remote <span class="keyword">add</span><span class="bash"> origin 远程仓库名 </span></span><br><span class="line"><span class="comment">## eg 远程仓库名:[email protected]:DWJWendy/Weibo_Spider.git</span></span><br></pre></td></tr></table></figure><ol start="2"><li>推送到远程仓库:</li></ol><figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">push</span> -u <span class="built_in">origin</span> master</span><br></pre></td></tr></table></figure><p>注:用git push命令,实际上是把当前分支master推送到远程。由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git之后会把本地的master分支和远程的master分支关联起来,所以之后可以不用-u这个参数,直接 <strong>git push origin master</strong>。</p><ol start="3"><li>克隆远程仓库的内容:<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="keyword">clone</span> <span class="title">远程仓库名</span></span><br></pre></td></tr></table></figure></li></ol><hr><h4 id="分支管理"><a href="#分支管理" class="headerlink" title="分支管理"></a>分支管理</h4><p>分支管理是我最想整理的一部分,因为现在需要用上,但是自己还不熟/(ㄒoㄒ)/~~</p><table><thead><tr><th>操作</th><th style="text-align:left">代码</th><th style="text-align:center">备注</th></tr></thead><tbody><tr><td>查看分支</td><td style="text-align:left">git branch</td><td style="text-align:center">当前分支会在前标*</td></tr><tr><td>创建分支</td><td style="text-align:left">git branch <name></name></td><td style="text-align:center"></td></tr><tr><td>切换分支</td><td style="text-align:left">git checkout <name></name></td><td style="text-align:center"></td></tr><tr><td>创建+切换分支</td><td style="text-align:left">git checkout -b <name></name></td><td style="text-align:center"></td></tr><tr><td>合并某分支到当前分支</td><td style="text-align:left">git merge <name></name></td><td style="text-align:center"></td></tr><tr><td>删除分支</td><td style="text-align:left">git branch -d <name></name></td><td style="text-align:center">合并后删除</td></tr><tr><td>如果要丢弃一个没有被合并过的分支</td><td style="text-align:left">git branch -D <name></name></td><td style="text-align:center">强行删除</td></tr></tbody></table><hr><p>下图是一个分支关系图,每次提交,Git都把它们串成一条时间线,在Git里,master是主分支,在下图中,当我们<strong>创建了一个新的分支dev</strong>时,Git就新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上,我们在dev上的工作完成了,就可以把<strong>dev合并到master上</strong>。Git怎么合并呢?就是直接把master指向dev的当前提交,就完成了合并。合并完分支后,甚至<strong>可以删除dev分支</strong>。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:</p><h2 id><a href="#" class="headerlink" title></a><img src="https://upload-images.jianshu.io/upload_images/5274272-2bda6d0dc4c9d7b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure-4: 分支关系"></h2><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 1. 创建分支并切换到分支</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git checkout -b dev</span></span><br><span class="line">Switched to a new branch 'dev'</span><br><span class="line">或者</span><br><span class="line"><span class="meta">$</span><span class="bash"> git branch dev</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git checkout dev</span></span><br><span class="line">Switched to branch 'dev'</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 2.查看分支</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git branch</span></span><br><span class="line">* dev</span><br><span class="line"> master</span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 3.提交</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git add readme.txt </span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git commit -m <span class="string">"branch test"</span></span></span><br><span class="line">[dev fec145a] branch test</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 4.切换会master</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git checkout master</span></span><br><span class="line">Switched to branch 'master‘</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 5.合并</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git merge dev</span></span><br><span class="line">Updating d17efd8..fec145a</span><br><span class="line">Fast-forward</span><br><span class="line"> readme.txt | 1 +</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"> </span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="comment"># 6. 删除分支</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git branch -d dev</span></span><br><span class="line">Deleted branch dev (was fec145a)</span><br></pre></td></tr></table></figure><p>Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。强制禁用Fast forward模式,Git需在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。<br>下面就是–no-ff方式的git merge:</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">git</span> merge --<span class="literal">no</span>-ff -m <span class="string">"merge with no-ff"</span> dev</span><br></pre></td></tr></table></figure><p><strong>冲突解决</strong>:git告诉我们,文件存在冲突,<strong>必须手动解决冲突后再提交</strong>。<strong>git status</strong>也可以告诉我们冲突的文件。Git会用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改后保存,再提交,用带参数的<strong>git log</strong>也可以看到分支的合并情况</p><hr><p><strong>bug分支</strong>:每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。Git还提供了一个stash功能,可以把当前工作现场“储藏”起来 <strong>git stash</strong>,此时用git status查看工作区,就是干净的,因此可以放心地创建分支来修复bug。</p><figure class="highlight livecodeserver"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">##1. 确定要在哪个分支上修复bug,就在其分支上修复,eg 修复master上的bug,就从master创建临时分支</span></span><br><span class="line">$ git checkout master</span><br><span class="line">Switched <span class="built_in">to</span> branch <span class="string">'master'</span></span><br><span class="line">Your branch is ahead <span class="keyword">of</span> <span class="string">'origin/master'</span> <span class="keyword">by</span> <span class="number">6</span> commits.</span><br><span class="line">$ git checkout -b issue<span class="number">-101</span></span><br><span class="line">Switched <span class="built_in">to</span> <span class="keyword">a</span> <span class="built_in">new</span> branch <span class="string">'issue-101'</span></span><br><span class="line"><span class="comment">## 2. 修复bug后,提交</span></span><br><span class="line"><span class="comment">## 3. 修复完成后,切换到master分支,并完成合并,最后删除issue-101分支</span></span><br></pre></td></tr></table></figure><p>注:<strong>git stash list</strong>可以查看刚才的修复,Git把stash内容存在某个地方了,如需恢复有两个办法:一是用<strong>git stash apply</strong>恢复,但是恢复后,stash内容并不删除,你需要用<strong>git stash drop</strong>来删除;另一种方式是用<strong>git stash pop</strong>,恢复的同时把stash内容也删了:再用git stash list查看,就看不到任何stash内容了,另外你可以多次先用git stash list查看,然后恢复指定的stash,用命令:<strong>git stash apply stash@{0}</strong></p><hr><p><strong>分支策略</strong><br>按照几个基本原则进行分支管理:</p><ol><li><p>master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;</p></li><li><p>干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;</p></li><li><p>团队每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了</p></li></ol><hr><p><strong>多人协作</strong></p><table><thead><tr><th>操作</th><th style="text-align:left">代码</th><th style="text-align:center">备注</th></tr></thead><tbody><tr><td>查看远程库</td><td style="text-align:left">git remote</td><td style="text-align:center">git remote -v显示详细信息</td></tr><tr><td>推送主分支</td><td style="text-align:left">git push origin master</td><td style="text-align:center">主分支要时刻与远程同步</td></tr><tr><td>推送分支</td><td style="text-align:left">git push origin <dev></dev></td><td style="text-align:center">成员都在dev上工作,因此要与远程同步</td></tr><tr><td>推送Future分支</td><td style="text-align:left">类似</td><td style="text-align:center">每添加一个新功能,最好新建一个feature分支,开发->合并->删除</td></tr><tr><td>bug分支</td><td style="text-align:left">类似</td><td style="text-align:center">用于在本地修复bug,就没必要推到远程</td></tr><tr><td>创建远程分支到本地</td><td style="text-align:left">git checkout -b dev origin/dev</td><td style="text-align:center">要在dev分支上开发,就必须创建远程origin的dev分支到本地,用这个命令创建本地dev分支</td></tr></tbody></table><hr><p>我之前在推送代码的时候经常会遇到这样的问题,如下图</p><p><img src="https://upload-images.jianshu.io/upload_images/5274272-4cc51f942b42a7b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="figure -5 : 推送冲突"></p><p>解决策略:解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送</p><hr><p><strong>小结:</strong></p><p>1、查看远程库信息,使用git remote -v;</p><p>2、本地新建的分支如果不推送到远程,对其他人就是不可见的;</p><p>3、从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;</p><p>4、在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;</p><p>5、建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name;</p><p>6、从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。</p><h4 id="标签管理"><a href="#标签管理" class="headerlink" title="标签管理"></a>标签管理</h4><p>发布一个版本时,通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。</p><table><thead><tr><th>操作</th><th style="text-align:left">代码</th><th style="text-align:center">备注</th></tr></thead><tbody><tr><td>打一个新标签</td><td style="text-align:left">git tag <name></name></td><td style="text-align:center">默认为HEAD</td></tr><tr><td>查看标签</td><td style="text-align:left">git tag</td></tr><tr><td>对应的commit id打标签</td><td style="text-align:left">git tag v0.9 6224937</td><td style="text-align:center">数字是commit id</td></tr><tr><td>查看标签信息</td><td style="text-align:left">git show <tagname></tagname></td></tr><tr><td>用PGP签名标签</td><td style="text-align:left">git tag -s <tagname> -m “blablabla…”</tagname></td></tr><tr><td>指定标签信息</td><td style="text-align:left">git tag -a <tagname> -m “blablabla…”</tagname></td></tr><tr><td>删除标签</td><td style="text-align:left">git tag -d v0.1</td></tr><tr><td>推送本地标签</td><td style="text-align:left">git push origin <tagname></tagname></td></tr><tr><td>推送全部本地标签</td><td style="text-align:left">git push origin –tag</td><td style="text-align:center">可以推送全部未推送过的本地标签</td></tr><tr><td>删除远程标签</td><td style="text-align:left">git push origin :refs/tags/<tagname></tagname></td></tr></tbody></table><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>git使用是必须必须会的,每次遇到就是临时的找命令或者只记住了基础的命令,所以想把它总结下来,之后查的时候也方便,最后给需要的你,O(∩_∩)O哈哈~</p>]]></content>
<categories>
<category> tool </category>
</categories>
<tags>
<tag> Git </tag>
<tag> github </tag>
</tags>
</entry>
</search>