Получите плохой результат для случайной прогулки

1

Я хочу реализовать случайное блуждание и вычислить устойчивое состояние.

Предположим, что мой график задан как на следующем изображении: Изображение 174551

График выше определен в файле следующим образом:

1   2   0.9
1   3   0.1
2   1   0.8
2   2   0.1
2   4   0.1
etc

Чтобы прочитать и построить этот график, я использую следующий метод:

def _build_og(self, original_ppi):
""" Build the original graph, without any nodes removed. """

try:
    graph_fp = open(original_ppi, 'r')
except IOError:
    sys.exit("Could not open file: {}".format(original_ppi))

G = nx.DiGraph()
edge_list = []

# parse network input
for line in graph_fp.readlines():
    split_line = line.rstrip().split('\t')
    # assume input graph is a simple edgelist with weights
    edge_list.append((split_line[0], split_line[1],  float(split_line[2])))

G.add_weighted_edges_from(edge_list)
graph_fp.close()
print edge_list

return G

В вышеприведенной функции мне нужно определить граф как DiGraph или simpy Graph?

Мы строим матрицу перехода следующим образом:

def _build_matrices(self, original_ppi, low_list, remove_nodes):
        """ Build column-normalized adjacency matrix for each graph.

        NOTE: these are column-normalized adjacency matrices (not nx
              graphs), used to compute each p-vector
        """
        original_graph = self._build_og(original_ppi)
        self.OG = original_graph
        og_not_normalized = nx.to_numpy_matrix(original_graph)
        self.og_matrix = self._normalize_cols(og_not_normalized)

И я нормализую матрицу, используя:

def _normalize_cols(self, matrix):
        """ Normalize the columns of the adjacency matrix """
        return normalize(matrix, norm='l1', axis=0)

теперь для моделирования случайного блуждания мы определяем:

def run_exp(self, source):

        CONV_THRESHOLD = 0.000001
        # set up the starting probability vector
        p_0 = self._set_up_p0(source)
        diff_norm = 1
        # this needs to be a deep copy, since we're reusing p_0 later
        p_t = np.copy(p_0)

        while (diff_norm > CONV_THRESHOLD):
            # first, calculate p^(t + 1) from p^(t)
            p_t_1 = self._calculate_next_p(p_t, p_0)

            # calculate L1 norm of difference between p^(t + 1) and p^(t),
            # for checking the convergence condition
            diff_norm = np.linalg.norm(np.subtract(p_t_1, p_t), 1)

            # then, set p^(t) = p^(t + 1), and loop again if necessary
            # no deep copy necessary here, we're just renaming p
            p_t = p_t_1

Мы определяем начальное состояние (p_0), используя следующий метод:

def _set_up_p0(self, source):
    """ Set up and return the 0th probability vector. """
    p_0 = [0] * self.OG.number_of_nodes()
    # convert self.OG.number_of_nodes() to list
    l =  list(self.OG.nodes())
    #nx.draw(self.OG, with_labels=True)
    #plt.show()
    for source_id in source:
        try:
            # matrix columns are in the same order as nodes in original nx
            # graph, so we can get the index of the source node from the OG
            source_index = l.index(source_id)
            p_0[source_index] = 1 / float(len(source))
        except ValueError:
            sys.exit("Source node {} is not in original graph. Source: {}. Exiting.".format(source_id, source))

    return np.array(p_0)  

Чтобы сгенерировать следующее состояние, мы используем следующую функцию

и стратегия итерации мощности:

def _calculate_next_p(self, p_t, p_0):
        """ Calculate the next probability vector. """
        print 'p_0\t{}'.format(p_0)
        print 'p_t\t{}'.format(p_t)
        epsilon = np.squeeze(np.asarray(np.dot(self.og_matrix, p_t)))
        print 'epsilon\t{}'.format(epsilon)
        print 10*"*"
        return np.array(epsilon)

Предположим, что случайное блуждание может начинаться с любого узла (1, 2, 3 или 4).

При запуске кода я получаю следующий результат:

2       0.32
3       0.31
1       0.25
4       0.11

Результат должен быть:

(0.28, 0.30, 0.04, 0.38).

Так может кто-то помочь мне определить, где моя ошибка?

Я не знаю, находится ли проблема в моей переходной матрице.

  • 0
    1. В вашем вопросе тонна кода. Можете ли вы упростить вещи, чтобы мы лучше понимали, что происходит? Копировать / вставлять из вашего кода проще, но нам намного труднее понять 2. Не ясно, что такое «другое». Можете ли вы нарисовать или объяснить, как результат отличается и каков ожидаемый результат?
  • 0
    @ CD98 Я хочу вычислить вектор устойчивого распределения для данного ориентированного графа. Этот вектор должен быть равен [0,35, 0,56, 0,07]. Но в моем результате я получаю [0,41, 0,35, 0,24].
Теги:
networkx
random-walk

1 ответ

1
Лучший ответ

Вот как должна быть матрица (заданная, чем ваша матрица перехода, умножает вектор состояния слева, это левая стохастическая матрица, где столбцы составляют до 1, а запись (i, j) - это вероятность перехода от j к i).

import numpy as np
transition = np.array([[0, 0.8, 0, 0.1], [0.9, 0.1, 0.5, 0], [0.1, 0, 0.3, 0], [0, 0.1, 0.2, 0.9]])
state = np.array([1, 0, 0, 0])    # could be any other initial position
diff = tol = 0.001
while diff >= tol:
    next_state = transition.dot(state)
    diff = np.linalg.norm(next_state - state, ord=np.inf)
    state = next_state
print(np.around(state, 3))

Это печатает [0.279 0.302 0.04 0.378].

Я не могу сказать, неправильно ли вы загружаете данные или что-то еще. Шаг с "нормализацией столбцов" является предупреждающим знаком: если данные вероятности перехода не составляют до 1, вы должны сообщать о плохих данных, а не нормализовать столбцы. И я не знаю, почему вы используете NetworkX вообще, когда данные уже представлены в виде матрицы: таблица, которую вы даете, может быть прочитана как

column   row   entry 

и эта матрица нужна для расчетов.

  • 0
    Спасибо за ваш ответ. Я не знаю, как вы получаете матрицу перехода в этой форме. У меня есть файл .txt, содержащий узел и дугу между ними. 1 2 0,9 означает дугу с весом 0,9 между узлом 1 и узлом 2.
  • 1
    Правильно, поэтому transition[1, 0] = 0.9 (смещение для индексов на основе 0). Первая строка матрицы - это вероятность перехода в узел 1 из узлов 1, 2, 3, 4. Вторая строка: вероятность перехода в узел 2 из узлов 1, 2, 3, 4. И т.д.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню