在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 語言標簽
與四軸無人機的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動開發(fā)
Collection View 動畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進的自動布局工具箱
動畫
為 iOS 7 重新設(shè)計 App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項目介紹
Swift 的強大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計優(yōu)雅的移動游戲
繪制像素到屏幕上
相機與照片
音頻 API 一覽
交互式動畫
常見的后臺實踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機項目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動追蹤
依賴注入
Swift
項目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實戰(zhàn)
iOS 7
Layer 中自定義屬性的動畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機捕捉
語言標簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機工作原理
Build 過程

語言標簽

當(dāng)我們處理自然語言(相對于程序語言而言)的時候會遇到一項挑戰(zhàn),即涵義模棱兩可。程序語言是被設(shè)計成為有且只有一個可能解釋的語言,而人類語言可能由于模糊性和不確定性衍生出很多問題。這是由于有時候你并不想確切地告訴別人你對某事物的想法。在社交場合這完全沒有問題,但是當(dāng)你試圖使用計算機來處理人類語言的話,就會非常痛苦。

詞法標識(token)就是一個簡單的例子。程序語言的詞法分析對于標識表示什么,它是什么類型(語句分隔符,標識符,保留關(guān)鍵字等等)是什么有著明確的規(guī)則。而自然語言則遠不能如此清晰可辯。can’t 是一個還是兩個標識?并且根據(jù)你做出的判斷,cannot 或者 can not 這兩個應(yīng)該是相同意思的詞又各是幾個標識呢?很多復(fù)合詞都可以寫成一個詞(比如:bookshelf),或者兩個詞(比如:lawn mower),甚至還可以用連字符來連接(比如:life-cycle)。有些字符 (比如說連字符或者右肩單撇號),可以有很多種解釋,而如何選擇正確字符往往取決于上下文語言環(huán)境(撇號在一個單詞的最后是表示所有格符號還是后單引號?)

句子的情況同樣不怎么好:如果簡單認為句號是用來結(jié)束一個句子的話,在我們使用縮寫或是序數(shù)的時候就悲劇了。雖然通常情況下,我們是可以解決這個問題的,但是對有些句子而言,除非將整個段落徹底分析,否則無法真正確定這些句子的意思。我們?nèi)祟惿踔烈矡o法有意識地考慮這些問題。

不過我們希望能夠處理人類語言,因為在跟軟件交流的時候,使用人類語言對用戶更加友好。我們更愿意直接告訴計算機要做什么,讓計算機為我們分析報紙文章,并對我們感興趣的新聞做個總結(jié),而不是通過敲擊鍵盤或者點擊小小的按鈕(或者在小小的虛擬鍵盤上打字)來讓計算機為我們做這些事。其中有些還在我們的能力范圍之外(至少在蘋果為我們提供與 Siri 交互的 API 之前)。但是有些已經(jīng)成為可能,那就是 NSLinguisticTagger。

NSLinguisticTagger 是 Foundation 框架中命名極為不當(dāng)?shù)念愔?,這是因為它遠遠不止是一個小小的詞性 tagger,而是集詞法分析,分詞器,命名實體識別及詞性標注為一體的類。換句話說,它幾乎可以滿足你處理某些計算機語言處理的全部要求。

為了展示 NSLinguisticTagger 類的用法,我們會開發(fā)一個靈活的工具用來搜索。我們有一個充滿了文本(比如新聞,電郵,或者其他的任意文本)的集合,然后我們輸入一個單詞,這個單詞將返回所有包含這個單詞的句子。我們會忽略功能詞(比如 theof 或者 and),因為它們在這個語言環(huán)境中太過于常見,沒有什么用處。我們目前要實現(xiàn)的是第一步:從一個單獨文件中提取相關(guān)單詞。由此可以迅速地擴展到提供完整功能。

