iOS MachineLearning 系列(12)—— 自然語言之詞句相似性分析
本篇文章將介紹如何使用NaturalLanguage框架來對詞句的相似性進行分析。文本相似性的分析在實際開發中應用很多,比如我們可以通過查找與用戶輸入相似的詞來進行內容推薦。
分析語句的相似性需要進行大量的訓練,NaturalLanguage已經內置了許多語言的訓練模型,使用非常方便。
1 - 文本相似性分析的示例
需要創建NLEmbedding實例來進行詞句的相似性分析。例如:
let embedding = NLEmbedding.wordEmbedding(for: .english)!
let embedding2 = NLEmbedding.sentenceEmbedding(for: .english)!
其中,使用wordEmbedding創建出的實例用來進行單詞分析,sentenceEmbedding創建出的實例用來進行句子分析。其參數設置所分析的語言,需要注意,並非所有語言都支持進行相似性分析。
下面示例代碼演示瞭如何對單詞,句子的相似性進行分析,並能夠自動根據傳入的單詞來進行相近的詞的推薦:
let label = UILabel(frame: CGRect(x: 0, y: 100, width: view.frame.width, height: 500))
label.numberOfLines = 0
label.text = ""
view.addSubview(label)
let word = "dog"
let word2 = "cat"
let word3 = "teacher"
// 計算單詞間的矢量距離
let distance = embedding.distance(between: word, and: word2)
let distance2 = embedding.distance(between: word, and: word3)
label.text = label.text!.appending("單詞1:\(word)\n單詞2:\(word2)\n單詞3:\(word3)")
label.text = label.text!.appending("\n\n單詞1與單詞2間的距離:\(distance)\n單詞1與單詞3間的距離:\(distance2)")
// 獲取相似的詞
embedding.enumerateNeighbors(for: word3, maximumCount: 5, using: { item, distance in
label.text = label.text!.appending("\n與單詞3相近的詞:\(item) - \(distance)")
return true
})
let sen = "Hello, Xiao."
let sen2 = "Hi, Xiao."
let sen3 = "My name is Xiao."
// 計算句子間的矢量距離
let distance3 = embedding2.distance(between: sen, and: sen2)
let distance4 = embedding2.distance(between: sen, and: sen3)
label.text = label.text!.appending("\n\n\n句子1:\(sen)\n句子2:\(sen2)\n句子3:\(sen3)")
label.text = label.text!.appending("\n\n句子1與句子2間的距離:\(distance3)\n句子1與句子3間的距離:\(distance4)")
計算出的矢量距離越大,標明詞句間的差異越大,即相似性越差。效果如下圖所示:
通常矢量距離小於1的詞句相似性較高。取值範圍爲0-2之間。
2 - 關於NLEmbedding類
要進行詞句的相似性分析,需要NLEmbedding類來完成:
open class NLEmbedding : NSObject {
// 創建分析單詞的實例
open class func wordEmbedding(for language: NLLanguage) -> NLEmbedding?
open class func wordEmbedding(for language: NLLanguage, revision: Int) -> NLEmbedding?
// 創建分析句子的實例
open class func sentenceEmbedding(for language: NLLanguage) -> NLEmbedding?
open class func sentenceEmbedding(for language: NLLanguage, revision: Int) -> NLEmbedding?
// 判斷詞彙表是否包含參數字符串
open func contains(_ string: String) -> Bool
// 向量空間維數
open var dimension: Int { get }
// 詞彙表單詞數量
open var vocabularySize: Int { get }
// 所使用的語言
open var language: NLLanguage? { get }
// 所使用的算法版本
open var revision: Int { get }
// 獲取所支持的算法版本
open class func supportedRevisions(for language: NLLanguage) -> IndexSet
open class func supportedSentenceEmbeddingRevisions(for language: NLLanguage) -> IndexSet
// 當前默認的算法版本
open class func currentRevision(for language: NLLanguage) -> Int
open class func currentSentenceEmbeddingRevision(for language: NLLanguage) -> Int
// 計算兩個字符串之間的向量距離
public func distance(between firstString: String, and secondString: String, distanceType: NLDistanceType = .cosine) -> NLDistance
// 計算參數字符串的空間向量數據
public func vector(for string: String) -> [Double]?
// 獲取相似的詞句,maxCount控制最大返回個數
public func enumerateNeighbors(for string: String, maximumCount maxCount: Int, distanceType: NLDistanceType = .cosine, using block: (String, NLDistance) -> Bool)
public func neighbors(for string: String, maximumCount maxCount: Int, distanceType: NLDistanceType = .cosine) -> [(String, NLDistance)]
// 通過空間向量數據來獲取相似的詞句
public func enumerateNeighbors(for vector: [Double], maximumCount maxCount: Int, distanceType: NLDistanceType = .cosine, using block: (String, NLDistance) -> Bool)
public func neighbors(for vector: [Double], maximumCount maxCount: Int, distanceType: NLDistanceType = .cosine) -> [(String, NLDistance)]
}
其中NLDistance是Double類型的一個別名。直接使用這些API實際上並不能很好的支持中文,NaturalLanguage也支持我們使用自定義的模型,關於模型的使用和訓練,我們後面文章會再介紹。
完整的示例代碼可以在如下地址找到: