NLP(四十七)文本糾錯之獲取形近字
簡介
??筆者最近在從事文本糾錯的相關(guān)工作,頗有收獲,因此記錄于此。
??文本糾錯很大一部分工作在于糾正同音字、形近字,所謂形近字,是指字形相近的漢字。本文將介紹如何獲取形近字。
??獲取形近字的算法如下:
獲取漢字庫,將所有漢字轉(zhuǎn)化為黑白圖片;
獲取每個漢字的向量表示(即將圖片轉(zhuǎn)化為向量);
計(jì)算兩個漢字的向量的余弦相似度,得到它們的字形相似度。
??下面將詳細(xì)演示如何獲取形近字。
獲取形近字
??我們從網(wǎng)上得到3500個漢字的txt文件(all_3500_chars.txt),通過pygame將漢字轉(zhuǎn)化為100*100的黑白圖片,Python程序如下:
# -*- coding: utf-8 -*-
import pygame
pygame.init()
# 獲取3500個漢字
with open("all_3500_chars.txt", "r", encoding="utf-8") as f:
chars = f.read().strip()
# 通過pygame將漢字轉(zhuǎn)化為黑白圖片
for char in chars:
font = pygame.font.Font("C://Windows/Fonts/simkai.ttf", 100)
rtext = font.render(char, True, (0, 0, 0), (255, 255, 255))
pygame.image.save(rtext, "{}.png".format(char))
前10個漢字為一乙二十丁廠七卜人入,其對應(yīng)的黑白圖片如下:

??接著我們獲取每個漢字的向量表示,并將這兩個向量的余弦相似度作為對應(yīng)漢字的余弦相似度,Python程序如下:
# -*- coding: utf-8 -*-
# get_similiar_char.py
import numpy as np
import cv2
import os
from operator import itemgetter
def read_img_2_list(img_path):
# 讀取圖片
img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
# 把圖片轉(zhuǎn)換為灰度模式
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).reshape(-1, 1)
return [_[0] for _ in img.tolist()]
# 獲取所有漢字的向量表示,以dict儲存
def get_all_char_vectors():
image_paths = [_ for _ in os.listdir(".") if _.endswith("png")]
img_vector_dict = {}
for image_path in image_paths:
img_vector_dict[image_path[0]] = read_img_2_list(img_path=image_path)
return img_vector_dict
# 計(jì)算兩個向量之間的余弦相似度
def cosine_similarity(vector1, vector2):
dot_product = 0.0
normA = 0.0
normB = 0.0
for a, b in zip(vector1, vector2):
dot_product += a * b
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return 0
else:
return dot_product / ((normA**0.5)*(normB**0.5))
if __name__ == '__main__':
img_vector_dict = get_all_char_vectors()
# 獲取最接近的漢字
similarity_dict = {}
while True:
match_char = input("輸入漢字: ")
match_vector = img_vector_dict[match_char]
for char, vector in img_vector_dict.items():
cosine_similar = cosine_similarity(match_vector, vector)
similarity_dict[char] = cosine_similar
# 按相似度排序,取前10個
sorted_similarity = sorted(similarity_dict.items(), key=itemgetter(1), reverse=True)
print([(char, round(similarity, 4))for char, similarity in sorted_similarity[:10]])
我們嘗試著輸入國、填、博這三個字,得到的相近字形的漢字如下:
輸入漢字: 國
[('國', 1.0), ('固', 0.9493), ('團(tuán)', 0.9432), ('困', 0.9405), ('因', 0.9369), ('圍', 0.9357), ('門', 0.9334), ('園', 0.9326), ('同', 0.929), ('圓', 0.9261)]
輸入漢字: 填
[('填', 1.0), ('慎', 0.9522), ('塢', 0.9238), ('培', 0.9149), ('坎', 0.9133), ('塊', 0.9101), ('幣', 0.9092), ('鎮(zhèn)', 0.9077), ('埠', 0.9074), ('了', 0.9044)]
輸入漢字: 博
[('博', 1.0), ('傅', 0.9306), ('協(xié)', 0.9115), ('搏', 0.907), ('惰', 0.9046), ('膊', 0.9029), ('愕', 0.9019), ('侯', 0.8999), ('悴', 0.8997), ('憐', 0.8989)]
opencv讀取文件名為漢字的圖片
??在使用opencv讀取文件名為漢字的圖片時,讀取的圖片內(nèi)容為None,我們以一.png為例,演示程序如下:
# -*- coding: utf-8 -*-
import cv2
image_path = "一.png"
img = cv2.imread(image_path, 1)
print(img, type(img))
輸出結(jié)果為None <class 'NoneType'>。也就是說,opencv在讀取帶漢字的文件路徑時會報錯,解決辦法如下:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
image_path = "一.png"
img = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
print(img.shape, type(img))
輸出結(jié)果為(100, 100, 3) <class 'numpy.ndarray'>。
總結(jié)
??本文通過將漢字轉(zhuǎn)化為圖片,獲取圖片的向量表示來表征漢字,在獲取形近字方面有著不錯的效果。
??我們可以通過更復(fù)雜的圖片相似度算法來增強(qiáng)獲得更好的形近字能力。
??也有不少研究者,通過四角碼、音形碼等算法來獲取形近字,取得了不錯的效果。本文想法樸素,容易用程序?qū)崿F(xiàn),且效果也較為不錯。
??后面將繼續(xù)記錄筆者在文本糾錯方面的嘗試,歡迎大家繼續(xù)閱讀~
??2021年6月29日于上海浦東,此日上海暑氣逼人~