GitHub 上有源代碼和樣本文本。這是《衛(wèi)報》上一篇關(guān)于中英貿(mào)易的文章。當(dāng)用軟件分析這份文本時,你會發(fā)現(xiàn),它并不是總是運行良好,不過,出現(xiàn)運行故障完全正常:人類語言和任何正式語言都不同,人類語言凌亂復(fù)雜,無法簡單劃歸到整齊劃一的規(guī)則系統(tǒng)。很多理論問題(哪怕就像詞性一樣基礎(chǔ)的問題)在某種程度上是無法解決的,這是由于我們?nèi)匀粚θ绾尾拍茏詈玫孛枋稣Z言還所知甚少。比如說,詞的分類是以拉丁語為依據(jù)的,但這并不意味著就必定適合英語。它們充其量只是大概近似而已。不過從很多實際的目的來看,這樣就已經(jīng)足夠了,不需要讓人怎么擔(dān)心了。

標簽體系 (Tag Schemes)

注釋和標記文本的核心方法就是標簽體系的核心方法。以下是幾個可用的標簽體系:

  • NSLinguisticTagSchemeTokenType
  • NSLinguisticTagSchemeLexicalClass
  • NSLinguisticTagSchemeNameType
  • NSLinguisticTagSchemeNameTypeOrLexicalClass
  • NSLinguisticTagSchemeLemma
  • NSLinguisticTagSchemeLanguage
  • NSLinguisticTagSchemeScript

NSLinguisticTagger 實例掃描文本中的所有條目,并調(diào)用一個包含被請求的標簽體系值的 block。最基礎(chǔ)的是 NSLinguisticTagSchemeTokenType:詞,標點,空格,或是“其他”。我們可以使用這個來識別哪些是真正的詞,那么我們在應(yīng)用程序中就可以簡單地忽略其他那些不是有效詞的語素。NSLinguisticTagSchemeLexicalClass 和詞性有關(guān),是一組非常基礎(chǔ)的標簽(就嚴格意義上的語言分析而言,這組標簽還遠遠不夠精細),我們可以使用這組標簽來分辨我們想要的實詞(名詞,動詞,形容詞,副詞)和我們想忽略的虛詞(連詞,介詞,冠詞等等)。在 NSLinguisticTagger 類的文檔中寫明了全套可能值。

NSLinguisticTagSchemeNameType 是指命名實體識別:我們可以知道一個詞是不是表示人物,地點或者組織。同樣的,這相對于自然語言的處理而言是相當(dāng)基本,但卻非常有用的,比如說你想搜索一個特定的人物或者地點。還有一種潛在的應(yīng)用是“給我一份文本中所提到的所有政治家的名錄”,你可以瀏覽這份文本中的人名,然后查閱數(shù)據(jù)庫(比如維基)來核對他們是否確實是政治家。這也可以跟 lexical 類相結(jié)合,因為這往往包含一個分類叫做“名字”。

NSLinguisticTagSchemeLemma 是詞匯的標準形式,或者說是其基本形式。對英語而言,這不是什么大問題,不過對于其它語言而言卻重要得多。原型基本上就是你在詞典中查的到的那個形式。比如說,tables 是一個復(fù)數(shù)名詞,它的基本形式是單數(shù)的 table。同樣的,動詞 running 是由 run 變形而來的不定式。如果你想要以同樣的方式處理各種詞類的變形,使用原形就非常有用,事實上這也是我們要為我們的示例應(yīng)用程序所做的 (因為這可以有助于保持索引不過于龐大)。

NSLinguisticTagSchemeLanguage 和我們所使用的語言相關(guān)。如果你使用iOS(截至iOS7),目前只能處理英語。使用OS X(截至10.9 / Mavericks)你可以稍微多幾種語言可以選擇。+[NSLinguisticTagger availableTagSchemesForLanguage:] 方法為我們列舉了對于給定語言的所有可用體系。對于在 iOS 中對應(yīng)語言數(shù)量限制的原因很可能是資源文件要占用大量空間。在筆記本或者臺式電腦上不是什么大問題,但是在手機或者平板上的話就不太妙了。

NSLinguisticTagSchemeScript 是書寫體系,比如拉丁字母 (Latin),西里爾字母 (Cyrillic) 等等。對于英語,我們將使用拉丁字母。如果你知道你將處理哪種語言,使用 setOrthography 方法可以改善標簽的結(jié)果,特別對相對較短的字符而言更是如此。

標簽選項

