Как реализовать сегментацию слов на основе дерева Trie и словаря

машинное обучение искусственный интеллект глубокое обучение Java
Как реализовать сегментацию слов на основе дерева Trie и словаря

предисловие

В настоящее время более популярно использовать глубокое обучение для сегментации слов, например, с использованием рекуррентных нейронных сетей и условных случайных полей, а также прямое использование условных случайных полей или скрытых марковских моделей. Вышеупомянутое также было реализовано ранее, и эффект довольно хороший.На основе скрытой марковской модели эффект условного случайного поля лучше, а эффект добавления глубокого обучения лучший.

Многие из наиболее традиционных методов сегментации слов основаны на словаре, а затем сопоставляются методом максимального соответствия, и эффект является относительно общим. Хотя эффект общий, давайте посмотрим, как его достичь.

Древовидная структура Trie

Trie — это дерево поиска, все ключи которого являются строками, а значение можно найти по ключу. Он может обеспечить эффективный запрос и вставку, временная сложность O (k), а недостатком является то, что он потребляет память. Его основная идея состоит в том, чтобы уменьшить количество ненужных сравнений символов и сделать запрос эффективным, то есть использовать пространство вместо времени, а затем использовать общий префикс для повышения эффективности запроса.

Корневой узел дерева Trie не содержит символов. Строка, связанная путем от корневого узла к узлу, является строкой, соответствующей узлу. Каждый узел содержит только один символ. Кроме того, символы всех дочерних узлов дерева любой узел отличается.

Например, в дерево Trie добавляются пять слов, и конечная структура показана на рисунке.

TrieTree tree = new TrieTree();
tree.put("美利坚");
tree.put("美丽");
tree.put("金币");
tree.put("金子");
tree.put("帝王");

这里写图片描述

Github

https://github.com/sea-boat/TextAnalyzer/blob/master/src/main/java/com/seaboat/text/analyzer/segment/

Эффект

Видно, что эффект сегментации слов на основе словаря имеет недостатки и нуждается в дальнейшей оптимизации с помощью машинного обучения.

DictSegment segment = new DictSegment();
System.out.println(segment.seg("我是中国人"));
System.out.println(segment.seg("人工智能是什么"));
System.out.println(segment.seg("北京互联网违法和不良信息举报中心"));
[我, 是, 中国人]
[人工智能, 是, 什么]
[北京, 互联网, 违法, 和不, 良, 信息, 举报中心]

легко реализовать

Определите класс узла для представления узла дерева Trie, содержащего несколько дочерних узлов, значений и маркеров удаления.getChildМетод используется для обхода дочерних узлов указанного персонажа под узлом,allChildrenDeletedМетод используется для определения того, был ли удален дочерний узел под узлом,setChildМетод используется для установки дочерних узлов в узел.

public class TrieNode {

	private TrieNode[] children;
	private String value;
	private boolean deleted = false;

	public TrieNode(String value) {
		this.value = value == null ? null : value.intern();
	}

	public boolean isEmpty() {
		return this.value == null && this.children == null;
	}

	public TrieNode[] getChildren() {
		return children;
	}

	public TrieNode getChild(String word) {
		if (children == null)
			return null;
		for (TrieNode c : children) {
			if (c.getValue() == word.intern() && !c.deleted)
				return c;
		}
		return null;
	}

	public boolean allChildrenDeleted() {
		if (children == null)
			return true;
		for (TrieNode c : children) {
			if (!c.deleted)
				return false;
		}
		return true;
	}

	public void setChild(TrieNode child) {
		if (children == null) {
			children = new TrieNode[1];
			children[0] = child;
		} else {
			TrieNode[] temp = children;
			children = new TrieNode[temp.length + 1];
			System.arraycopy(temp, 0, children, 0, temp.length);
			children[children.length - 1] = child;
		}
	}

}

Определите класс TrieTree для представления объекта дерева, включая корневой узел дерева.putМетод используется для помещения строки в древовидную структуру, необходимо пройти, чтобы проверить, есть ли уже префикс строки, если нет, создать соответствующий узел, а затем добавить его в дочерние узлы соответствующего узла.getиremoveВсе операции должны быть обработаны в отношении древовидной структуры и, наконец, завершить запрос и удаление.Для удобства операция удаления должна только установить флаг удаления указанного узла.

public class TrieTree {

	protected TrieNode root;

	public TrieTree() {
		this.root = new TrieNode(null);
	}

	public void put(String word) throws IllegalArgumentException {
		if (word == null) {
			throw new IllegalArgumentException();
		}
		TrieNode current = this.root;
		for (String s : word.split("")) {
			TrieNode child = current.getChild(s);
			if (child == null) {
				child = new TrieNode(s);
				current.setChild(child);
			}
			current = child;
		}
	}

	public TrieNode get(String word) throws IllegalArgumentException {
		if (word == null) {
			throw new IllegalArgumentException();
		}
		TrieNode current = this.root;
		for (String s : word.split("")) {
			TrieNode child = current.getChild(s);
			if (child == null)
				return null;
			current = child;
		}
		return current;
	}

	public void remove(String word) {
		if (word == null || word.length() <= 0) {
			return;
		}
		for (int i = 0; i < word.length(); i++) {
			String sub_word = word.substring(0, word.length() - i);
			TrieNode current = this.root;
			for (String s : sub_word.split("")) {
				TrieNode child = current.getChild(s);
				if (child != null && (child.getChildren() == null || child.allChildrenDeleted()))
					child.setDeleted(true);
				current = child;
			}
		}
	}

}

segДля метода сегментации слов он в основном пытается сопоставить максимальную строку, пытается сопоставить самое длинное слово в словаре и выясняет, есть ли строка в дереве тери.

public List<String> seg(String text) {
		int flag = 0;
		int delta = 1;
		List<String> words = new ArrayList<String>();
		while (flag + delta <= text.length()) {
			String temp = text.substring(flag, flag + delta);
			if (tree.get(temp) != null) {
				if ((flag + delta) == text.length()) {
					words.add(temp);
					break;
				}
				delta++;
				continue;
			}
			words.add(temp.substring(0, temp.length() - 1));
			flag = flag + delta - 1;
			delta = 1;
		}
		return words;
	}

------------- Рекомендуем прочитать ------------

Резюме моей статьи за 2017 год — машинное обучение

Краткое изложение моих статей за 2017 год — Java и промежуточное ПО

Резюме моих статей 2017 года — глубокое обучение

Краткое изложение моих статей за 2017 год — исходный код JDK

Резюме моей статьи за 2017 год — обработка естественного языка

Резюме моих статей 2017 года — Java Concurrency


Поговори со мной, задай мне вопросы:

这里写图片描述

Меню официальной учетной записи было разделено на «Сводка для чтения», «Распределенное», «Машинное обучение», «Глубокое обучение», «НЛП», «Глубина Java», «Ядро параллелизма Java», «Исходный код JDK», "Tomcat Core" "Подождите, может быть, есть тот, который соответствует вашему аппетиту.

Зачем писать «Анализ проектирования ядра Tomcat»

Добро пожаловать, чтобы следовать:

这里写图片描述