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

261 天前
 ShikiSuen

先来个例子:

import Foundation

func tokenize(sentence: String) -> [String] {
  var tokens:[String] = [String]()
  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: [String] = ["有個大夫叫白朮,他有個徒弟叫七七。"]
for text in texts {
  let tokens = tokenize(sentence: text)
  print("\(text) --> \(tokens)")
}

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

1647 次点击
所在节点    iDev
17 条回复
blackcat888
261 天前
不玩原神即可
chenY520
261 天前
自定义词典吧
ShikiSuen
261 天前
@blackcat888 跟原神无关的例句也可以拿来测试:
「金庸有一篇小說,張三丰是其中的一個角色。」
该怎样让这个断句器认为“张三丰”是一个完整的词?
ShikiSuen
261 天前
@chenY520 对,我想问这里该怎么自定义。
chenY520
261 天前
@ShikiSuen #4

import Foundation

// 创建自定义词典,将需要保留的词汇映射到一个数组,以便后续检查
let customDictionary: [String: [String]] = [
"白术": ["白术"],
"大夫": ["大夫"],
"七七": ["七七"]
]

func tokenize(sentence: String) -> [String] {
var tokens: [String] = []
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[word] {
tokens.append(contentsOf: specialCases)
} else {
tokens.append(word)
}
}
return tokens
}

let texts: [String] = ["有個大夫叫白朮,他有個徒弟叫七七。"]
for text in texts {
let tokens = tokenize(sentence: text)
print("\(text) --> \(tokens)")
}
chenY520
261 天前
@ShikiSuen #4 chatgpt 可以试试
zjuster
261 天前
之前做过知识图谱,用的 NLP 相关技术和模型。其中的专有词都是走 NER 的(命名实体识别)。NLP 的技术模型另说,NER 就要调教很多模型了。

楼主的这个命题都是人工打标的。分两种
1. 模型建设
先用第三方的中英文语料库调教启动语料库,然后迭代模型,设置在不同的 context 下,某些特定的字符组合将被识别为 entity 模型的概率组合,然后给到人工评估模型结果,打分来调教。这个算是日常模型调教,有更新就需要做定量对比模型版本的。
如果语料库的质量比较高,能够减少很多术语的问题。
前公司是搜索出身的,本身就积累了大量的 user query 库,所以这方便少了很多麻烦。

2. 强制识别
这没啥好说的,直接人工干预模型结果,一般是纠错 case ,需要一个一个积累。比较麻烦的是以后 context 模型调整,或者划分,需要人工重新做一遍。

不清楚楼主的目的和背景,我建议先找一下中文语料库,别的不说,新华词典啊就能解决你的“白术”问题。
抛开原神,这也是一款中药材。龙葵之类的,都应该是能识别出来的。
难点应该是如何识别是游戏角色白术,还是中药材白术。
ShikiSuen
261 天前
@chenY520 您不妨把「白术」全改成「白朮」再試試看?
我這邊測試結果:
["有", "個", "大夫", "叫", "白", "朮", "他", "有", "個", "徒弟", "叫", "七七"]
白朮還是被切了。
ShikiSuen
261 天前
感觉五楼 @chenY520 的方法作用有限:唯一用到自订辞典的场合居然在 enumerateTags 的 loop 内部。此时的 word 断然不可能是「白朮」,只可能是「白」与「朮」。

得想办法在 enumerateTags 执行之前就将自订辞典给介入到里面去。
yuhu96
260 天前
jieba 自定义词库。不知道你 swift 里有没有这一套,你上网抓取领域相关的词汇(随便哪里,比如百度百科)做好词库,加载这个词库,分词的时候就不容易错分。
oxoxoxox
260 天前
ChatGPT 3.5 的答案:

有個大夫叫白朮,他有個徒弟叫七七。

拆分为单词:
有 / 個 / 大夫 / 叫 / 白朮 / , / 他 / 有 / 個 / 徒弟 / 叫 / 七七。
kingbill
260 天前
你得有个牛逼的词库
S1deny
260 天前
感觉得需要大量的语义词库进行训练才行啊 自定义的词库以哈工大词典和百度情感词典为例 好像那个腾讯的词向量模型涉及到了很多的词库
ShikiSuen
260 天前
@yuhu96 @oxoxoxox @kingbill @S1deny
先感谢各位的意见。

然后呢,问题的真正症结已经在 #9 讲清楚了。
第三方服务不是不能用,但我将这个讨论串放在 iDev 版、自然是要问与 macOS 内建模组有关的问题。
不然我直接投递在别的版面就好。
iugo
250 天前
如果 NSLinguisticTagger 内置会更好, 即便没有, 也是有一些笨方法解决的.

```swift
let customDictionary = ["白朮": 1]

func tokenize(sentence: String) -> [String] {
var tokens:[String] = [String]()
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
}
```
iugo
250 天前
因为是笨办法, 所以这里面有两个问题:

1. 如果多个组合怎么处理? 比如这个大夫姓 "叫" , 全名 "叫白朮". 因为代码只能将两个词进行匹配, 那么则匹配不上. 如果不是完全匹配而是匹配字符串前面的部分, 则可能出现误匹配. 所以当前的两个字完全匹配是一个简单做法.
2. 换用 Set. 不过这个 Set 做不了替换, 比如今后想将 白朮 替换为 白术 用字典就简单, 用集合就做不到.

总之, 这种分词办法比较笨, 因为并没有了解真实的语义. 最好还是服务端做, 用 python 这种库.
BB9z
202 天前
训练自定义模型打标签,再结合标签结果分词?
https://developer.apple.com/documentation/naturallanguage/creating_a_word_tagger_model

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/968016

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX