Natulal Languageを利用して、自然言語テキスト処理に入門したかった
TL;DR
以下の情報はXcode 15.3時点での情報です。
- iOSで自然言語テキスト処理を行う場合、Appleが提供するNatural Language Frameworkを利用できます。
- 現状のNatural Languageで提供されるNLTaggerでは、下記3種類しかSchemeを利用できません
- "Language"
- "Script"
- "TokenType"
Natural Language Frameworkとは
Natural Language Frameworkとは、Appleが提供している自然言語テキストを解析するためのフレームワークです。
このFrameworkではおもに下記3つのclassをよく利用します。
- NLLanguageRecognizer
- NLTokenizer
- NLTagger
NLLanguageRecognizer
このクラスのインスタンスは与えられたテキストの言語を推定し、プログラムに返却することができます。
処理させたい言語を流し込む
NLLanguageRecognizerのインスタンスを生成し、処理させたい言語を流し込みましょう。
let recognizer = NLLanguageRecognizer()
recognizer.processString("This is a test, mein Freund.")
主要言語を取り出す
下記コードで、主要言語を取り出すことができます。
// Identify the dominant language.
if let language = recognizer.dominantLanguage {
print(language.rawValue)
} else {
print("Language not recognized")
}
可能性のある言語を取り出す。
下記コードで可能性のある言語を取り出すこともできます。
// Generate up to two language hypotheses.
let hypotheses = recognizer.languageHypotheses(withMaximum: 2)
print(hypotheses)
この場合、下記のように類似度も返却してくれます。
[__C.NLLanguage(_rawValue: de): 0.43922990560531616, __C.NLLanguage(_rawValue: en): 0.5024932026863098]
推測される言語をあらかじめ設定しておく
recognizerに入力するテキストがあらかじめどの言語かわかっている場合は下記のように言語を指定したり割合を指定できたりします。
// Specify constraints for language identification.
recognizer.languageConstraints = [.french, .english, .german,
.italian, .spanish, .portuguese]
recognizer.languageHints = [.french: 0.5,
.english: 0.9,
.german: 0.8,
.italian: 0.6,
.spanish: 0.3,
.portuguese:0.2]
別の言語を処理させる
すでに処理させたテキストではない別のテキストを処理させる場合は、下記のようにしてリセットします。
recognizer.reset()
// Process additional strings for language identification.
recognizer.processString("Este es un idioma diferente.")
NLTokenizer
NLTokenizerは、入力したテキストをトークン化するクラスです。
let text = """
All human beings are born free and equal in dignity and rights.
They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.
"""
let tokenizer = NLTokenizer(unit: .word)
tokenizer.string = text
tokenizer.setLanguage(.english)
tokenizer.enumerateTokens(in: text.startIndex..<text.endIndex) { tokenRange, _ in
print(text[tokenRange])
return true
}
上記のように処理を行うことで、入力した自然文のテキストをトークンごとに分割することが可能です。
どの粒度でトークン化するのかは、初期化時のunitを変更することで可能です。
指定できるのは下記パターンになります。
- word
- sentence
- paragraph
- document
NLTagger
自然言語分析に置いて一番使うクラスです。
下記のように利用することで、単語を適切に分解し種類を得ることができます。
let text = "This is a test text. hello world!"
let tagger = NLTagger(tagSchemes: [.lexicalClass])
tagger.string = text
let options: NLTagger.Options = [.omitWhitespace, .omitPunctuation]
tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .lexicalClass, options: options) { tag, tokenRange in
if let tag = tag {
print("\(text[tokenRange]): \(tag.rawValue)")
}
return true
}
コンソールへの出力は下記のようになります。
This: Determiner
is: Verb
a: Determiner
test: Noun
text.: Noun
hello: Interjection
world: Noun
NLTaggerで有効なスキームは言語ごとに違います。
どのスキームをサポートしているかは下記処理で判定可能です。
let jpSchemes = NLTagger.availableTagSchemes(for: .word, language: .japanese)
print(jpSchemes.map ({ $0.rawValue }))
日本語の場合、下記になり、lexicalは使えないことになってしまいます。
"["Language", "Script", "TokenType"]\n", "TokenType"
自然言語テキストをプログラムで扱う場合、おそらくlexicalclassを利用したいと思うのですが、現状日本語では動詞や形容詞といった単語の種類を分析することはできないようです。
終わりに
大学時代に形態素解析にちょっと興味があり調べた程度の知識しか持っていないのですが、Natural language Frameworkを用いることで、Swiftではとても簡単に自然テキスト処理を行えることがわかりました。
残念なことに日本語ではうまい使い方ができないので、今後の機能拡張に期待したいと思います。
Discussion