-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathli-yong-zi-ran-yu-yan-chu-li-nlpshi-gu-jia-yu-ce-geng-wei-jing-zhun.html
590 lines (485 loc) · 42.2 KB
/
li-yong-zi-ran-yu-yan-chu-li-nlpshi-gu-jia-yu-ce-geng-wei-jing-zhun.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
<!DOCTYPE html>
<html lang="zh-hant-tw">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="" />
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro|Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/theme/stylesheet/style.min.css">
<link id="pygments-light-theme" rel="stylesheet" type="text/css"
href="/theme/pygments/github.min.css">
<link rel="stylesheet" type="text/css" href="/theme/font-awesome/css/fontawesome.css">
<link rel="stylesheet" type="text/css" href="/theme/font-awesome/css/brands.css">
<link rel="stylesheet" type="text/css" href="/theme/font-awesome/css/solid.css">
<link href="/static/custom.css" rel="stylesheet">
<meta name="author" content="Michael Chien" />
<meta name="description" content="本篇結合自然語言處理的相關技術與統計資料分析為2019年選修資工所類神經網路課程時所做的side project。 (2020/08/13更新) 前言 股價的漲跌往往不是我們這些股市菜鳥所能夠理解的,尤其是在股價的起伏還受到各種消息面的影響,甚至老闆的一句話就可以讓股價一飛沖天或跌落谷底,近年來最著名的例子就是特斯拉的執行長 Elon Musk,若沒有掌握到這些消息將會對股價的漲幅丈二金剛摸不著頭緒。 img+br+em,a+br+em, img+em, a+em { font-size: 90%; /*使用較小的文字*/ font-color: #AAAAAA; /*使用較淡的文字色彩*/ font-style: normal; /*以正常字體呈現*/ } Elon Musk 總是喜歡在Twitter上發表個人看法,他的一言一行牽動著旗下公司股價的漲跌 ( 圖片來源 ) 有些股市老手會說:哎呀花時間閱讀那些資訊是沒有用的,等你看到時早就已經反映在股價上了,但事實上可能有些資訊早就潛藏在其中,只是礙於我們的經驗不足而無法做出適當的判斷。 因此本篇將透過自然語言處理(Natural Language Processing, NLP)試著將公司行號釋出的重大消息資訊納入,透過科技來輔佐我們在茫茫的資訊海中抽絲剝繭,以期望能輔助我們尋找出其中的脈絡並先行做出部署 …" />
<meta name="keywords" content="Natural Language Processing, Stock">
<meta property="og:site_name" content="Learning note & Build some side projects | Michael Chien"/>
<meta property="og:title" content="利用自然語言處理(NLP)使股價預測更為精準"/>
<meta property="og:description" content="本篇結合自然語言處理的相關技術與統計資料分析為2019年選修資工所類神經網路課程時所做的side project。 (2020/08/13更新) 前言 股價的漲跌往往不是我們這些股市菜鳥所能夠理解的,尤其是在股價的起伏還受到各種消息面的影響,甚至老闆的一句話就可以讓股價一飛沖天或跌落谷底,近年來最著名的例子就是特斯拉的執行長 Elon Musk,若沒有掌握到這些消息將會對股價的漲幅丈二金剛摸不著頭緒。 img+br+em,a+br+em, img+em, a+em { font-size: 90%; /*使用較小的文字*/ font-color: #AAAAAA; /*使用較淡的文字色彩*/ font-style: normal; /*以正常字體呈現*/ } Elon Musk 總是喜歡在Twitter上發表個人看法,他的一言一行牽動著旗下公司股價的漲跌 ( 圖片來源 ) 有些股市老手會說:哎呀花時間閱讀那些資訊是沒有用的,等你看到時早就已經反映在股價上了,但事實上可能有些資訊早就潛藏在其中,只是礙於我們的經驗不足而無法做出適當的判斷。 因此本篇將透過自然語言處理(Natural Language Processing, NLP)試著將公司行號釋出的重大消息資訊納入,透過科技來輔佐我們在茫茫的資訊海中抽絲剝繭,以期望能輔助我們尋找出其中的脈絡並先行做出部署 …"/>
<meta property="og:locale" content="en_US"/>
<meta property="og:url" content="/li-yong-zi-ran-yu-yan-chu-li-nlpshi-gu-jia-yu-ce-geng-wei-jing-zhun.html"/>
<meta property="og:type" content="article"/>
<meta property="article:published_time" content="2019-06-05 11:20:00+08:00"/>
<meta property="article:modified_time" content=""/>
<meta property="article:author" content="/author/michael-chien.html">
<meta property="article:section" content="articles"/>
<meta property="article:tag" content="Natural Language Processing"/>
<meta property="article:tag" content="Stock"/>
<meta property="og:image" content="static/profile.jpg">
<title>Learning note & Build some side projects | Michael Chien – 利用自然語言處理(NLP)使股價預測更為精準</title>
</head>
<body class="light-theme">
<aside>
<div>
<a href="">
<img src="static/profile.jpg" alt="Michael Chien" title="Michael Chien">
</a>
<h1>
<a href="">Michael Chien</a>
</h1>
<p>Data enthusiast / Database / ML <br/> <br/> 投入巨量資料分析相關研究 <br/> 熱衷於挖掘資料數據中的價值</p>
<nav>
<ul class="list">
<li>
<a target="_self"
href="/pages/about-me.html#about-me">
About Me
</a>
</li>
</ul>
</nav>
<ul class="social">
<li>
<a class="sc-github" href="https://github.com/michael81045" target="_blank">
<i class="fab fa-github"></i>
</a>
</li>
<li>
<a class="sc-Another social link" href="#" target="_blank">
<i class="fab fa-Another social link"></i>
</a>
</li>
</ul>
</div>
</aside>
<main>
<nav>
<a href="/index.html">Home</a>
<a href="/archives.html">Archives</a>
<a href="/categories.html">Categories</a>
<a href="/tags.html">Tags</a>
</nav>
<article class="single">
<header>
<h1 id="li-yong-zi-ran-yu-yan-chu-li-nlpshi-gu-jia-yu-ce-geng-wei-jing-zhun">利用自然語言處理(NLP)使股價預測更為精準</h1>
<p>
Posted on 週三 05 六月 2019 in <a href="/category/articles.html">articles</a>
</p>
</header>
<div>
<p></br></p>
<p><strong>本篇結合自然語言處理的相關技術與統計資料分析為2019年選修資工所類神經網路課程時所做的side project。</strong></p>
<p>(2020/08/13更新)
</br></p>
<h1><font size = 6 > <strong>前言</strong> </font></h1>
<p>股價的漲跌往往不是我們這些股市菜鳥所能夠理解的,尤其是在股價的起伏還受到各種消息面的影響,甚至老闆的一句話就可以讓股價一飛沖天或跌落谷底,近年來最著名的例子就是特斯拉的執行長 Elon Musk,若沒有掌握到這些消息將會對股價的漲幅丈二金剛摸不著頭緒。</p>
<style>
img+br+em,a+br+em, img+em, a+em {
font-size: 90%; /*使用較小的文字*/
font-color: #AAAAAA; /*使用較淡的文字色彩*/
font-style: normal; /*以正常字體呈現*/
}
</style>
<p></br></p>
<p align="center">
<img src="../extra/musk.png">
<font color = #AAAAAA> Elon Musk 總是喜歡在Twitter上發表個人看法,他的一言一行牽動著旗下公司股價的漲跌 (
<a href="https://technews.tw/?p=596503">圖片來源</a> )
</font>
</p>
<p></br></p>
<p>有些股市老手會說:哎呀花時間閱讀那些資訊是沒有用的,等你看到時早就已經反映在股價上了,但事實上可能有些資訊早就潛藏在其中,只是礙於我們的經驗不足而無法做出適當的判斷。</p>
<p>因此本篇將透過自然語言處理(Natural Language Processing, NLP)試著將公司行號釋出的重大消息資訊納入,透過科技來輔佐我們在茫茫的資訊海中抽絲剝繭,以期望能輔助我們尋找出其中的脈絡並先行做出部署,來預測股價的漲跌。</p>
<p></br></p>
<hr>
<h1><font size = 6 > <strong>資料來源</strong> </font></h1>
<p>首先透過爬蟲(web crawler)的方式取得本篇拿來分析用的歷史股價-玉晶光(3406)。</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="kn">as</span> <span class="nn">pd</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">datetime</span>
<span class="n">url</span> <span class="o">=</span> <span class="s2">"https://query1.finance.yahoo.com/v7/finance/download/3406.TW?period1=0&period2=1549258857&interval=1d&events=history&crumb=hP2rOschxO0"</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'file.csv'</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">f</span><span class="o">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s1">'file.csv'</span><span class="p">,</span> <span class="n">index_col</span><span class="o">=</span><span class="s1">'Date'</span><span class="p">,</span> <span class="n">parse_dates</span><span class="o">=</span><span class="p">[</span><span class="s1">'Date'</span><span class="p">])</span>
<span class="n">df</span><span class="o">.</span><span class="n">Close</span><span class="o">.</span><span class="n">plot</span><span class="p">()</span>
<span class="n">stock_TW</span><span class="o">=</span><span class="n">crawl_price</span><span class="p">(</span><span class="s2">"3406.TW"</span><span class="p">)</span>
<span class="n">stock_TW</span><span class="o">.</span><span class="n">to_csv</span><span class="p">(</span><span class="s2">"3406.csv"</span><span class="p">)</span>
<span class="n">stock_TW</span>
</pre></div>
<p><img align = "left" witdh = 1000 src= "../extra/stock_3406.png"></p>
<p></br></br></br></br></br></br></br></br></p>
<p>再來我一樣透過爬蟲的方式將<a href="https://mops.twse.com.tw/">公開資訊網站</a>內過去曾發布過的<strong>重大消息與公告</strong>給抓取下來。</p>
<p>抓到的內容如下(以其中一篇重大消息為例):</p>
<blockquote>
<p>1.事實發生日:108/05/14
2.接受資金貸與之:
(1)公司名稱:玉晶光電(廈門)有限公司
(2)與資金貸與他人公司之關係:
聯屬關係
(3)資金貸與之限額(仟元):541617
(4)原資金貸與之餘額(仟元):289440
(5)本次新增資金貸與之金額(仟元):62000
(6)是否為董事會授權董事長對同一貸與對象分次撥貸或循環動用之資金貸與:否
(7)迄事實發生日止資金貸與餘額(仟元):351440
(8)本次新增資金貸與之原因:
為因應玉晶光電(廈門)有限公司營運周轉而從事之資金貸與,並供做資金
貸與借新還舊之用。
3.接受資金貸與公司所提供擔保品之:
(1)內容:
無
(2)價值(仟元):0
4.接受資金貸與公司最近期財務報表之:
(1)資本(仟元):4620848
(2)累積盈虧金額(仟元):1403737
5.計息方式:
年利率不低於同幣別借款之最高利率,到期一次付息。
6.還款之:
(1)條件:
視接受資金貸與公司之營運狀況,於借款期限內還清。
(2)日期:
借款日起一年內還清。
7.迄事實發生日為止,資金貸與餘額(仟元):
2062882
8.迄事實發生日為止,資金貸與餘額占公開發行公司最近期財務報表淨值之比率:
25.54
9.公司貸與他人資金之來源:
子公司本身
10.其他應敘明事項:
無</p>
</blockquote>
<p></br></p>
<p>我們能夠從重大消息公告當中得知公司的財務資訊, 交易對象等,甚至是該消息發布的緣由都會附上詳盡的文字敘述。而新聞媒體所發布的新聞稿在本篇分析當中將先不納入我的資料來源,因為考量到不同媒體報導的角度可能不同,導致對於事件的描述上有所差異,用詞上情感的強烈亦會影響模型判斷的依據,徒增資料分析上的變因。</p>
<p></br></p>
<hr>
<h1><font size = 5 ><strong>那我們如何將文字轉換為有意義的量值呢?</strong></font></h1>
<p>一個詞彙的涵義可能在不同使用者的經歷或是書寫的習慣上的差異,而使得語意上有所差距,因此如何使一個詞彙表達出表達出語意上真正的涵義,Tomas Mikolov 在 2013 年提出了他的看法:<font color = #FF4500 ><strong>字詞就如同我們人一般,能夠透過周遭相似的詞彙(context)反映出它真正的涵義。</strong></font> [<a href="https://arxiv.org/pdf/1301.3781.pdf">原文連結</a>]</p>
<p></br></p>
<p>概念如下圖:</p>
<p align="center">
<img src="../extra/word_embedding.png">
<font color = #AAAAAA> 將所有字詞以向量方式表示 (
<a href="https://www.youtube.com/watch?v=UYPa347-DdE">圖片來源</a> )
</font>
</p>
<p></br></p>
<hr>
<h1><font size = 6 > <strong>雛型架構 Naive model</strong> </font></h1>
<blockquote>
<ol>
<li>Extractor 用來提取重大消息中有用的資訊</li>
<li>Classifier 將提取出的資訊結合股價區分為不同的類別,給予適當的數值範圍辨別漲跌的趨勢。</li>
</ol>
</blockquote>
<p>接下來就看我是怎麼實做這個部分的內容瞜</p>
<p></br></p>
<h1><font size = 6 > <strong>文章分類 Document Classification</strong> </font></h1>
<p>在斷詞的使用上我是透過 <a href="https://github.com/fxsjy/jieba">jieba</a> 的 <code>search_mode</code>。</p>
<p>以下方的例子為例,將 <code>text = "101在台北市信義區"</code>,可以很明顯的看出不同模式在斷詞結果上的差別。</p>
<ul>
<li>search_mode </br>
101 / 在 / 台北 / 北市 / 台北市 / 信義區</li>
<li>full_mode </br>
101 / 在 / 台北 / 台北市 / 北市 / 信 / 義 / 區</li>
<li>precise_mode </br>
101 / 在 / 台北 / 北市 / 台北市 / 信義區</li>
</ul>
<div class="highlight"><pre><span></span><span class="n">text</span> <span class="o">=</span> <span class="s2">"101在台北市信義區"</span>
<span class="k">print</span><span class="p">(</span><span class="n">jieba</span><span class="o">.</span><span class="n">lcut_for_search</span><span class="p">(</span><span class="n">text</span><span class="p">))</span> <span class="c1"># serch_mode</span>
<span class="c1"># ['101', '在', '台北', '北市', '台北市', '信義區']</span>
<span class="k">print</span><span class="p">(</span><span class="n">jieba</span><span class="o">.</span><span class="n">lcut</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">cut_all</span> <span class="o">=</span> <span class="bp">True</span><span class="p">))</span> <span class="c1"># full_mode</span>
<span class="c1"># ['101', '在', '台北', '台北市', '北市', '信', '義', '區']</span>
<span class="k">print</span><span class="p">(</span><span class="n">jieba</span><span class="o">.</span><span class="n">lcut</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">cut_all</span> <span class="o">=</span> <span class="bp">False</span><span class="p">))</span> <span class="c1"># precise_mode (default mode)</span>
<span class="c1"># ['101', '在', '台北市', '信義區']</span>
</pre></div>
<p>選擇使用 <code>search_mode</code> 是為了提高模型的召回率(recall),而模型的準確率(precision)與召回率之間的權衡是未來我們在針對模型作微調以提升預測的準確率時能夠著墨的地方,但現在先讓我們粗步地完成整個模型後再回頭過來調校,有關這方面的討論可以參考以下文章: </br></p>
<ul>
<li><a href="https://www.ycc.idv.tw/confusion-matrix.html">如何辨別機器學習模型的好壞?秒懂Confusion Matrix</a> </br></li>
</ul>
<p>按照上述的方式我將所有抓取到的玉晶光重大公開消息做為本篇文本分析的語料庫(corpus),在刪除停用詞(stopword)等一些常用的詞或沒有意義的符號,例如:<code>在</code>、<code>不外乎</code>、<code>不只</code>等這一類的詞,將所有的詞集合而成一個向量。</p>
<blockquote>
<p>101 / 台北 / 北市 / 台北市 / 信義區</p>
</blockquote>
<p>我們可以很直觀的認為如果一個詞很頻繁的在一篇重大消息當中出現,表示這個詞可能與這篇公開消息的關聯性越高,可以將其出現的頻率-詞頻(Term Frequency, TF)透過下方的公式計算得出:</p>
<blockquote>
<p>字詞在文章中出現的次數 / 文章的總詞彙數</p>
</blockquote>
<p>但是今天如果有一個詞(ex. 撤資)它只出現在特定的幾篇相較於廣泛出現的用語(ex. 資金),前者的重要性以及獨特性應該要更高,這也是逆向文件頻率(Inverse Document Frequency, IDF)的概念,計算的公式為:</p>
<blockquote>
<p>log (字詞在文章中出現的次數 / 文章的總詞彙數)</p>
</blockquote>
<p>並將TF與IDF相乘得到該篇公開消息的特徵值。</p>
<p>接下來我們可以利用 <code>consine similarity</code> 來評估所有公開消息與以下三項類別的相似程度:</p>
<ul>
<li>
<p>上漲 (Up) </br>
<code>當天股價漲幅</code> ≥ 1 % </br></p>
</li>
<li>
<p>持平 (Stay) </br>
-1 % ≤ <code>當天股價漲幅</code> ≤ 1 % </br></p>
</li>
<li>
<p>下跌 (Down) </br>
<code>當天股價漲幅</code> ≤ -1 % </br></p>
</li>
</ul>
<p align="center">
<img src="../extra/cosine-similarity.png">
<font color = #AAAAAA> 計算文本的相似度時很常見的方式 (
<a href="https://clay-atlas.com/blog/2020/03/26/cosine-similarity-text-count/">圖片來源</a> )
</font>
</p>
<p></br></p>
<p>但是在TF-IDF的使用上有些<font color = #FF4500 > <strong>缺點</strong> </font>:</br></p>
<ol>
<li>字詞出現的頻率較高不一定就能完整的表達該消息欲傳達的內容。</li>
<li>無法辨識同義詞,甚至是,甚至是同一個詞的變形也不能處理。</li>
<li>多義詞亦是 TF-IDF 無法處理的狀況。</li>
<li>存在特徵稀疏(Sparse feature)的問題。 (<a href="https://www.zhihu.com/question/31951092">參考文章</a>)</li>
</ol>
<p>若是結合文章標註 Document tag (<code>TF-IDF + Word2Vec</code>)及 <code>cosine similarity</code> 的話,雖然能包含文檔中的上下文,使其對於同義詞的辨識度提高,<font color = #FF4500 > <strong>但是同樣對於多義詞的辨識束手無策</strong> </font>。 </p>
<p></br></p>
<h1><font size = 5 > <strong>語言的博大精深!!</strong> </font></h1>
<p>舉個有趣的例子為例:</p>
<blockquote>
<p><font size = 4 > <strong>I arrived at the <font color = #FF4500 > bank </font> after crossing the river.</strong> </font><br>
<font size = 4 > <strong>I arrived at the <font color = #FF4500 > bank </font> after crossing the street.</strong> </font> </p>
</blockquote>
<p>當這兩句併排在一起我們能很明顯的判別出 <font color = #FF4500 >
<strong>bank</strong> </font> 這一個字分別有不同的意思: </p>
<p align="center">
<img src="../extra/bank_translate.png">
<font color = #AAAAAA> 同一個詞在不同的句子當中會有不同的意義 (
<a href="https://dictionary.cambridge.org/zht/%E8%A9%9E%E5%85%B8/%E8%8B%B1%E8%AA%9E-%E6%BC%A2%E8%AA%9E-%E7%B9%81%E9%AB%94/bank">圖片來源</a> )
</font>
</p>
<p></br></p>
<p>而判斷的基準則是必須透過上下文的方式來判斷這個單字真正的涵義,這樣的現象在中文當中同樣也可以發現到。</p>
<p></br></p>
<h1><font size = 6 > <strong>類神經網路(Neural Network)</strong> </font></h1>
<p>近年來深度學習快速的發展,現在已經能夠將一個詞投影到較低維的空間當中,使得近似詞能夠獲得上下文資訊,透過非監督式學習(unsupervised learning)提取特徵,能廣泛的利用在其他的狀況(generalization)。
依照提取出來的特徵做 expression,再根據不同的 case 微調(fine tuning)做監督式學習(supervised learning),來達成我們要的目的。</p>
<p></br></p>
<h2><strong>BERT</strong></h2>
<p>最終我決定以 GOOGLE 在 2018 年發表的自然語言模型- BERT 作為我分類器(Classifier)的最終 model,在 <a href="https://colab.research.google.com/github/tensorflow/tpu/blob/master/tools/colab/bert_finetuning_with_cloud_tpus.ipynb">colab</a> 可以看到 GOOGLE 自附的所有教學以及完整的 code,若要自行搭載環境也可以參考以下文章:</p>
<ul>
<li><a href="https://leemeng.tw/attack_on_bert_transfer_learning_in_nlp.html">進擊的 BERT:NLP 界的巨人之力與遷移學習</a> </br></li>
</ul>
<p>BERT整個 model 最重要的部分是以 <code>transformer</code> 中 <font color = #FF4500 > <strong>Attention</strong> </font> 的機制所組成,原因是考慮了過去常用的類神經網路- RNN是依照時間的次序(time series)由左往右計算,這對模型產生了一定程度上的限制。
在 <code>transformer</code> 作者的研究論文當中給予的定義也提到:</p>
<blockquote>
<p>Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution.</p>
</blockquote>
<p align="center">
<img src="../extra/rnn-animate.gif">
<font color = #AAAAAA> </br> RNN模型中需要一步步地按照順序從頭處理所有詞語 (
<a href="https://www.youtube.com/watch?time_continue=2&v=LHXXI4-IEns">圖片來源</a> )
</font>
</p>
<hr>
<p>以前面提到的英文例句為例:</p>
<blockquote>
<p><font size = 4 > <strong>I arrived at the <font color = #FF4500 > bank </font> after crossing the river.</strong> </font> </p>
</blockquote>
<p>要解析出<font color = #FF4500 > <strong>bank</strong> </font>真正的涵義須完整閱讀到<font color = #FF4500 > <strong>river</strong> </font> ,如果這兩個詞語距離較遠時RNN的執行效率就會較差。
而 <font color = #FF4500 > <strong>Attention</strong> </font> 則是透過計算每個單詞與其他所有單詞之間的關聯性,能夠很快地得出在翻譯 bank 的同時, river 有較高的 Attention score ,就可以依此作加權,反饋至前一個神經網絡,能夠迅速且充分地掌握上下文信息的特徵。(<a href="https://zhuanlan.zhihu.com/p/47282410">參考文章</a>)</p>
<p align="center">
<img src="../extra/self_attention.gif">
<font color = #AAAAAA> </br> Self-Attention計算每個字詞與其他所有字詞之間的關係,掌握上下文的關聯性 (
<a href="https://zhuanlan.zhihu.com/p/47282410">圖片來源</a> )
</font>
</p>
<p>也因為 <code>transformer</code> 這樣的並行機制較符合現行GPU的框架,model 運行的速度亦能得到大幅地提升,如果想要更詳細地了解其運作原理可以閱讀 <a href="http://jalammar.github.io/"><strong>Jay Alammer</strong></a> 的文章,附有大量的圖文解說:</br></p>
<ul>
<li><a href="http://jalammar.github.io/illustrated-transformer/">The Illustrated Transformer</a></li>
</ul>
<p>BERT 詳細的原理可以參考李宏毅老師的影片以及其他網路上的資源:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=UYPa347-DdE">ELMO, BERT, GPT</a> </br></li>
<li><a href="https://www.jishuwen.com/d/2M6u/zh-tw">BERT模型詳解</a> </br></li>
</ul>
<hr>
<p>BERT提供了四種下游的任務供使用者選取</p>
<ul>
<li>Sentence Pair Cassification </br>
ex. 給定一對句子,目標是預測第二個句子相對第一個句子是包含、矛盾還是中立。</li>
<li>Single Sentence Classification </br>
ex. 從電影評論中提取句子或者是標註人類帶有情緒性的用詞。</li>
<li>Question Answering </br>
ex. 給定一個問題以及包含答案的段落,預測答案落在文本的哪一範圍中。</li>
<li>Single Sentence Tagging </br>
ex. 識別文本內具有特別意義的字詞-人名、地名、專有名詞等。</li>
</ul>
<p align="center">
<img src="../extra/BERT_tasks.png">
<font color = #AAAAAA> </br> BERT提供四種不同下游任務的
pre-training model 供使用者選取 (
<a href="https://arxiv.org/pdf/1810.04805.pdf">圖片來源</a> )
</font>
</p>
<p></br></p>
<p>依照我的需求,我使用 <a href="https://tfhub.dev/tensorflow/bert_zh_L-12_H-768_A-12/2">TensorFlow</a> 中與中文相關的 <font color = #FF4500 > <strong>pre-train model</strong> </font> 對整理好的資料集做下游的 <code>Single Sentence Classification</code> 監督式學習任務。</p>
<p align="center">
<img src="../extra/3406_text.png">
<font color = #AAAAAA> </br> 將玉晶光的歷史股價與日期所對應的公開消息整理成一個dataset
</font>
</p>
<p>首先,將原始資料集轉換成BERT能夠讀得懂的格式</p>
<ul>
<li>text_a </br>
需要被給定分類類別的文本。</li>
<li>text_b </br>
ex. 給定一個問題以及包含答案的段落,預測答案落在文本的哪一範圍中。</li>
<li>label </br>
總共要區分為哪幾類。</li>
</ul>
<div class="highlight"><pre><span></span><span class="sd">"""</span>
<span class="sd">上漲: 0</span>
<span class="sd">持平: 1</span>
<span class="sd">下跌: 2</span>
<span class="sd">"""</span>
<span class="n">data_column</span> <span class="o">=</span> <span class="s1">'Text'</span>
<span class="n">label_column</span> <span class="o">=</span> <span class="s1">'Signal'</span>
<span class="c1"># label_list is the list of labels</span>
<span class="n">label_list</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
<span class="n">train_InputExamples</span> <span class="o">=</span> <span class="n">train</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">bert</span><span class="o">.</span><span class="n">run_classifier</span><span class="o">.</span><span class="n">InputExample</span><span class="p">(</span>
<span class="n">text_a</span> <span class="o">=</span> <span class="n">train_set</span><span class="p">[</span><span class="n">data_column</span><span class="p">],</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">train_set</span><span class="p">[</span><span class="n">label_column</span><span class="p">]),</span> <span class="n">axis</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">test_InputExamples</span> <span class="o">=</span> <span class="n">test</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">bert</span><span class="o">.</span><span class="n">run_classifier</span><span class="o">.</span><span class="n">InputExample</span><span class="p">(</span>
<span class="n">text_a</span> <span class="o">=</span> <span class="n">test_set</span><span class="p">[</span><span class="n">data_column</span><span class="p">],</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">test_set</span><span class="p">[</span><span class="n">label_column</span><span class="p">]),</span> <span class="n">axis</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">BERT_MODEL_HUB</span> <span class="o">=</span> <span class="s2">"https://tfhub.dev/tensorflow/bert_zh_L-12_H-768_A-12/2"</span>
<span class="k">def</span> <span class="nf">create_tokenizer_from_hub_module</span><span class="p">():</span>
<span class="sd">"""Get the vocab file and casing info from the Hub module."""</span>
<span class="k">with</span> <span class="n">tf</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span><span class="o">.</span><span class="n">as_default</span><span class="p">():</span>
<span class="n">bert_module</span> <span class="o">=</span> <span class="n">hub</span><span class="o">.</span><span class="n">Module</span><span class="p">(</span><span class="n">BERT_MODEL_HUB</span><span class="p">)</span>
<span class="n">tokenization_info</span> <span class="o">=</span> <span class="n">bert_module</span><span class="p">(</span><span class="n">signature</span><span class="o">=</span><span class="s2">"tokenization_info"</span><span class="p">,</span> <span class="n">as_dict</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">with</span> <span class="n">tf</span><span class="o">.</span><span class="n">Session</span><span class="p">()</span> <span class="k">as</span> <span class="n">sess</span><span class="p">:</span>
<span class="n">vocab_file</span><span class="p">,</span> <span class="n">do_lower_case</span> <span class="o">=</span> <span class="n">sess</span><span class="o">.</span><span class="n">run</span><span class="p">([</span><span class="n">tokenization_info</span><span class="p">[</span><span class="s2">"vocab_file"</span><span class="p">],</span><span class="n">tokenization_info</span><span class="p">[</span><span class="s2">"do_lower_case"</span><span class="p">]])</span>
<span class="k">return</span> <span class="n">bert</span><span class="o">.</span><span class="n">tokenization</span><span class="o">.</span><span class="n">FullTokenizer</span><span class="p">(</span><span class="n">vocab_file</span><span class="o">=</span><span class="n">vocab_file</span><span class="p">,</span> <span class="n">do_lower_case</span><span class="o">=</span><span class="n">do_lower_case</span><span class="p">)</span>
<span class="n">tokenizer</span> <span class="o">=</span> <span class="n">create_tokenizer_from_hub_module</span><span class="p">()</span>
<span class="c1"># We'll set sequences to be at most 128 tokens long.</span>
<span class="n">MAX_SEQ_LENGTH</span> <span class="o">=</span> <span class="mi">128</span>
<span class="c1"># Convert our train and test features to InputFeatures that BERT understands.</span>
<span class="n">train_features</span> <span class="o">=</span> <span class="n">bert</span><span class="o">.</span><span class="n">run_classifier</span><span class="o">.</span><span class="n">convert_examples_to_features</span><span class="p">(</span><span class="n">train_InputExamples</span><span class="p">,</span> <span class="n">label_list</span><span class="p">,</span> <span class="n">MAX_SEQ_LENGTH</span><span class="p">,</span> <span class="n">tokenizer</span><span class="p">)</span>
<span class="n">test_features</span> <span class="o">=</span> <span class="n">bert</span><span class="o">.</span><span class="n">run_classifier</span><span class="o">.</span><span class="n">convert_examples_to_features</span><span class="p">(</span><span class="n">test_InputExamples</span><span class="p">,</span> <span class="n">label_list</span><span class="p">,</span> <span class="n">MAX_SEQ_LENGTH</span><span class="p">,</span> <span class="n">tokenizer</span><span class="p">)</span>
</pre></div>
<p>格式轉換完畢之後就可以開始訓練下游的任務模型了!!詳細的 code 以及參數設定可以參考 Google 在 Colab 上釋出的 <a href="https://colab.research.google.com/github/google-research/bert/blob/master/predicting_movie_reviews_with_bert_on_tf_hub.ipynb#scrollTo=IuMOGwFui4it">Google BERT Predicting Movie Reviews with BERT on TF Hub</a> ,在<font color = #FF4500 ><strong>本篇當中只是將 Classification 改成 Multi-Classification</strong></font>。</p>
<p>以下是我最終的流程架構圖:</p>
<p align="center">
<img src="../extra/stock_flow_structure.png">
<font color = #AAAAAA> </br> 預測的準確度還算可以,但仍然有許多調整的空間
</font>
</p>
<p></br></p>
<hr>
<h1><strong>結論</strong></h1>
<p>本篇到這邊也算是告一個段落,透過NLP的方式將消息面量化運用在股價的預測上,整個模型的架構不用到很複雜也能有很不錯的表現,但仍然能有幾處可以持續精進的地方,<font color = #FF4500 ><strong>未來或許可以從以下這些方面下手使模型預測的準確度再向上提升</strong> </font>。</p>
<hr>
<p><font color = #FF4500 > <strong>(2020/08/13更新)</strong> </font></p>
<h2><strong>Data Segmentation</strong></h2>
<p>首先是繁體中文方面的斷詞,本篇實作是透過大陸那邊的開源工具-jieba,但是在用語上與臺灣還是略微不同,好在中研院資訊所的繁體中文斷詞系統<font color = #FF4500 > <strong><a href="https://github.com/ckiplab/ckiptagger">CKIP(CkipTagger)</a></strong> </font> 在去年九月時開源在Github上,在繁體中文斷詞的表現上可是比 jieba 還要好上許多!</p>
<p align="center">
<img src="../extra/nlp_performance.png">
<font color = #AAAAAA> </br> 中研院的研究團隊表示在中文處理方面的準確率還比 jieba 高出七個百分點 (
<a href="https://github.com/ckiplab/ckiptagger">圖片來源</a> )
</font>
</p>
<p>再者,我們也能夠針對不同的case建置字典使中文識別上能夠更加的精確,以本篇所採用的公開消息為例,jieba在對許多投資金融相關的專業用語辨識度實在是差強人意,甚至是<font color = #FF4500 ><strong>股東</strong></font>兩個字都會被切開,若大家有仔細去看過各公司行號所發布的公開消息,不難發現有許多資訊是針對投資金額以及股東相關權益,或許正是丟失了這部分的資訊,導致模型的準確率下降,我們可以透過自定義字典來將這方面的資訊補齊。</p>
<p></br></p>
<h2><strong>樣本不平衡(Unbalanced Data)</strong></h2>
<p>我們蒐集到的樣本往往不如理想情況那樣每一個類別的樣本數都是相同的,一定會有樣本數不平衡的情形發生,以本篇的資料來源為例:股價的漲跌與持平的天數可能不會完全相同,在樣本數不平衡的情況下所建構出來的模型預測能力可能會失準,因此我們或許可以透過<font color = #FF4500 ><strong>調整閾值</strong></font>的方式使模型對於數量較少的類別更加敏感,亦或者是<font color = #FF4500 ><strong>藉由採樣(sampling)來改善數據不平衡的現象</strong></font>。</br>
但是其中仍有許多需要注意的地方,可以參考以下文章:
* <a href="https://www.zhihu.com/question/269698662">欠采样(undersampling)和过采样(oversampling)会对模型带来怎样的影响?</a> </br></p>
<p><strong>至於是否一定得透過採樣的方式來優化模型,則必須回歸到當初建構模型的目的以及Domain Knowledge的判斷,衡量其中的利弊,或者是我們可以乾脆更改模型的<font color = #FF4500 >評測指標</font>,重新評估模型的表現</strong>。</p>
<p></br></p>
<h2><strong>評測指標(Evaluation Metric)</strong></h2>
<p>這部分其實在前面一開始的部分有提到評估模型的好壞不能只看預測出來的準確率(accurracy)來判定,倘若的資料正反例不平衡的情況下,準確率這項指標可能就會失去參考價值,因此其他常見的判定指標還有精確率(precision)以及召回率(recall),概念如下圖:</p>
<p align="center">
<img src="../extra/precision_recall.png">
<font color = #AAAAAA> </br> Precision and Recall (
<a href="https://en.wikipedia.org/wiki/Precision_and_recall">圖片來源</a> )
</font>
</p>
<p>這也是我們前面所提到的混淆矩陣(<a href="https://www.ycc.idv.tw/confusion-matrix.html">Confusion Matrix</a>),但是往往 Precision 與 Recall 兩者不能兼得,想獲得更多的 Ground Truth 為 Truth 的例子則可能造成Recall上升,Precision下降,因此除了上述提到的這兩項指標外 F1-score 也是另一項常見的量化指標,此外也會使用 ROC-AUC 及 PR-AUC 來評估相同資料集下的表現結果(<a href="https://cynthiachuang.github.io/Common-Evaluation-MetricAccuracy-Precision-Recall-F1-ROCAUC-and-PRAUC/">參考文章</a>)。</br>
亦或者是使用Kaggle上通用的 Multi-Class-Log-Loss作為不同模型的評測指標,本篇只嘗試使用傳統文本分析的方法:TF - IDF 及 BERT,對於其他的分類器(Classifier)如:Logistic Regression、SVM、XGBoost 等等都還未實際嘗試過,或許能有更佳的分類表現也說不定。</p>
<p></br></p>
<h2><strong>模型集成(Model Ensembling)</strong></h2>
<p>不同的模型在當初被設計出來時的目的可能與我們的case不盡相同,擅長的方面也不同,而且在做完這個project後仍然陸續有許多新的model被推出,如:XLNet、GPT-3等等,甚至是有許多模型是以優化BERT為出發點所設計出來的,如:RoBERTa,因此我們或許可以集結各種不同model的長處,來達到我們建構模型的目的,而這也是目前各家經常採取的方式,從許多資料集的Leaderboard上就可以略窺一二:</br></p>
<ul>
<li>GLUE:<a href="https://gluebenchmark.com/leaderboard/">LeaderBoard</a></br></li>
<li>RACE:<a href="http://www.qizhexie.com/data/RACE_leaderboard.html">LeaderBoard</a></br></li>
<li>SQuAD:<a href="https://rajpurkar.github.io/SQuAD-explorer/">LeaderBoard</a></br></li>
</ul>
<p><font size = 4 color = #FF4500 ><strong>我們要做的就是保持開放且樂於學習的態度,汲取新知並應用在適合的project上</strong></font>。</p>
<p>更多集成式學習的詳細介紹及使用技巧可以參考以下文章:</br></p>
<ul>
<li><a href="http://violin-tao.blogspot.com/2018/01/ml-ensemble.html">Ensemble - Bagging, Boosting & Stacking</a></br></li>
<li><a href="https://www.coursera.org/lecture/competitive-data-science/ensembling-tips-and-tricks-XqLc1">Ensembling Tips and Tricks</a></br></li>
</ul>
<p></br></p>
<h2><strong>資料增強(Data Augmentation)</strong></h2>
<p>在NLP領域當中同樣也有學者提出增強式學習(Reinforcement Learning, RL)的方式來優化模型的表現,在2019年的研究論文提出可以<font color = #FF4500 ><strong>透過同意詞替換、隨機插入、隨機交換及隨機刪除等四種方式來達到資料增強</strong></font>(<a href="https://arxiv.org/pdf/1901.11196.pdf">參考文章</a>)。
</br>
關於中文文本方面的應用,已經有人套用在專案上,可以參考:</br></p>
<ul>
<li><a href="https://github.com/zhanlaoban/EDA_NLP_for_Chinese">EDA_NLP_for_Chinese</a> </br></li>
</ul>
<p>或者是Microsoft研究團隊將RL應用在文字特徵提取上面,使模型提取的特徵更為精確來提升整體model預測的準確性(<a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2017/11/zhang.pdf">參考文章</a>)。
我們可以持續關注在這方面的研究,並篩選適合的內容應用在專案上。</p>
<p></br></p>
<h2><strong>演化式運算(Evolutionary Computation)</strong></h2>
<p>演化式運算的概念其實脫胎於生物演化,<font color = #FF4500 ><strong>最佳化</strong></font>是我們最終的目標,要達到勢必得經過一條漫漫長路,而在演化過程當中,會有生物競爭力低落而走進演化的死胡同(evolutionary dead end),就如同模型在進行參數組合最佳化的過程當中,少數模型表現的準確性會較差而被淘汰,最終留下符合最佳化目的且動用最少資源(符合最大簡約法)的模型參數。</br>
這種最佳化方式其實在許多研究領域當中都會被運用上,以我從事的巨量基因體資料研究為例:<font color = #FF4500 ><strong>數十億甚至數千億的基因體序列排序,比對基因體的功能,結合從古到今的氣候因子與基因體序列的關聯性,尋找生物最適分布範圍,推測出生物演化的途徑</strong> </font>。
這樣的計算方式能夠在確定所有的模型建構流程後,將模型參數優化至最佳狀態。</p>
<p><a href="https://web.ntnu.edu.tw/~tcchiang/recruit.htm">啟發式演算法 (metaheuristics) 之設計與應用</a>
<a href="https://www.sciencedirect.com/science/article/pii/S1568494601000242?via%3Dihub"></a></p>
<hr>
<h1><font size = 6 > <strong>參考文獻</strong> </font></h1>
<p><a href="https://www.kesci.com/home/project/5be7e948954d6e0010632ef2">文本分類算法錦集</a> </br>
<a href="https://taweihuang.hpd.io/2017/03/01/tfidf/">TF-IDF 演算法:快速計算單字與文章的關聯</a> </br>
<a href="https://zhuanlan.zhihu.com/p/152526817">TFIDF+Wordembedding无监督多标签文本分类算法(论文解读)</a> </br>
<a href="https://zhuanlan.zhihu.com/p/102208639">BERT下游任務</a>
<a href="https://web.stanford.edu/class/archive/cs/cs224n/cs224n.1184/lectures/lecture16-guest.pdf">Reinforcement Learning for NLP</a></p>
</div>
<div class="tag-cloud">
<p>
<a href="/tag/natural-language-processing.html">Natural Language Processing</a>
<a href="/tag/stock.html">Stock</a>
</p>
</div>
</article>
<footer>
<p>© Michael Chien 2020</p>
<p>
Built with <a href="http://getpelican.com" target="_blank">Pelican</a> using <a href="http://bit.ly/flex-pelican" target="_blank">Flex</a> theme
</p> </footer>
</main>
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "Blog",
"name": " Learning note & Build some side projects | Michael Chien ",
"url" : "",
"image": "static/profile.jpg",
"description": ""
}
</script>
</body>
</html>