“Natural Language Processing with Swift”という素晴らしいトークを拝見しました.トークの中では,ナイーブベイズ分類器を用いた簡易のスパムフィルタの実装が説明されています.
その中でNSLinguisticTagger
という便利なクラスを知り,気になったので触ってみました.(環境は Xcode 7.3.1, Swift 2.2 です.)
初期化する
NSLinguisticTagger
の初期にはtagSchemes
とoptions
を渡します.
型はそれぞれ[String]
とInt
です.
NSLinguisticTagger
はなかなか多機能なやつで,tagSchemes
には用途に応じたパラメータを渡すことになります.これは後ほど調べるとして,今はとにかくテキトーに初期化してみます.
let tagger = NSLinguisticTagger(tagSchemes: [NSLinguisticTagSchemeLexicalClass], options: 0)
tagSchemes
は LexicalClass,options
は特に指定せずにインスタンスを取得出来ました.
試す
先ほど初期化したNSLinguisticTagger
の簡単な使用例を見ていきます.
let sentence = "I'm Spider-man."
let range = NSRange(location: 0, length: sentence.characters.count)
tagger.string = sentence
tagger.enumerateTagsInRange(
range,
scheme: NSLinguisticTagSchemeLexicalClass,
options: .OmitWhitespace) { tag, tokenRange, _, _ in
let start = sentence.startIndex.advancedBy(tokenRange.location)
let end = sentence.startIndex.advancedBy(tokenRange.location + tokenRange.length)
let token = sentence.substringWithRange(start ..< end)
print("\(token) (\(tag))")
}
出力結果は以下の通り.()
の中身がtagger
によって付加された tag です.
I (Pronoun)
'm (Verb)
Spider (Noun)
- (Dash)
man (Noun)
. (SentenceTerminator)
このように文章の品詞分解が出来ました.
Tagging Schemes
Scheme の指定を変更することで様々な結果を得ることが出来ます.(上記の例では LexicalClass を指定しました.)
英語のテキストに対して指定可能な Scheme の一覧は以下のように取得出来ます.
let availableSchemes = NSLinguisticTagger.availableTagSchemesForLanguage("en")
// => ["TokenType", "Language", "Script", "Lemma", "LexicalClass", "NameType", "NameTypeOrLexicalClass"]
試しに別な Scheme を指定して,先ほどのコードを実行してみます.(結果のみ)
TokenType
I (Word)
'm (Word)
Spider (Word)
- (Punctuation)
man (Word)
. (Punctuation)
NameType
I (OtherWord)
'm (OtherWord)
Spider (OtherWord)
- (Dash)
man (OtherWord)
. (SentenceTerminator)
Language
I (en)
'm (en)
Spider (en)
- ()
man (en)
. ()
と,このように異なる tagging がされていることが分かります.
Tag Schemes の一覧は公式ドキュメントを確認して下さい.
Options
上記の例では OmitWhitespace を指定していたので空白の除去が行われていました.
Options の一覧は公式ドキュメントを確認して下さい.
句読点の除去を行う OmitPunctuation や”New York”などを一単語として扱う JoinNames などがあります.
複数の option を指定したい場合は or 演算|
を行います.
let optionsRawValue: UInt =
NSLinguisticTaggerOptions.OmitWhitespace.rawValue | NSLinguisticTaggerOptions.JoinNames.rawValue
let optionsInt = Int(optionsRawValue)
let options = NSLinguisticTaggerOptions(rawValue: optionsRawValue)
遊ぶ
では最後にサンプルコードを掲載します.Playground でそのまま実行出来るはずです.
import Foundation
extension NSRange {
func rangeForString(string: String) -> Range<String.Index>? {
guard location != NSNotFound else { return nil }
let start = string.startIndex.advancedBy(location)
let end = string.startIndex.advancedBy(location + length)
return start ..< end
}
}
let sentence1 = "With great power comes great responsibility."
let sentence2 = "In critical moments, men sometimes see exactly what they wish to see."
let sentence3 = "He can make the choice that no one else can make, the right choice."
let availableSchemes = NSLinguisticTagger.availableTagSchemesForLanguage("en")
let optionsRawValue: UInt =
NSLinguisticTaggerOptions.OmitWhitespace.rawValue | NSLinguisticTaggerOptions.JoinNames.rawValue
let tagger = NSLinguisticTagger(tagSchemes: availableSchemes, options: Int(optionsRawValue))
for sentence in [sentence1, sentence2, sentence3] {
tagger.string = sentence
let range = NSRange(location: 0, length: sentence.characters.count)
tagger.enumerateTagsInRange(
range,
scheme: NSLinguisticTagSchemeNameTypeOrLexicalClass,
options: NSLinguisticTaggerOptions(rawValue: optionsRawValue)) {
tag, tokenRange, sentenceRange, stop in
let token = sentence.substringWithRange(tokenRange.rangeForString(sentence)!)
print("\(tag): \(token)")
}
print("\n")
}