Моделирование цепи Маркова с помощью Neo4J

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

цепь Маркова может быть легко представлена в Neo4J путем создания узла для каждого состояния, отношения для каждого перехода, а затем аннотирования отношений перехода с соответствующей вероятностью.

но, вы можете моделирование цепь Маркова с использованием Neo4J? Например, можно ли заставить Neo4J начать в определенное состояние, а затем переход к следующему состоянию и следующему состоянию на основе вероятностей? Может ли Neo4J вернуться с распечаткой пути, который он прошел через это пространство состояний?

возможно, это легче понять с помощью простого примера. Предположим, я хочу сделать 2-граммовую модель английского языка на основе текста блог технологии моей компании. Я запускаю скрипт, который делает следующее:

  1. он тянет вниз текст блог.
  2. он перебирает каждую пару соседних букв и создает узел в Neo4J.
  3. он повторяет снова над каждым 3-кортежем соседних букв, а затем создает направленную связь Neo4J между узлом, представленным первыми двумя буквами, и узлом, представленным последними двумя буквами. Он инициализирует счетчик в этом отношении к 1. Если связь уже существует, то счетчик увеличивается.
  4. наконец, он проходит через каждый узел подсчитывает, сколько всего исходящих переходов произошло, а затем создает новую аннотацию для каждого отношения конкретного узла, равного count/totalcount. Это вероятность перехода.

теперь, когда граф Neo4J завершен, как я могу заставить его создать "предложение" из моей 2-граммовой модели английского языка? Вот как может выглядеть вывод:

В ИСТ ШИРОТА СЫВОРОТОЧНЫЙ CRATICT FROURE БИРС GROCID PONDENOME ИЗ DEMONSTURES ИЗ REPTAGIN ЯВЛЯЕТСЯ REGOACTIONA ИЗ КРЭ.

1 ответов


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

я воссоздал ваш эксперимент здесь, С несколькими изменениями. Прежде всего, я заполняю базу данных одним проходом через текст (шаги 2 и 3), но это незначительно. Что еще более важно, я храню только количество вхождений на каждом отношение и общее число на узле (Шаг 4), так как я не думаю, что существует необходимость предварительного вычисления вероятностей.

код, который вы просите, выглядит примерно так:

/**
 * A component that creates a random sentence by a random walk on a Markov Chain stored in Neo4j, produced by
 * {@link NGramDatabasePopulator}.
 */
public class RandomSentenceCreator {

    private final Random random = new Random(System.currentTimeMillis());

    /**
     * Create a random sentence from the underlying n-gram model. Starts at a random node an follows random outgoing
     * relationships of type {@link Constants#REL} with a probability proportional to that transition occurrence in the
     * text that was processed to form the model. This happens until the desired length is achieved. In case a node with
     * no outgoing relationships it reached, the walk is re-started from a random node.
     *
     * @param database storing the n-gram model.
     * @param length   desired number of characters in the random sentence.
     * @return random sentence.
     */
    public String createRandomSentence(GraphDatabaseService database, int length) {
        Node startNode = randomNode(database);
        return walk(startNode, length, 0);
    }

    private String walk(Node startNode, int maxLength, int currentLength) {
        if (currentLength >= maxLength) {
            return (String) startNode.getProperty(NAME);
        }

        int totalRelationships = (int) startNode.getProperty(TOTAL, 0);
        if (totalRelationships == 0) {
            //terminal node, restart from random
            return walk(randomNode(startNode.getGraphDatabase()), maxLength, currentLength);
        }

        int choice = random.nextInt(totalRelationships) + 1;
        int total = 0;
        Iterator<Relationship> relationshipIterator = startNode.getRelationships(OUTGOING, REL).iterator();

        Relationship toFollow = null;
        while (total < choice && relationshipIterator.hasNext()) {
            toFollow = relationshipIterator.next();
            total += (int) toFollow.getProperty(PROBABILITY);
        }

        Node nextNode;
        if (toFollow == null) {
            //no relationship to follow => stay on the same node and try again
            nextNode = startNode;
        } else {
            nextNode = toFollow.getEndNode();
        }

        return ((String) nextNode.getProperty(NAME)).substring(0, 1) + walk(nextNode, maxLength, currentLength + 1);
    }

    private Node randomNode(GraphDatabaseService database) {
        return random(GlobalGraphOperations.at(database).getAllNodes());
    }
}