admin 发表于 2023-11-29 14:48:59

中文分词时该怎样定义被误拆的专有词?

先来个例子:
import Foundation

func tokenize(sentence: String) -> {
var tokens: = ()
let tagger = NSLinguisticTagger(tagSchemes: [.tokenType], options: 0)
tagger.string = sentence
let range = NSMakeRange(0, sentence.utf16.count)
let options: NSLinguisticTagger.Options = [.omitWhitespace, .omitPunctuation]
tagger.enumerateTags(in: range, unit: .word, scheme: .tokenType, options: options) { (tag, tokenRange, stop) in
    let word = (sentence as NSString).substring(with: tokenRange)
    tokens.append(word)
}
return tokens
}

let texts: = ["有個大夫叫白朮,他有個徒弟叫七七。"]
for text in texts {
let tokens = tokenize(sentence: text)
print("\(text) --> \(tokens)")
}

直接运行该 swift 脚本,可以发现「白朮」(「白术」的繁体中文写法)被拆开了。
该怎样定义这个词、使其不被误拆呢?

不玩原神即可
自定义词典吧
@blackcat888 跟原神无关的例句也可以拿来测试:「金庸有一篇小說,張三丰是其中的一個角色。」该怎样让这个断句器认为“张三丰”是一个完整的词?
@chenY520 对,我想问这里该怎么自定义。
@ShikiSuen #4 import Foundation// 创建自定义词典,将需要保留的词汇映射到一个数组,以便后续检查let customDictionary: ] = [ "白术": ["白术"], "大夫": ["大夫"], "七七": ["七七"]]func tokenize(sentence: String) -> { var tokens: = [] let tagger = NSLinguisticTagger(tagSchemes: [.tokenType], options: 0) tagger.string = sentence let range = NSMakeRange(0, sentence.utf16.count) let options: NSLinguisticTagger.Options = [.omitWhitespace, .omitPunctuation]tagger.enumerateTags(in: range, unit: .word, scheme: .tokenType, options: options) { (tag, tokenRange, stop) in let word = (sentence as NSString).substring(with: tokenRange) if let specialCases = customDictionary { tokens.append(contentsOf: specialCases) } else { tokens.append(word) } } return tokens}let texts: = ["有個大夫叫白朮,他有個徒弟叫七七。"]for text in texts { let tokens = tokenize(sentence: text) print("\(text) --> \(tokens)")}
@ShikiSuen #4 chatgpt 可以试试
之前做过知识图谱,用的 NLP 相关技术和模型。其中的专有词都是走 NER 的(命名实体识别)。NLP 的技术模型另说,NER 就要调教很多模型了。楼主的这个命题都是人工打标的。分两种1. 模型建设先用第三方的中英文语料库调教启动语料库,然后迭代模型,设置在不同的 context 下,某些特定的字符组合将被识别为 entity 模型的概率组合,然后给到人工评估模型结果,打分来调教。这个算是日常模型调教,有更新就需要做定量对比模型版本的。如果语料库的质量比较高,能够减少很多术语的问题。前公司是搜索出身的,本身就积累了大量的 user query 库,所以这方便少了很多麻烦。2. 强制识别这没啥好说的,直接人工干预模型结果,一般是纠错 case ,需要一个一个积累。比较麻烦的是以后 context 模型调整,或者划分,需要人工重新做一遍。不清楚楼主的目的和背景,我建议先找一下中文语料库,别的不说,新华词典啊就能解决你的“白术”问题。抛开原神,这也是一款中药材。龙葵之类的,都应该是能识别出来的。难点应该是如何识别是游戏角色白术,还是中药材白术。
@chenY520 您不妨把「白术」全改成「白朮」再試試看?我這邊測試結果:["有", "個", "大夫", "叫", "白", "朮", "他", "有", "個", "徒弟", "叫", "七七"]白朮還是被切了。
感觉五楼 @chenY520 的方法作用有限:唯一用到自订辞典的场合居然在 enumerateTags 的 loop 内部。此时的 word 断然不可能是「白朮」,只可能是「白」与「朮」。得想办法在 enumerateTags 执行之前就将自订辞典给介入到里面去。
jieba 自定义词库。不知道你 swift 里有没有这一套,你上网抓取领域相关的词汇(随便哪里,比如百度百科)做好词库,加载这个词库,分词的时候就不容易错分。
ChatGPT 3.5 的答案:有個大夫叫白朮,他有個徒弟叫七七。拆分为单词:有 / 個 / 大夫 / 叫 / 白朮 / , / 他 / 有 / 個 / 徒弟 / 叫 / 七七。
你得有个牛逼的词库
感觉得需要大量的语义词库进行训练才行啊 自定义的词库以哈工大词典和百度情感词典为例 好像那个腾讯的词向量模型涉及到了很多的词库
@yuhu96 @oxoxoxox @kingbill @S1deny 先感谢各位的意见。然后呢,问题的真正症结已经在 #9 讲清楚了。第三方服务不是不能用,但我将这个讨论串放在 iDev 版、自然是要问与 macOS 内建模组有关的问题。不然我直接投递在别的版面就好。
如果 NSLinguisticTagger 内置会更好, 即便没有, 也是有一些笨方法解决的.```swiftlet customDictionary = ["白朮": 1]func tokenize(sentence: String) -> { var tokens: = () let tagger = NSLinguisticTagger(tagSchemes: [.tokenType], options: 0) tagger.string = sentence let range = NSMakeRange(0, sentence.utf16.count) let options: NSLinguisticTagger.Options = [.omitWhitespace, .omitPunctuation] tagger.enumerateTags(in: range, unit: .word, scheme: .tokenType, options: options) { (tag, tokenRange, stop) in let word = (sentence as NSString).substring(with: tokenRange) // 找到上一个单词, 如果本单词加上一个单词和词库匹配, 则修改之前的词 let oldnew = (tokens.last ?? "") + word if customDictionary.keys.contains(oldnew) { tokens.removeLast() tokens.append(oldnew) } else { tokens.append(word) } } return tokens}```
因为是笨办法, 所以这里面有两个问题:1. 如果多个组合怎么处理? 比如这个大夫姓 "叫" , 全名 "叫白朮". 因为代码只能将两个词进行匹配, 那么则匹配不上. 如果不是完全匹配而是匹配字符串前面的部分, 则可能出现误匹配. 所以当前的两个字完全匹配是一个简单做法.2. 换用 Set. 不过这个 Set 做不了替换, 比如今后想将 白朮 替换为 白术 用字典就简单, 用集合就做不到.总之, 这种分词办法比较笨, 因为并没有了解真实的语义. 最好还是服务端做, 用 python 这种库.
训练自定义模型打标签,再结合标签结果分词? https://developer.apple.com/documentation/naturallanguage/creating_a_word_tagger_model
页: [1]
查看完整版本: 中文分词时该怎样定义被误拆的专有词?