Я пытаюсь реализовать алгоритм для генерации графиков, следующих Модель Барабаси-Альберта (BA). Согласно этой модели, распределение степеней происходит по степенному закону:
P (k) ~ k ^ -λ
Где показатель λ должен быть равен 3.
Для простоты я сосредоточусь здесь на коде R, где я использую igraph
функции. Тем не менее, я получаю сети с λ! = 3. Кажется, что эта тема широко освещена (пример вопроса 1, eq2, EQ3), но я не смог найти удовлетворительного решения.
В R я использую igraph:::sample_pa
функция для генерации графика по модели БА. В воспроизводимом примере ниже я установил
# Initialize
set.seed(1234)
order = 100
v_degrees = vector()
for (i in 1:10000) {
g <- sample_pa(order, power=3, m=8)
# Get degree distribution
d = degree(g, mode="all")
dd = degree_distribution(g, mode="all", cumulative=FALSE)
d = 1:max(d)
probability = dd[-1]
nonzero.position = which(probability !=0)
probability = probability[nonzero.position]
d = d[nonzero.position]
# Fit power law distribution and get gamma exponent
reg = lm (log(probability) ~ log(d))
cozf = coef(reg)
power.law.fit = function(x) exp(cozf[[1]] + cozf[[2]] * log(x))
gamma = -cozf[[2]]
v_degrees[i] = gamma
}
График, кажется, на самом деле не масштабируется, давая гамма = 0,72 ± 0,21 с заказом 100 и гамма = 0,68 ± 0,24 для порядка 10000 и аналогичных результатов, варьирующих параметр м. Но показатель степени явно отличается от ожидаемой гаммы = 3.
Фактически я пытался реализовать эту модель на другом языке (C ++, см. Код ниже), но я получаю аналогичные результаты с показателями ниже 3. Поэтому мне интересно, является ли это распространенным недоразумением в модели BA или что-то не так в предыдущие расчеты, соответствующие распределению по степенному закону, противоречат тому, что обычно ожидается, это нормальное поведение модели БА.
Если кто-то заинтересован или более знаком с C ++, см. Приложение ниже.
Приложение: код C ++
Для понимания кода ниже, предположим, что объектный класс Graph
и connect
функция, которая создала ребро между двумя вершинами, переданными в качестве аргумента. Ниже я даю код двух соответствующих функций BA_step а также build_BA.
BA_step
void Graph::BA_step (int ID, int m, std::vector<double>& freqs) {
std::vector<int> connect_history;
vertices.push_back(ID);
// Connect node ID to a random node i with pi ~ ki / sum kj
while (connect_history.size() < m) {
double U (sample_prob()); // gets a value in the range [0,1)
int index (freqs[freqs.size()-1]);
for (int i(0); i<freqs.size(); ++i) {
if (U<=freqs[i]/index && !is_in(connect_history, i)) { // is_in checks if i exists in connect_history
connect(ID, i);
connect_history.push_back(i);
break;
}
}
}
// Update vector of absolute edge frequencies
for (int i(0); i<connect_history.size(); ++i) {
int index (connect_history[i]);
for (int j(index); j<freqs.size(); ++j) {
++freqs[j];
}
}
freqs.push_back(m+freqs[freqs.size()-1]);
}
build_BA
void Graph::build_BA (int m0, int m) {
// Initialization
std::vector<double> cum_nedges;
std::vector<int> connect_history;
for (int ID(0); ID<m0; ++ID) {
vertices.push_back(ID);
}
// Initial BA step
vertices.push_back(m0);
for (int i(0); i<m; ++i) {
connect(m0, i);
connect_history.push_back(i);
}
cum_nedges.push_back(1);
for (int i(1); i<m; ++i) cum_nedges.push_back(cum_nedges[cum_nedges.size()-1]+1);
cum_nedges.push_back(m+m);
// BA model
for (int ID(m0+1); ID<order; ++ID) {
BA_step(ID, m, cum_nedges);
}
}
Две вещи могут помочь:
sample_pa
аргументы, чтобы получить показатель alpha = 3
Действительно power = 1
а также m = 1
(проверьте определение в той статье википедии по документации igraph :: sample_pa — power
аргумент не означает степень степенного распределения).
Просто запустив OLS / LM для распределения степеней, вы получите показатель степени ближе к 0, чем к 3 (другими словами, недооцененный). Вместо этого, если вы используете igraph::power_law_fit
командование с высоким xmin
, вы получите ответы ближе к 3. Проверьте Страница Аарона Клаусета и публикации для получения дополнительной информации об оценке степенных законов. На самом деле вам нужно оценить оптимальное X-мин для каждого распределения степени.
Вот код, который будет работать немного лучше:
library(igraph)
set.seed(1234)
order = 10000
v_degrees = vector()
for (i in 1:100) {
g <- sample_pa(order, power = 1, m = 1)
d <- degree(g, mode="all")
v_degrees[i] <- fit_power_law(d, ceiling(mean(d))+100) %>% .$alpha
}
v_degrees %>% summary()
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.646 2.806 2.864 2.873 2.939 3.120
Обратите внимание, что я составляю х-мин для использования (ceiling(mean(d))+100
). Изменение этого изменит ваши ответы.
Других решений пока нет …