目前我們已經(jīng)知道 NSLinguisticTagger 可以為我們識別什么了,我們需要告訴它我們想要什么,以及我們想如何獲得。這里有幾個可以定義 tagger 行為的選項,它們都是 NSUInteger 類型的,并且可以使用位運算 OR 組合使用。

第一個選項是“省略單詞”,除非你只想看標點或者其它非詞類,否則這個選項毫無意義。比較有用的是下面的三個選項:“省略標點(omit punctuation)”,“省略空格(omit whitespace)”以及“省略其他(omit other)”。除非你想要對文本做全面語言分析,否則你基本上只會對單詞感興趣,而對其中的逗號句號則興趣不大。有了這些選項,就可以輕輕松松讓 tagger 對單詞作出限制,再也不用掛慮在心。最后一個選項是“連接名字(join names)”,因為名字有時不僅僅是一個標識。這個選項會將它們結(jié)合在一起,作為一個獨立的語言單位來處理。這個選項可能不會總是用得上,但是確實非常有用。舉個例子,在樣本文本中,字符串“Owen Patterson”被識別為一個名稱,并且作為一個獨立的語言單位被返回。

處理架構(gòu)

程序會給一定數(shù)量的文本在獨立文件中建立索引(我們假設(shè)是使用UTF-8編碼)。我們將使用一個 FileProcessor 類來處理一個單獨文件,將文件內(nèi)容分為一個一個單詞,再把這些單詞傳遞給另一類來進行處理。后一個類將實現(xiàn) WordReceiver 接口,其中包括一個方法:

-(void)receiveWord:(NSDictionary*)word

我們不是使用 NSString 來表示單詞,而是使用字典,這是因為一個單詞會有很多屬性,包括實際標識,詞性或名稱類型,原型,所在句子的數(shù)目,句子中的位置等。為了建立索引,我們還想儲存文件名。調(diào)用 FileProcessor 的這個方法:

- (BOOL)processFile:(NSString*)filename

將觸發(fā)分析,如果一切進行順利的話,返回 YES,在出現(xiàn)錯誤的時候返回 NO。它首先由文件創(chuàng)建一個 NSString,然后將其傳遞給一個 NSLinguisticTagger 實例來處理。

NSLinguisticTagger 主要做的是的在一個 NSString 中進行掃描并對尋找到的每一個元素調(diào)用 block。為了稍作簡化,我們首先將文本分解為一個個的句子,然后分別掃描每一個句子。這樣比較容易追蹤句子的 ID。至于標簽,我們會處理大量的 NSRange,它們可以被用來界定源文件中文本的注解。我們從在第一個句子范圍內(nèi)創(chuàng)建一個搜索范圍開始,并使用其在最大程度上獲得初始語句的標簽。

NSRange currentSentence = [tagger sentenceRangeForRange:NSMakeRange(0, 1)];

一旦句子處理結(jié)束,就檢查是否成功完成全部的文本,或者是否還有更多的句子等待處理:

if (currentSentence.location + currentSentence.length == [fileContent length]) {
    currentSentence.location = NSNotFound;
} else {
    NSRange nextSentence = NSMakeRange(currentSentence.location + currentSentence.length + 1, 1);
    currentSentence = [tagger sentenceRangeForRange:nextSentence];
}

如果已經(jīng)到了文本的末尾,我們將使用 NSNotFound 來對 while 循環(huán)發(fā)出終止信號。如果我們使用一個超出文本之外的范圍,NSLinguisticTagger 將拋出一個異常并且直接崩潰。

句子處理循環(huán)中的主要方法調(diào)用如下:

while (currentSentence.location != NSNotFound) {
    __block NSUInteger tokenPosition = 0;
    [tagger enumerateTagsInRange:currentSentence
                          scheme:NSLinguisticTagSchemeNameTypeOrLexicalClass
                         options:options
                      usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) 
    {
        NSString *token = [fileContent substringWithRange:tokenRange];
        NSString *lemma = [tagger tagAtIndex:tokenRange.location 
                                      scheme:NSLinguisticTagSchemeLemma 
                                  tokenRange: NULL 
                               sentenceRange:NULL];
        if (lemma == nil) {
            lemma = token;
        }
        [self.delegate receiveWord:@{
            @"token": token, 
            @"postag": tag, 
            @"lemma": lemma, 
            @"position": @(tokenPosition), 
            @"sentence": @(sentenceCounter), 
            @"filename": filename
        }];
        tokenPosition++;
    }];
}

我們讓 tagger 處理 NSLinguisticTagSchemeNameTypeOrLexicalClass,指定一組選項(連接名字,省略標點和空格)。然后我們獲取這個標簽,以及搜索到的每一項條目的范圍,并進一步檢索信息。標識(token)是字符串一部分,僅僅由字符范圍來描述。lemma 是基本形式,如果不可能用的這個值會是 nil,所以我們需要做檢查,并使用標識字符串作為候補值。一旦收集到這個信息,我們就可以將其打包到一個字典中,然后發(fā)送給 delegate 進行處理。

在我們的示例應(yīng)用中,我們僅僅輸出了我們接收到的單詞,但是我們在這里基本上可以做任何我們想做的一切。為了實現(xiàn)搜索,我們可以過濾掉除了名詞,動詞,形容詞,副詞和名字以外的所有詞,并且在索引數(shù)據(jù)庫中儲存這些單詞的位置。使用原形,而不使用標識值,可以使我們合并各種詞的變形 (pigpigs),這可以保持索引不過于龐大,并且與僅只匹配實際標識詞相比,也可以檢索出更相關(guān)的詞。請記住,你可能還要將所有查詢按照原形變化進行歸類,否則,搜索 pigs 的話將不會返回任何結(jié)果。

為了更加真實,我在樣本文本頭部信息中加進了一些基本 HTML 標簽,比如確定標題,署名,日期。在通過 tagger 運行的時候出現(xiàn)一個問題,即 NSLinguisticTagger 是不知道關(guān)于 HTML 的東西的,并試圖將這些 HTML 標記當(dāng)做文本來處理。下面是最前面的三個檢索詞。

{
    filename = "/Users/oliver/tmp/guardian-article.txt";
    lemma = "<";
    position = 0;
    postag = Particle;
    sentence = 0;
    token = "<";
}
{
    filename = "/Users/oliver/tmp/guardian-article.txt";
    lemma = h1;
    position = 1;
    postag = Verb;
    sentence = 0;
    token = h1;
}
{
    filename = "/Users/oliver/tmp/guardian-article.txt";
    lemma = ">";
    position = 2;
    postag = Adjective;
    sentence = 0;
    token = ">";
}

不僅僅是標簽被分成了幾個部分,被當(dāng)做詞來處理,而且還得到了奇怪和完全錯誤的標簽。所以,如果你在處理包含標記的文件,最好先將其過濾出來?;蛟S,你想要識別出標簽,并返回覆蓋標簽區(qū)域的 NSRange,而不是像我們之前處理示例應(yīng)用一樣將整個文本分成一個個句子。或者說,如果存在內(nèi)嵌標簽(比如加粗,斜體,超鏈接),將標簽全部剔除出來會更好些。

結(jié)果

就算是用 tagger 來處理通用語言,其表現(xiàn)也出人意料的優(yōu)秀。如果你僅僅處理某一個領(lǐng)域(比如技術(shù)文本)的話,你可以做出一些在處理不受限制的文本時無法做到的假設(shè)。但是蘋果的 tagger 必須在無法預(yù)知會遇到什么的情況下也能工作,鑒于如此,它偶爾也會出錯,不過相對來說是非常少的。很顯然,很多名稱無法識別,比如說 Chengdu 這樣的地名。但另一方面,文本中大多數(shù)人名的處理都是非常不錯的。由于某些原因,日期(Wednesday 4 December 2013 10.35 GMT)被當(dāng)做了人名來處理,可能是來源于魯賓遜?克魯索的命名習(xí)慣吧。環(huán)境大臣 Owen Patterson 可以被識別出來,但是,一般被認為更加重要的首相 David Cameron 卻沒有被識別出來,盡管 David 是個更為常見的名字。

