Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 最近中文字幕免费在线看,91精品国产综合成人,99久久国产

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          javascript中的鍵盤抬起事件onkeyup實(shí)現(xiàn)文本域的輸入字?jǐn)?shù)控制

          實(shí)際運(yùn)用中啊隨處可見的就是PC端的字?jǐn)?shù)控制案例,如標(biāo)題只能多少字 內(nèi)容多少字 密碼多少長(zhǎng)度等等等等,那么這些功能它是怎么實(shí)現(xiàn)的呢,今兒這個(gè)小分享道哥就給大家分享一下怎么用js去實(shí)現(xiàn)文字的輸入控制。

          已知有如下html代碼

          <p class="p1"> 
          計(jì)算剩余字?jǐn)?shù)<br> 
          <textarea cols="70" rows="8" id="msg" onkeyup="test()"></textarea><br> 
          <span id="msg_s"></span> 	
          </p>
          

          要實(shí)現(xiàn)在文本域textarea中輸入長(zhǎng)度不能超過50的字符并且剩余字?jǐn)?shù)跟隨輸入的內(nèi)容不斷變化,提示還可以輸入多少個(gè)字符 (要注意的是一個(gè)中文占兩個(gè)字符 一個(gè)英文字母或者符號(hào)占一個(gè)字符)

          代碼如下

          <script type="text/javascript">
          	function test2(){
          		//取出文本框中文本內(nèi)容 
          		var a=document.getElementById("msg");
          		var len=50-a.value.length; //與50作比較,得道剩余字?jǐn)?shù)
          		if(len>0){ 
          			//如果剩余字?jǐn)?shù)大于0,則提示剩余字?jǐn)?shù)
          			document.getElementById("msg_s").innerHTML="您還剩余"+len+"個(gè)字";
          		}else{
          			//如果剩余字?jǐn)?shù)小于0,即字?jǐn)?shù)已超出,則只留前50個(gè)字
          			document.getElementById("msg_s").innerHTML="您還剩余0個(gè)字";
          			a.value=a.value.substr(0,50);
          		}
          	}
          </script>
          

          運(yùn)行結(jié)果如下

          家好,我是站長(zhǎng) polarisxu。

          今天要聊的內(nèi)容應(yīng)該可以當(dāng)做一道面試題,你可以先想想該怎么實(shí)現(xiàn)。

          統(tǒng)計(jì)字?jǐn)?shù)是一個(gè)很常見的需求,很多人印象最深的應(yīng)該是微博早些時(shí)候限制 140 字,而且邊輸入會(huì)邊統(tǒng)計(jì)剩余字?jǐn)?shù)?,F(xiàn)在很多社區(qū)文章也會(huì)有字?jǐn)?shù)統(tǒng)計(jì)的功能,而且可以依據(jù)字?jǐn)?shù)來預(yù)估閱讀時(shí)間。比如 Go語言中文網(wǎng)就有這樣的功能。

          01 需求分析

          下手之前先分析下這個(gè)需求。從我個(gè)人經(jīng)驗(yàn)看,在實(shí)際面試中,針對(duì)一個(gè)面試題,你的分析過程,循序漸進(jìn)的解決方案,可以很好的展示你的思考過程。正所謂分析問題、解決問題。這會(huì)給你加分的。

          我們采用類似詞法分析的思路分析這個(gè)需求。

          一篇文章通常包含如下元素,我們也稱之為 token:

          • 普通文字
          • 標(biāo)點(diǎn)符號(hào)
          • 圖片
          • 鏈接(包含各種協(xié)議的鏈接)
          • 代碼

          其中普通文字通常會(huì)分為歐美和中日韓(CJK),因?yàn)?CJK 屬于表意文字,和歐美字母的文字差異很大。同時(shí)這里還涉及到編碼的問題。本文假設(shè)使用 UTF-8 編碼。

          對(duì)于標(biāo)點(diǎn)符號(hào),中文標(biāo)點(diǎn)和英文標(biāo)點(diǎn)也會(huì)很不一樣。

          此外還有全角和半角的問題。

          根據(jù)以上分析,對(duì)于該需求作如下假定:

          • 空格(包括換行)不算字?jǐn)?shù);
          • HTML 標(biāo)簽需要剔除;
          • 編碼方式:假定為 UTF-8 編碼;
          • 標(biāo)點(diǎn)符號(hào)算不算做字?jǐn)?shù)。如果算,像括號(hào)這樣的按 2 個(gè)字算;
          • 鏈接怎么算?一個(gè)鏈接約定為 1 個(gè)字可能更合適,大概閱讀時(shí)只是把它當(dāng)鏈接,而不太會(huì)關(guān)心鏈接由什么字母組成;
          • 圖片不算做字?jǐn)?shù),但如果計(jì)算閱讀時(shí)間,可能需要適當(dāng)考慮圖片的影響;
          • 對(duì)于技術(shù)文章,代碼是最麻煩的。統(tǒng)計(jì)代碼字?jǐn)?shù)感覺是沒多大意義的。統(tǒng)計(jì)代碼行數(shù)可能更有意義;

          本文的解決方案針對(duì)以上的假定進(jìn)行。

          02 Go 語言實(shí)現(xiàn)

          先看最簡(jiǎn)單的。

          純英文

          根據(jù)以上分析,如果文章只包含普通文本且是英文,也就是說,每個(gè)字(單詞)根據(jù)空格分隔,統(tǒng)計(jì)是最簡(jiǎn)單的。

          func TotalWords(s string) int {
           n := 0
           inWord := false
           for _, r := range s {
            wasInWord := inWord
            inWord = !unicode.IsSpace(r)
            if inWord && !wasInWord {
             n++
            }
           }
           return n
          }
          

          還有一種更簡(jiǎn)單的方式:

          len(strings.Fields(s))
          

          不過看 strings.Fields 的實(shí)現(xiàn),性能會(huì)不如第一種方式。

          回顧上面的需求分析,會(huì)發(fā)現(xiàn)這個(gè)實(shí)現(xiàn)是有 Bug 的。比如下面的例子:

          s1 := "Hello,playground"
          s2 := "Hello, playground"
          

          用上面的實(shí)現(xiàn),s1 的字?jǐn)?shù)是 1,s2 的字?jǐn)?shù)是 2。它們都忽略了標(biāo)點(diǎn)符號(hào)。而且因?yàn)閷懛ǖ亩鄻有裕ú灰?guī)范統(tǒng)一),導(dǎo)致計(jì)算字?jǐn)?shù)會(huì)有誤差。所以我們需要對(duì)寫法進(jìn)行規(guī)范。

          規(guī)范排版

          其實(shí)和寫代碼要有規(guī)范一樣,文章也是有規(guī)范的。比如出版社對(duì)于一本書的排版會(huì)有明確的規(guī)定。為了讓我們的文章看起來更舒服,也應(yīng)該遵循一定的規(guī)范。

          這里推薦一個(gè) GitHub 上的排版指南:《中文文案排版指北》,它的宗旨,統(tǒng)一中文文案、排版的相關(guān)用法,降低團(tuán)隊(duì)成員之間的溝通成本,增強(qiáng)網(wǎng)站氣質(zhì)。這個(gè)規(guī)范開頭關(guān)于空格的一段話很有意思:

          有研究顯示,打字的時(shí)候不喜歡在中文和英文之間加空格的人,感情路都走得很辛苦,有七成的比例會(huì)在 34 歲的時(shí)候跟自己不愛的人結(jié)婚,而其余三成的人最后只能把遺產(chǎn)留給自己的貓。畢竟愛情跟書寫都需要適時(shí)地留白。

          建議大家可以看看這個(gè)指北,一些知名的網(wǎng)站就是按照這個(gè)做的。

          因?yàn)?GCTT 的排版在這個(gè)規(guī)范做,但人為約束不是最好的方法,所以我開發(fā)了一個(gè) Go 工具:https://github.com/studygolang/autocorrect,用于自動(dòng)給中英文之間加入合理的空格并糾正專用名詞大小寫。

          所以為了讓字?jǐn)?shù)統(tǒng)計(jì)更準(zhǔn)確,我們假定文章是按一定的規(guī)范書寫的。比如上面的例子,規(guī)范的寫法是 s2 := "Hello, playground"。不過這里標(biāo)點(diǎn)不算作字?jǐn)?shù)。

          剛?cè)ノ⒉┥显嚵艘幌拢l(fā)現(xiàn)微博的字?jǐn)?shù)計(jì)算方式有點(diǎn)詭異,竟然是 9 個(gè)字。

          測(cè)試一下發(fā)現(xiàn),它直接把兩個(gè)英文字母算作一個(gè)字(兩個(gè)字節(jié)算一個(gè)字)。而漢字是正常的。大家可以想想微博是怎么實(shí)現(xiàn)的。

          中英文混合

          中文不像英文,單詞之間沒有空格分隔,因此開始的那兩種方式不適合。

          如果是純中文,我們?cè)趺从?jì)算字?jǐn)?shù)呢?

          在 Go 語言中,字符串使用 UTF-8 編碼,一個(gè)字符用 rune 表示。因此在標(biāo)準(zhǔn)庫中查找相關(guān)計(jì)算方法。

          func RuneCountInString(s string) (n int)
          

          這個(gè)方法能計(jì)算字符串包含的 rune(字符)數(shù),對(duì)于純中文,就是漢字?jǐn)?shù)。

          str := "你好世界"
          fmt.Println(utf8.RuneCountInString(str))
          

          以上代碼輸出 4。

          然而,因?yàn)楹芏鄷r(shí)候文章會(huì)中英文混合,因此我們先采用上面的純英文的處理方式,即:strings.Fields(),將文章用空格分隔,然后處理每一部分。

          func TotalWords(s string) int {
           wordCount := 0
            
           plainWords := strings.Fields(s)
           for _, word := range plainWords {
            runeCount := utf8.RuneCountInString(word)
            if len(word) == runeCount {
             wordCount++
            } else {
             wordCount += runeCount
            }
           }
          
           return wordCount
          }
          

          增加如下的測(cè)試用例:

          func TestTotalWords(t *testing.T) {
           tests := []struct {
            name  string
            input string
            want  int
           }{
            {"en1", "hello,playground", 2},
            {"en2", "hello, playground", 2},
            {"cn1", "你好世界", 4},
            {"encn1", "Hello你好世界", 5},
            {"encn2", "Hello 你好世界", 5},
           }
           for _, tt := range tests {
            t.Run(tt.name, func(t *testing.T) {
             if got := wordscount.TotalWords(tt.input); got != tt.want {
              t.Errorf("TotalWords() = %v, want %v", got, tt.want)
             }
            })
           }
          }
          

          發(fā)現(xiàn) en1 和 encn1 測(cè)試不通過,因?yàn)闆]有按照上面說的規(guī)范書寫。因此我們通過程序增加必要的空格。

          // AutoSpace 自動(dòng)給中英文之間加上空格
          func AutoSpace(str string) string {
           out := ""
          
           for _, r := range str {
            out = addSpaceAtBoundary(out, r)
           }
          
           return out
          }
          
          func addSpaceAtBoundary(prefix string, nextChar rune) string {
           if len(prefix) == 0 {
            return string(nextChar)
           }
          
           r, size := utf8.DecodeLastRuneInString(prefix)
           if isLatin(size) != isLatin(utf8.RuneLen(nextChar)) &&
            isAllowSpace(nextChar) && isAllowSpace(r) {
            return prefix + " " + string(nextChar)
           }
          
           return prefix + string(nextChar)
          }
          
          func isLatin(size int) bool {
           return size == 1
          }
          
          func isAllowSpace(r rune) bool {
           return !unicode.IsSpace(r) && !unicode.IsPunct(r)
          }
          

          這樣可以在 TotalWords 函數(shù)開頭增加 AutoSpace 進(jìn)行規(guī)范化。這時(shí)結(jié)果就正常了。

          處理標(biāo)點(diǎn)和其他類型

          以上例子標(biāo)點(diǎn)沒計(jì)算在內(nèi),而且如果英文和中文標(biāo)點(diǎn)混合在一起,情況又復(fù)雜了。

          為了更好地實(shí)現(xiàn)開始的需求分析,重構(gòu)以上代碼,設(shè)計(jì)如下的結(jié)構(gòu):

          type Counter struct {
           Total     int // 總字?jǐn)?shù) = Words + Puncts
           Words     int // 只包含字符數(shù)
           Puncts    int // 標(biāo)點(diǎn)數(shù)
           Links     int // 鏈接數(shù)
           Pics      int // 圖片數(shù)
           CodeLines int // 代碼行數(shù)
          }
          

          同時(shí)將 TotalWords 重構(gòu)為 Counter 的 Stat 方法,同時(shí)記錄標(biāo)點(diǎn)數(shù):

          func (wc *Counter) Stat(str string) {
           wc.Links = len(rxStrict.FindAllString(str, -1))
           wc.Pics = len(imgReg.FindAllString(str, -1))
          
           // 剔除 HTML
           str = StripHTML(str)
          
           str = AutoSpace(str)
          
           // 普通的鏈接去除(非 HTML 標(biāo)簽鏈接)
           str = rxStrict.ReplaceAllString(str, " ")
           plainWords := strings.Fields(str)
          
           for _, plainWord := range plainWords {
            words := strings.FieldsFunc(plainWord, func(r rune) bool {
             if unicode.IsPunct(r) {
              wc.Puncts++
              return true
             }
             return false
            })
          
            for _, word := range words {
             runeCount := utf8.RuneCountInString(word)
             if len(word) == runeCount {
              wc.Words++
             } else {
              wc.Words += runeCount
             }
            }
           }
          
           wc.Total = wc.Words + wc.Puncts
          }
          
          var (
           rxStrict = xurls.Strict()
           imgReg   = regexp.MustCompile(`<img [^>]*>`)
           stripHTMLReplacer = strings.NewReplacer("\n", " ", "</p>", "\n", "<br>", "\n", "<br />", "\n")
          )
          
          // StripHTML accepts a string, strips out all HTML tags and returns it.
          func StripHTML(s string) string {
           // Shortcut strings with no tags in them
           if !strings.ContainsAny(s, "<>") {
            return s
           }
           s = stripHTMLReplacer.Replace(s)
          
           // Walk through the string removing all tags
           b := GetBuffer()
           defer PutBuffer(b)
           var inTag, isSpace, wasSpace bool
           for _, r := range s {
            if !inTag {
             isSpace = false
            }
          
            switch {
            case r == '<':
             inTag = true
            case r == '>':
             inTag = false
            case unicode.IsSpace(r):
             isSpace = true
             fallthrough
            default:
             if !inTag && (!isSpace || (isSpace && !wasSpace)) {
              b.WriteRune(r)
             }
            }
          
            wasSpace = isSpace
          
           }
           return b.String()
          }
          

          代碼過多的細(xì)節(jié)不討論。此外,關(guān)于文章內(nèi)的代碼行數(shù)統(tǒng)計(jì)未實(shí)現(xiàn)(目前沒有想到特別好的方法,如果你有,歡迎交流)。

          03 總結(jié)

          通過本文的分析發(fā)現(xiàn),精準(zhǔn)統(tǒng)計(jì)字?jǐn)?shù)沒那么容易,這里涉及到很多的細(xì)節(jié)。

          當(dāng)然,實(shí)際應(yīng)用中,字?jǐn)?shù)不需要那么特別精準(zhǔn),而且對(duì)于非正常文字(比如鏈接、代碼)怎么處理,會(huì)有不同的約定。

          本文涉及到的完整代碼放在 GitHub:https://github.com/polaris1119/wordscount。

          自floydhub

          作者:Alfrick Opidi

          機(jī)器之心編譯

          參與:杜偉、張倩

          我們?cè)陂喿x新聞報(bào)道等實(shí)時(shí)性文章時(shí),需要快速歸納出文章的大意。但是,如果將一篇很長(zhǎng)的文章歸納成一個(gè)能夠涵蓋原文中心思想的小段落,則需要我們耗費(fèi)大量時(shí)間。本文介紹了自然語言處理中的兩種文本自動(dòng)摘要生成方法——抽取式和抽象式文本摘要。這兩種方法通過計(jì)算文本中句子成分的權(quán)重來生成摘要,可以大大節(jié)省通讀全文以及歸納總結(jié)主要信息的時(shí)間,為讀者提供方便。

          你是否曾將一篇冗長(zhǎng)的文檔歸納為一個(gè)小的段落?你用了多長(zhǎng)時(shí)間呢?手動(dòng)歸納總結(jié)耗費(fèi)時(shí)間、枯燥乏味。文本自動(dòng)摘要可以克服此類難題,幫你輕松歸納出一篇文章的中心思想。

          文本摘要方法能夠?qū)θ唛L(zhǎng)文本進(jìn)行簡(jiǎn)潔準(zhǔn)確的總結(jié),同時(shí)將重點(diǎn)放在傳達(dá)有用信息的章節(jié),而又不失去文章大意。

          文本自動(dòng)摘要旨在將冗長(zhǎng)文檔變成縮寫版本,若手動(dòng)完成則可能非常麻煩且成本高昂。

          在生成需要的摘要文本之前,機(jī)器學(xué)習(xí)算法可被訓(xùn)練用以理解文檔,識(shí)別傳達(dá)重要事實(shí)和信息的章節(jié)。

          使用文本摘要機(jī)器學(xué)習(xí)算法生成一篇在線新聞文章的摘要。

          文本自動(dòng)摘要的必要性

          隨著目前數(shù)字空間中數(shù)據(jù)的爆炸式增長(zhǎng),而大多又是非結(jié)構(gòu)化的文本數(shù)據(jù),因而需要開發(fā)文本自動(dòng)摘要工具,使人們可以輕易獲知文本大意。當(dāng)前,我們可以快速訪問大量信息。但是,大多數(shù)信息冗長(zhǎng)、無關(guān)緊要,還可能無法傳達(dá)其本意。例如,如果你想從一篇在線新聞報(bào)道中搜尋一些特定信息,你也許要吃透報(bào)道內(nèi)容,花費(fèi)大量時(shí)間剔除無用信息,之后才能找到自己想要了解的信息。所以,使用能夠提取有用信息并剔除無關(guān)緊要和無用數(shù)據(jù)的自動(dòng)文本摘要生成器變得非常重要。文本摘要的實(shí)現(xiàn)可以增強(qiáng)文檔的可讀性,減少搜尋信息的時(shí)間,獲得更多適用于特定領(lǐng)域的信息。

          文本自動(dòng)摘要的主要類型

          從廣義的角度看,自然語言處理(NLP)中有兩種文本摘要生成方法:抽取式和抽象式。

          抽取式摘要(extraction-based summarization)

          在抽取式摘要中,抽取一段文本中表示重點(diǎn)內(nèi)容的單詞子集,并結(jié)合起來生成摘要。我們可以將抽取式摘要看作是一支熒光筆-從源文本中抽取主要信息。

          熒光筆 = 抽取式摘要

          在機(jī)器學(xué)習(xí)中,抽取式摘要通常需要衡量基本句子成分的權(quán)重,并根據(jù)權(quán)重結(jié)果生成摘要。

          不同類型的算法和方法均可用于衡量句子的權(quán)重,之后根據(jù)各成分之間的關(guān)聯(lián)性和相似性進(jìn)行排序-并進(jìn)一步將這些成分連接起來以生成摘要。

          如下例所示:

          抽取式摘要

          如上例所示,抽取式摘要由熒光筆標(biāo)黃的單詞組成,生成摘要的語法可能不準(zhǔn)確。

          抽象式摘要

          在抽象式摘要中,高級(jí)深度學(xué)習(xí)方法(advanced deep learning technique)用于解釋和縮寫原始文檔,就像人類所做的一樣。將抽象式摘要想象成一支鋼筆-它能生成或許不屬于源文檔的新句子。

          鋼筆 = 抽象式摘要

          由于抽象式機(jī)器學(xué)習(xí)算法能夠生成表示源文本中最重要信息的新短語和句子,所以這些抽象式算法有助于克服抽取式摘要中的語法不準(zhǔn)確問題。

          如下例所示:

          抽象式摘要。

          盡管抽象式文本摘要的表現(xiàn)更好,但開發(fā)相關(guān)算法需要復(fù)雜的深度學(xué)習(xí)技巧和語言模型。

          為了獲得合理產(chǎn)出,抽象式摘要方法必須能夠解決諸多自然語言處理問題,如自然語言生成、語義表征和推理排序(inference permutation)。

          同樣地,抽取式文本摘要方法依然大受歡迎。在本文中,我們將重點(diǎn)介紹抽象式文本摘要方法。

          如何執(zhí)行文本摘要

          我們使用以下一段話展示如何執(zhí)行文本摘要抽?。?/p>

          我們依照以下步驟對(duì)這段話作總結(jié),同時(shí)盡可能保留原意。

          第一步:將這段話轉(zhuǎn)換成句子

          首先,我們將這段話分割成相應(yīng)的句子。轉(zhuǎn)換成句子的最佳方法是在句點(diǎn)(period)出現(xiàn)時(shí)提取一個(gè)句子。

          第二步:文本處理

          接下來,我們?cè)谖谋咎幚碇幸瞥V乖~(那些沒有實(shí)際意義的常見詞,如「and」和「the」)、數(shù)字、標(biāo)點(diǎn)符號(hào)以及句子中的其他特殊字符。

          句子成分的過濾有助于移除冗余和不重要的信息,這些信息對(duì)文本意圖的表達(dá)或許沒有任何價(jià)值。

          以下是文本處理結(jié)果:

          第三步:分詞

          切分各個(gè)句子,列出句子中的所有單詞。

          以下是單詞列表:

          ['peter','elizabeth','took','taxi','attend','night','party','city','party','elizabeth','collapse','rush','hospital', 'diagnose','brain', 'injury', 'doctor','told','peter','stay','besides','get','well','peter', 'stayed','hospital','days','without','leaving']
          

          第四步:評(píng)估單詞的加權(quán)出現(xiàn)頻率(occurrence frequency)

          緊接著,我們計(jì)算所有單詞的加權(quán)出現(xiàn)頻率。為此,我們用每個(gè)單詞的出現(xiàn)頻率除以這段話中出現(xiàn)最多次的單詞的頻率,在這段話中出現(xiàn)最多的是 Peter,總共出現(xiàn)了三次。

          下表給出了每個(gè)單詞的加權(quán)出現(xiàn)頻率。

          第五步:用相應(yīng)的加權(quán)頻率替代原句中的各個(gè)單詞,然后計(jì)算總和。

          我們?cè)谖谋咎幚聿襟E中已經(jīng)移除了停止詞和特殊字符等無關(guān)緊要的單詞,因而它們的加權(quán)頻率為零,也就沒有必要在計(jì)算時(shí)加上。

          根據(jù)所有單詞的加權(quán)頻率總和,我們可以推導(dǎo)出:第一個(gè)句子在整段話中的權(quán)重最大。所以,第一個(gè)句子能夠?qū)@段話的意思作出最具代表性的總結(jié)。

          此外,如果第一個(gè)句子與第三個(gè)句子(該句的權(quán)重在整段話中排第二)相結(jié)合,則可以作出更好的總結(jié)。

          以上例子只是基本說明了如何在機(jī)器學(xué)習(xí)中執(zhí)行抽取式文本摘要?,F(xiàn)在,我們看看如何在創(chuàng)建實(shí)際摘要生成器中運(yùn)用上述概念。

          維基百科文章的文本摘要

          讓我們動(dòng)手創(chuàng)建一個(gè)可以簡(jiǎn)化冗長(zhǎng) web 文章中信息的文本摘要生成器。為簡(jiǎn)單起見,除了 Python 的 NLTK toolkit,我們不使用任何其他機(jī)器學(xué)習(xí)庫(machine learning library)。

          以下是摘要生成器的代碼 blueprint:

          # Creating a dictionary for the word frequency table
          frequency_table = _create_dictionary_table(article)
          # Tokenizing the sentences
          sentences = sent_tokenize(article)
          # Algorithm for scoring a sentence by its words
          sentence_scores = _calculate_sentence_scores(sentences, frequency_table)
          # Getting the threshold
          threshold = _calculate_average_score(sentence_scores)
          # Producing the summary
          article_summary = _get_article_summary(sentences, sentence_scores, 1.5 * threshold)
          print(article_summary)
          

          依照下列步驟使用 Python 語言創(chuàng)建一個(gè)簡(jiǎn)單的文本摘要生成器。

          第一步:準(zhǔn)備數(shù)據(jù)

          在這個(gè)例子中,我們想總結(jié)一下這篇 Wikipedia 文章的信息,這篇文章只是對(duì) 20 世紀(jì)發(fā)生的主要事件進(jìn)行概述。

          為了獲取這篇文章的文本,我們將使用 Beautiful Soup 庫。

          以下是抓取文章內(nèi)容的代碼:

          import bs4 as BeautifulSoup
          import urllib.request 
          # Fetching the content from the URL
          fetched_data = urllib.request.urlopen('https://en.wikipedia.org/wiki/20th_century')
          article_read = fetched_data.read()
          # Parsing the URL content and storing in a variable
          article_parsed = BeautifulSoup.BeautifulSoup(article_read,'html.parser')
          # Returning <p> tags
          paragraphs = article_parsed.find_all('p')
          article_content = ''
          # Looping through the paragraphs and adding them to the variable
          for p in paragraphs: 
           article_content += p.text
          

          在以上代碼中,我們首先導(dǎo)入抓取網(wǎng)頁數(shù)據(jù)所必需的庫。BeautifulSoup 庫用于解析網(wǎng)頁內(nèi)容,而 urllib library 用于連接網(wǎng)頁和檢索 HTML。

          BeautifulSoup 將輸入文本轉(zhuǎn)化為 Unicode 字符,將輸出文本轉(zhuǎn)化為 UTF-8 字符,省去了從 web 上抓取文本時(shí)處理不同字符集編碼的麻煩。

          我們使用 urllib.request 程序中的 urlopen 函數(shù)打開網(wǎng)頁。之后,使用 read 函數(shù)讀取所抓取的數(shù)據(jù)對(duì)象。為了解析數(shù)據(jù),我們調(diào)用 BeautifulSoup 對(duì)象,并向它傳遞兩個(gè)參數(shù),即 article_read 和 html.parser。

          find_all 函數(shù)用于傳回 HTML 中出現(xiàn)的所有<p>元素。此外,.text 使我們只能選擇<p>元素中的文本。

          第二步:處理數(shù)據(jù)

          為盡可能確保廢棄的文本數(shù)據(jù)無噪聲,我們將執(zhí)行一些基本的文本清理(text cleaning)。為協(xié)助完成這一處理過程,我們將從 NLTK 庫中導(dǎo)入一個(gè)停止詞列表。

          我們還將引入 PorterStemmer,這是一種將單詞還原成詞根形式的算法。例如,單詞 cleaning、cleaned 和 cleaner 都可以還原成詞根 clean。

          此外,我們還將創(chuàng)建一個(gè)包含文本中每一單詞出現(xiàn)頻率的字典表。我們將依次讀取文本及相應(yīng)單詞,以消除所有停止詞。

          之后,我們將檢查單詞是否出現(xiàn)在 frequency_table 中。如果一個(gè)單詞之前就在字典中,則其值更新 1。否則,如果一個(gè)單詞首次被識(shí)別到,則其值設(shè)置為 1。

          例如,頻率表應(yīng)如下所示:

          代碼如下:

          from nltk.corpus import stopwords
          from nltk.stem import PorterStemmer
          def _create_dictionary_table(text_string) -> dict:
           # Removing stop words
           stop_words = set(stopwords.words("english"))
           words = word_tokenize(text_string)
           # Reducing words to their root form
           stem = PorterStemmer()
           # Creating dictionary for the word frequency table
           frequency_table = dict()
           for wd in words:
           wd = stem.stem(wd)
           if wd in stop_words:
           continue
           if wd in frequency_table:
           frequency_table[wd] += 1
           else:
           frequency_table[wd] = 1
           return frequency_table
          

          第三步:將文章分割成句子

          為了將 article_content 分割成一個(gè)句子集,我們將使用 NLTK 庫中的內(nèi)置方法。

          from nltk.tokenize import word_tokenize, sent_tokenize
          sentences = sent_tokenize(article)
          

          第四步:確定句子的加權(quán)頻率

          為了評(píng)估文本中每個(gè)句子的分?jǐn)?shù),我們將分析每個(gè)單詞的出現(xiàn)頻率。在這種情況下,我們將根據(jù)句子中的單詞對(duì)該句進(jìn)行評(píng)分,也就是加上句子中每個(gè)重要單詞的出現(xiàn)頻率。

          請(qǐng)看以下代碼:

          def _calculate_sentence_scores(sentences, frequency_table) -> dict: 
           # Algorithm for scoring a sentence by its words
           sentence_weight = dict()
           for sentence in sentences:
           sentence_wordcount = (len(word_tokenize(sentence)))
           sentence_wordcount_without_stop_words = 0
           for word_weight in frequency_table:
           if word_weight in sentence.lower():
           sentence_wordcount_without_stop_words += 1
           if sentence[:7] in sentence_weight:
           sentence_weight[sentence[:7]] += frequency_table[word_weight]
           else:
           sentence_weight[sentence[:7]] = frequency_table[word_weight]
           sentence_weight[sentence[:7]] = sentence_weight[sentence[:7]] / sentence_wordcount_without_stop_words
           return sentence_weight
          

          重要的是,為了避免長(zhǎng)句的分?jǐn)?shù)必然高于短句,我們用每個(gè)句子的分?jǐn)?shù)除以該句中的單詞數(shù)。

          另外,為了優(yōu)化字典內(nèi)存,我們?nèi)我馓砑?sentence[:7],這指的是每個(gè)句子的前七個(gè)字符。但在較長(zhǎng)的文檔中,你很可能遇到具有相同首個(gè) n_chars 的句子,這時(shí)最好使用哈希函數(shù)(hash function)或 index 函數(shù)(index function)來處理此類極端情況(edge-cases),避免沖突。

          第五步:計(jì)算句子閾值

          為了進(jìn)一步調(diào)整適合摘要的句子類型,我們將創(chuàng)建句子的平均分。借助于這個(gè)閾值,我們可以避免選擇分?jǐn)?shù)低于平均分的句子。

          代碼如下:

          def _calculate_average_score(sentence_weight) -> int:
           # Calculating the average score for the sentences
           sum_values = 0
           for entry in sentence_weight:
           sum_values += sentence_weight[entry]
           # Getting sentence average value from source text
           average_score = (sum_values / len(sentence_weight))
           return average_score
          

          第六步:生成摘要

          最后,我們擁有了所有必需的參數(shù),因而現(xiàn)在可以生成文章摘要了。

          代碼如下:

          def _get_article_summary(sentences, sentence_weight, threshold):
           sentence_counter = 0
           article_summary = ''
           for sentence in sentences:
           if sentence[:7] in sentence_weight and sentence_weight[sentence[:7]] >= (threshold):
           article_summary += " " + sentence
           sentence_counter += 1
           return article_summary
          

          總結(jié)

          下圖展示了創(chuàng)建文本摘要算法的工作流程。

          以下是機(jī)器學(xué)習(xí)中簡(jiǎn)單抽取式文本摘要生成器的完整代碼:

          #importing libraries
          from nltk.corpus import stopwords
          from nltk.stem import PorterStemmer
          from nltk.tokenize import word_tokenize, sent_tokenize
          import bs4 as BeautifulSoup
          import urllib.request 
          #fetching the content from the URL
          fetched_data = urllib.request.urlopen('https://en.wikipedia.org/wiki/20th_century')
          article_read = fetched_data.read()
          #parsing the URL content and storing in a variable
          article_parsed = BeautifulSoup.BeautifulSoup(article_read,'html.parser')
          #returning <p> tags
          paragraphs = article_parsed.find_all('p')
          article_content = ''
          #looping through the paragraphs and adding them to the variable
          for p in paragraphs: 
           article_content += p.text
          def _create_dictionary_table(text_string) -> dict:
           #removing stop words
           stop_words = set(stopwords.words("english"))
           words = word_tokenize(text_string)
           #reducing words to their root form
           stem = PorterStemmer()
           #creating dictionary for the word frequency table
           frequency_table = dict()
           for wd in words:
           wd = stem.stem(wd)
           if wd in stop_words:
           continue
           if wd in frequency_table:
           frequency_table[wd] += 1
           else:
           frequency_table[wd] = 1
           return frequency_table
          def _calculate_sentence_scores(sentences, frequency_table) -> dict: 
           #algorithm for scoring a sentence by its words
           sentence_weight = dict()
           for sentence in sentences:
           sentence_wordcount = (len(word_tokenize(sentence)))
           sentence_wordcount_without_stop_words = 0
           for word_weight in frequency_table:
           if word_weight in sentence.lower():
           sentence_wordcount_without_stop_words += 1
           if sentence[:7] in sentence_weight:
           sentence_weight[sentence[:7]] += frequency_table[word_weight]
           else:
           sentence_weight[sentence[:7]] = frequency_table[word_weight]
           sentence_weight[sentence[:7]] = sentence_weight[sentence[:7]] / sentence_wordcount_without_stop_words
           return sentence_weight
          def _calculate_average_score(sentence_weight) -> int:
           #calculating the average score for the sentences
           sum_values = 0
           for entry in sentence_weight:
           sum_values += sentence_weight[entry]
           #getting sentence average value from source text
           average_score = (sum_values / len(sentence_weight))
           return average_score
          def _get_article_summary(sentences, sentence_weight, threshold):
           sentence_counter = 0
           article_summary = ''
           for sentence in sentences:
           if sentence[:7] in sentence_weight and sentence_weight[sentence[:7]] >= (threshold):
           article_summary += " " + sentence
           sentence_counter += 1
           return article_summary
          def _run_article_summary(article):
           #creating a dictionary for the word frequency table
           frequency_table = _create_dictionary_table(article)
           #tokenizing the sentences
           sentences = sent_tokenize(article)
           #algorithm for scoring a sentence by its words
           sentence_scores = _calculate_sentence_scores(sentences, frequency_table)
           #getting the threshold
           threshold = _calculate_average_score(sentence_scores)
           #producing the summary
           article_summary = _get_article_summary(sentences, sentence_scores, 1.5 * threshold)
           return article_summary
          if __name__ == '__main__':
           summary_results = _run_article_summary(article_content)
           print(summary_results)
          

          點(diǎn)擊原文中的以下按鈕在 FloydHub Notebook 上運(yùn)行代碼:

          在這個(gè)例子中,我們所采用的閾值是平均分的 1.5 倍。這個(gè)超參數(shù)值(hyperparameter value)在幾次試驗(yàn)后為我們生成了良好的結(jié)果。當(dāng)然,你可以根據(jù)自身的偏好對(duì)數(shù)值進(jìn)行微調(diào),并改進(jìn)摘要生成效果。

          下圖是 Wikipedia 文章的生成摘要。

          使用文本摘要算法生成的 Wikipedia 文章摘要。

          如你所見,運(yùn)行代碼可以對(duì)冗長(zhǎng)的 Wikipedia 文章進(jìn)行總結(jié),并簡(jiǎn)要概述 20 世紀(jì)發(fā)生的主要事件。

          盡管如此,我們還可以改進(jìn)摘要生成器,使之更好地生成長(zhǎng)篇幅文本的簡(jiǎn)潔、精確摘要。

          更多內(nèi)容

          當(dāng)然,本文只是簡(jiǎn)要介紹了機(jī)器學(xué)習(xí)中使用文本摘要算法所能實(shí)現(xiàn)的功能。

          若想了解更多有關(guān)該主題,特別是抽象式文本摘要的知識(shí),下面一些有用的資源可以為你提供幫助:

          有沒有可能將兩種方法(抽象式和抽取式文本自動(dòng)摘要)相結(jié)合?這是指針生成網(wǎng)絡(luò)(pointer generator network)的主要原理,該網(wǎng)絡(luò)通過結(jié)合抽取(指向)和抽象(生成)取得了最佳效果。

          圖源:"Taming Recurrent Neural Networks for Better Summarization"

          《WikiHow: A Large Scale Text Summarization Dataset》一文提出了一個(gè)新的大規(guī)模文本自動(dòng)摘要數(shù)據(jù)集 WikiHow,該數(shù)據(jù)集包含提取自 WikiHow 在線知識(shí)庫的 230000 多篇文章。目前可用的大多數(shù)數(shù)據(jù)集的規(guī)模不足以訓(xùn)練序列到序列模型,它們也許只能提供有限的摘要,并且更適合執(zhí)行抽取式摘要。但是,WikiHow 數(shù)據(jù)集規(guī)模大,質(zhì)量高,能夠在抽象式文本摘要中獲得最優(yōu)結(jié)果。

          《Pretraining-Based Natural Language Generation for Text Summarization》一文提出了一個(gè)基于序列到序列范式的獨(dú)特二階段模型。該模型同時(shí)在編碼器和解碼器側(cè)利用 BERT,并在學(xué)習(xí)過程中注重強(qiáng)化目標(biāo)。當(dāng)該模型在一些基準(zhǔn)數(shù)據(jù)集上進(jìn)行評(píng)估時(shí),結(jié)果顯示,該方法在文本自動(dòng)摘要中表現(xiàn)更好,尤其相較于其他傳統(tǒng)系統(tǒng)而言。

          原文鏈接:https://blog.floydhub.com/gentle-introduction-to-text-summarization-in-machine-learning/

          本文為機(jī)器之心編譯,轉(zhuǎn)載請(qǐng)聯(lián)系本公眾號(hào)獲得授權(quán)。

          ?------------------------------------------------

          加入機(jī)器之心(全職記者 / 實(shí)習(xí)生):hr@jiqizhixin.com

          投稿或?qū)で髨?bào)道:content@jiqizhixin.com

          廣告 & 商務(wù)合作:bd@jiqizhixin.com


          主站蜘蛛池模板: 国产精品合集一区二区三区 | 熟女精品视频一区二区三区| 国产精品久久久久一区二区| 天天爽夜夜爽人人爽一区二区| 亚洲av日韩综合一区久热| 91在线一区二区三区| 精品免费久久久久国产一区| 少妇人妻精品一区二区三区| 国产韩国精品一区二区三区 | 日本在线不卡一区| 午夜福利国产一区二区| 国产在线精品一区在线观看| 国产一区视频在线| 国产AV一区二区三区无码野战| 亚洲国产成人久久一区久久| 国产伦精品一区二区三区在线观看 | 精品乱子伦一区二区三区高清免费播放 | 高清一区二区三区视频| 日本一区二区三区精品国产| 国产成人无码aa精品一区| 另类ts人妖一区二区三区| 亚洲电影唐人社一区二区| 精品国产福利一区二区| 无码av人妻一区二区三区四区| 日韩精品一区二区三区老鸭窝 | 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久伊人精品一区二区三区| 一区二区三区午夜视频| 日韩精品一区二区三区国语自制| 日韩伦理一区二区| 国产视频一区二区在线播放| 亚洲综合av一区二区三区| 一级毛片完整版免费播放一区 | 亚洲av乱码一区二区三区香蕉| 在线免费视频一区| 无码国产伦一区二区三区视频| 在线免费观看一区二区三区| 国偷自产一区二区免费视频| 国内精品一区二区三区最新| 中文字幕一区二区三区永久 | 国产精品熟女视频一区二区|