這是概率 tagger 的問題:有時候很難理解為什么某些詞以特定的方式被加上標簽。也沒有什么像鉤子一樣的東西可以掛靠 tagger,可以讓你提供比如說已知的地點,人物或者組織的名稱列表。你只能用默認設(shè)置進行處理。因此,最好使用大量數(shù)據(jù)來測試那些帶有 tagger 的應(yīng)用程序,通過觀察結(jié)果,你可以大概知道哪些可以正常運行,哪些會遇到問題。

概率

有很多種方法來實現(xiàn)詞性標簽:兩個主要的途徑,一個是規(guī)則性的,一個是隨機性。兩種途徑都有一套相當(dāng)龐大的規(guī)則來告訴你,形容詞的后面是名詞,而不是冠詞,或者有一個概率矩陣告訴你某一個特定的標簽會出現(xiàn)在一個特定的語言環(huán)境中的可能性有多大。你也可以使用基于概率性的模型,同時添加一些規(guī)則來修正反復(fù)出現(xiàn)的典型錯誤,這就是所謂的混合 tagger。由于為不同語言開發(fā)規(guī)則集比自動學(xué)習(xí)隨機語言模型的成本要高得多,所以我猜測 NSLinguisticTagger 應(yīng)該是基于完全的隨機模型。這個實現(xiàn)細節(jié)也可以從下面的方法中窺探一二:

- (NSArray *)possibleTagsAtIndex:(NSUInteger)charIndex 
                          scheme:(NSString *)tagScheme 
                      tokenRange:(NSRangePointer)tokenRange 
                   sentenceRange:(NSRangePointer)sentenceRange 
                          scores:(NSArray **)scores

這說明了一個事實,那就是有時候(其實是大多數(shù)時候)會出現(xiàn)多個可能的標簽值,tagger 必須判斷哪個可能是錯誤的。使用這個方法,你可以獲得一份選項列表和概率得分。得分最高的詞則被 tagger 選中,但是如果你想要創(chuàng)建一套基于規(guī)則的后處理來改善 tagger 工作,你依然可以訪問得分第二的詞或者其他候選項。

對于這個方法要提高警惕,其中有個 bug,實際上它并沒有返回任何的分數(shù)。不過在 OS X 10.9 / Mavericks 中這個 bug 已被修復(fù)。所以,如果你需要支持 OS X 10.9 / Mavericks 之前的版本,會提示你無法使用這個方法。順帶一提,在 iOS 7 中這個方法可以良好運行。

下面是幾個 When is the next train…: 的輸出案例:

When is the next train
Pronoun, 0.9995162 Verb, 1 Determiner, 0.9999986 Adjective, 0.9292629 Noun, 0.8741992
Conjunction, 0.0004337671 Adverb, 1.344403e-06 Adverb, 0.0636334 Verb, 0.1258008
Adverb, 4.170838e-05 Preposition, 0.007003677
Noun, 8.341675e-06 Noun, 0.0001000525

正如你所見,在這個例子中到現(xiàn)在為止,正確的 tag 擁有最高的概率。對于大多數(shù)應(yīng)用程序而言,你可以保持程序簡單,并認可 tagger 所提供的標簽,而不對概率進行深究。不過你得承認 tagger 偶然也是會出錯的,而你也可以訪問到這些識別結(jié)果,并做出相應(yīng)處理。 當(dāng)然,如果你不親自檢查的話,你就不會知道 tagger 什么時候會出錯。然而,其中一個線索是概率差:如果概率非常接近(和上面的例子不同),說不定就表示可能出錯了。

結(jié)論

處理自然語言是很困難的,蘋果給我們提供了一個非常好的工具,這個工具可以簡便地支持絕大多數(shù)使用情況。當(dāng)然,它也不是完美無缺的,即使最先進的語言處理工具也不是完美無缺的。iOS 目前只支持英語,不過隨著技術(shù)改善,以及如果有足夠大的內(nèi)存來儲存(毫無疑問會很大的)語言模型的話,這將有所改變。在此之前,我們會受到一些限制。不過還是有很多方法可以給應(yīng)用程序添加語言支持。在文本編輯器中突出動詞,理解用戶鍵入的內(nèi)容,或者處理外部數(shù)據(jù)文件等工作還是很簡單的,NSLinguisticTagger 可以幫助你做到這一點。

上一篇:截圖測試