# !pip install powerlaw
Network Science - UDD
Leyes de Potencia
Cristian Candia-Castro Vallejos, Ph.D.
- [1] Data Science Institute (IDS), Universidad del Desarrollo, Chile
- [2] Northwestern Institute on Complex Systems, Kellogg School of Management, Northwestern Unviersity, USA
- [3] Centro de Investigación en Complejidad Social, Universidad del Desarrollo, Chile
- [4] Computational Research in Social Science Laboratory, Facultad de Ingeniería y Facultad de Gobierno, Universidad del Desarrollo, Chile
Referencias: Descargar artiículo https://arxiv.org/pdf/1305.0215.pdf
Paquetes
import powerlaw #INSTALLAR usando pip
print(powerlaw.__version__)
1.5
%pylab inline
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
import pylab
'xtick.major.pad']='8'
pylab.rcParams['ytick.major.pad']='8'
pylab.rcParams[#pylab.rcParams['font.sans-serif']='Arial'
from matplotlib import rc
'font', family='sans-serif')
rc('font', size=10.0)
rc('text', usetex=False)
rc(
from matplotlib.font_manager import FontProperties
= FontProperties().copy()
panel_label_font "bold")
panel_label_font.set_weight(12.0)
panel_label_font.set_size("sans-serif") panel_label_font.set_family(
Cargando data (repositorios online)
from os import listdir
= listdir('.')
files if 'blackouts.txt' not in files:
import urllib
'https://raw.github.com/jeffalstott/powerlaw/master/manuscript/blackouts.txt', 'blackouts.txt')
urllib.urlretrieve(if 'words.txt' not in files:
import urllib
'https://raw.github.com/jeffalstott/powerlaw/master/manuscript/words.txt', 'words.txt')
urllib.urlretrieve(if 'worm.txt' not in files:
import urllib
'https://raw.github.com/jeffalstott/powerlaw/master/manuscript/worm.txt', 'worm.txt') urllib.urlretrieve(
from numpy import genfromtxt
#Cargando data
= genfromtxt('blackouts.txt')#/10**3
blackouts = genfromtxt('words.txt')
words = genfromtxt('worm.txt')
worm = worm[worm>0] worm
El primer conjunto de datos mejor ajustado es quizás el más conocido y sólido de todos las ditribuciones de leyes de potencia: la frecuencia de uso de las palabras en el idioma inglés. Los datos específicos utilizados son las frecuencias del uso de las palabras en la novela de Herman Melville “Moby Dick”.
El segundo, moderadamente apropiado conjunto de datos es el número de conexiones que tiene cada neurona en el gusano nematodo C. elegans.
El último, los datos inadecuados son el número de personas afectadas por apagones en los Estados Unidos entre 1984 y 2002.
def plot_basics(data, data_inst, fig, units):
from powerlaw import plot_pdf, Fit, pdf
= (-.4, .95)
annotate_coord = fig.add_subplot(n_graphs,n_data,data_inst)
ax1 = pdf(data, linear_bins=True)
x, y = y>0
ind = y[ind]
y = x[:-1]
x = x[ind]
x ='r', s=.5)
ax1.scatter(x, y, color>0], ax=ax1, color='b', linewidth=2)
plot_pdf(data[datafrom pylab import setp
=False)
setp( ax1.get_xticklabels(), visible
if data_inst==1:
"A", annotate_coord, xycoords="axes fraction", fontproperties=panel_label_font)
ax1.annotate(
from mpl_toolkits.axes_grid.inset_locator import inset_axes
= inset_axes(ax1, width = "30%", height = "30%", loc=3)
ax1in ='b')#normed=True,
ax1in.hist(data, color
ax1in.set_xticks([])
ax1in.set_yticks([])
= fig.add_subplot(n_graphs,n_data,n_data+data_inst, sharex=ax1)
ax2 =ax2, color='b', linewidth=2)
plot_pdf(data, ax= Fit(data, xmin=1, discrete=True)
fit =ax2, linestyle=':', color='g')
fit.power_law.plot_pdf(ax= fit.power_law.pdf()
p
ax2.set_xlim(ax1.get_xlim())
= Fit(data, discrete=True)
fit =ax2, linestyle='--', color='g')
fit.power_law.plot_pdf(axfrom pylab import setp
=False)
setp( ax2.get_xticklabels(), visible
if data_inst==1:
"B", annotate_coord, xycoords="axes fraction", fontproperties=panel_label_font)
ax2.annotate(u"p(X)")# (10^n)")
ax2.set_ylabel(
= fig.add_subplot(n_graphs,n_data,n_data*2+data_inst)#, sharex=ax1)#, sharey=ax2)
ax3 =ax3, linestyle='--', color='g')
fit.power_law.plot_pdf(ax=ax3, linestyle='--', color='r')
fit.exponential.plot_pdf(ax=ax3, color='b', linewidth=2)
fit.plot_pdf(ax
ax3.set_ylim(ax2.get_ylim())
ax3.set_xlim(ax1.get_xlim())
if data_inst==1:
"C", annotate_coord, xycoords="axes fraction", fontproperties=panel_label_font)
ax3.annotate(
ax3.set_xlabel(units)
Figura 1
= 3
n_data = 4
n_graphs = figure(figsize=(12,15))
f
= words
data = 1
data_inst = 'Word Frequency'
units
plot_basics(data, data_inst, f, units)
= 2
data_inst #data = city
#units = 'City Population'
= worm
data = 'Neuron Connections'
units
plot_basics(data, data_inst, f, units)
= blackouts
data = 3
data_inst = 'Population Affected\nby Blackouts'
units
plot_basics(data, data_inst, f, units)
=None, bottom=None, right=None, top=None, wspace=.3, hspace=.2)
f.subplots_adjust(left= 'FigWorkflow'
figname +'.eps', bbox_inches='tight')
f.savefig(figname#f.savefig(figname+'.tiff', bbox_inches='tight', dpi=300)
/var/folders/q8/5g879lls62l1z8smyjkh4h700000gn/T/ipykernel_34258/3393955097.py:19: MatplotlibDeprecationWarning:
The mpl_toolkits.axes_grid module was deprecated in Matplotlib 2.1 and will be removed two minor releases later. Use mpl_toolkits.axes_grid1 and mpl_toolkits.axisartist, which provide the same functionality instead.
from mpl_toolkits.axes_grid.inset_locator import inset_axes
Calculating best minimal value for power law fit
Calculating best minimal value for power law fit
Calculating best minimal value for power law fit
xmin progress: 99%
Linea punteada representa con xmin de 1.
Linea segmentada representa un xmin estimado
Pasos básicos de análisis para distribuciones de cola pesada: visualización, ajuste y comparación.
Los datos de ejemplo para el ajuste de la ley de potencia son: buen ajuste (columna izquierda), ajuste medio (centro columna) y mal ajuste (columna derecha).
Visualizando datos con funciones de densidad de probabilidad. Un histograma típico en ejes lineales (recuadros) no es útil para visualizar distribuciones de cola pesada. En los ejes log-log, es necesario utilizar contenedores (bins) espaciados logarítmicamente para representar datos (linea azul). Los contenedores espaciados linealmente (línea roja) ocultan la cola de la distribución (ver paper).
Ajuste a la cola de la distribución. El mejor ajuste de ley de potencia solo puede cubrir una parte de la cola de la distribución. Línea verde punteada: la ley de potencia se ajusta a partir de xmin=1 . Línea verde discontinua: ley de potencia ajuste desde el
óptimo (consulte Métodos básicos: Identificación del rango de escala).Comparando la bondad del ajuste. Una vez que se establece el mejor ajuste a una ley de potencia, la comparación con otras posibles distribuciones son necesarias. Línea verde discontinua: ajuste de la ley de potencia a partir del
óptimo. Línea roja punteado: ajuste exponencial a partir del mismo .
= blackouts/10**3 blackouts
Introducción
= blackouts
data ####
import powerlaw
= powerlaw.Fit(data)
fit
fit.power_law.alpha
fit.power_law.sigma
'power_law', 'exponential') fit.distribution_compare(
Calculating best minimal value for power law fit
xmin progress: 99%
(12.7545626758821, 0.15229255604426487)
= words
data ####
import powerlaw
= powerlaw.Fit(data)
fit
fit.power_law.alpha
fit.power_law.sigma'power_law', 'exponential') fit.distribution_compare(
Calculating best minimal value for power law fit
xmin progress: 99%
(3809.7804237111686, 2.753965722517646e-23)
= worm
data ####
import powerlaw
= powerlaw.Fit(data)
fit
fit.power_law.alpha
fit.power_law.sigma'power_law', 'exponential') fit.distribution_compare(
Calculating best minimal value for power law fit
xmin progress: 93%
(16.601134166691274, 0.0005788608926042935)
Devuelve el log-likelihood* ratio, y su valor p , entre los dos ajustes de distribución, asumiendo que las distribuciones candidatas están anidadas.
Si es mayor que 0, se prefiere la primera distribución. Si es menor que 0, se prefiere la segunda distribución.
*El likelihood cuantifica qué tan bueno es un modelo, dado un conjunto de datos que se han observado.
Basic Methods
Visualization
PDF Linear vs Logarithmic Bins
= words
data ####
= powerlaw.plot_pdf(data, color='b')
figPDF =True, color='r', ax=figPDF)
powerlaw.plot_pdf(data, linear_bins####
"p(X)")
figPDF.set_ylabel(r"Word Frequency")
figPDF.set_xlabel(= 'FigPDF'
figname +'.eps', bbox_inches='tight')
savefig(figname#savefig(figname+'.tiff', bbox_inches='tight', dpi=300)
Las PDF requieren bining en los datos, y al presentar una PDF en ejes logarítmicos, los contenedores deben tener espaciado logarítmico (anchos exponencialmente crecientes).
Aunque los contenedores lineales mantienen una alta resolución en todo el rango de valores, la probabilidad muy reducida de observar valores grandes en las distribuciones dificulta una estimación confiable de su probabilidad de ocurrencia.
Esto se compensa utilizando bins logarítmicos, lo que aumenta la probabilidad de observar un rango de valores en la cola de la distribución y normalizando apropiadamente para ese aumento en el ancho del contenedor.
Figura 2
= words
data = powerlaw.Fit(data, discrete=True)
fit ####
= fit.plot_pdf(color='b', linewidth=2)
figCCDF ='b', linestyle='--', ax=figCCDF)
fit.power_law.plot_pdf(color='r', linewidth=2, ax=figCCDF)
fit.plot_ccdf(color='r', linestyle='--', ax=figCCDF)
fit.power_law.plot_ccdf(color
####
u"p(X), p(X≥x)")
figCCDF.set_ylabel(r"Word Frequency")
figCCDF.set_xlabel(
= 'FigCCDF'
figname +'.eps', bbox_inches='tight')
savefig(figname#savefig(figname+'.tiff', bbox_inches='tight', dpi=300)
Calculating best minimal value for power law fit
xmin progress: 99%
Otra forma de extraer información sobre la cola de la distribución es usando la Distribución acumulada complementaria, donde:
Donde si
Función de densidad de probabilidad
Función de distribución acumulativa complementaria
= blackouts
data = powerlaw.Fit(data)
fit ###
= fit.cdf()
x, y = fit.pdf()
bin_edges, probability = fit.lognormal.cdf()#data=[300,350]
y = fit.lognormal.pdf() y
Calculating best minimal value for power law fit
xmin progress: 99%
Identificando el rango de escalamiento (de la ley de potencia)
El primer paso para ajustar una ley de potencia es determinar en qué parte de los datos se ajustará una cola pesada.
Una característica interesante de la distribución es la cola pesada son su cola y sus propiedades, por lo que si los valores iniciales, pequeños de los datos no siguen una distribución de ley de potencia, el usuario puede optar por ignorar dichos datos.
La pregunta es de que valor mínimo xmin comienza la relación de escala de la ley de potencia?. Los métodos de [5] (ver paper) encuentran este óptimo, el valor de xmin, al crear un ajuste de ley de potencia a partir de cada valor único en el conjunto de datos, luego seleccionando el que resulta en la distancia mínima de Kolmogorov-Smirnov, D, entre los datos y el ajuste.
Si el usuario no proporciona un valor para xmin, Powerlaw calcula el valor óptimo cuando el objeto Fit se crea por primera vez. Como las leyes de potencia no están definidas para x = 0, debe haber algún valor mínimo. Por lo tanto, incluso si un determinado conjunto de datos trae consigo un razonamiento específico del dominio de que los datos deben seguir una ley de potencia en todo su rango, el usuario todavía debe dictar un xmin. Esto podría ser un mínimo teórico, un umbral de ruido, o el valor mínimo observado en los datos. La Figura 1B visualiza la diferencia de ajuste entre la asignación xmin = 1 y encontrar el xmin óptimo minimizando D
= blackouts
data ####
import powerlaw
= powerlaw.Fit(data)
fit
print(':')
print(fit.xmin)
print(fit.fixed_xmin)
print(fit.alpha)
print(fit.D)
print('---------')
= powerlaw.Fit(data, xmin=1.0)
fit print(fit.xmin)
print(fit.fixed_xmin)
print(fit.alpha)
print(fit.D)
Calculating best minimal value for power law fit
:min progress: 99%
230000.0
False
2.272637219830288
0.0606737962944387
---------
1.0
True
1.087339569337401
0.5080981565416758
= blackouts
data ####
= powerlaw.Fit(data)#, xmin=(250.0, 300.0)
fit
fit.fixed_xmin
fit.given_xmin fit.xmin
Calculating best minimal value for power law fit
xmin progress: 99%
230000.0
Un límite superior también podría deberse a la escala de tamaño finito, en la que los datos observados provienen de una pequeña subsección de un sistema más grande.
El tamaño finito de la ventana de observación significaría que los puntos de datos individuales no podrían ser más grandes que dicha ventana, xmax, aunque el sistema mayor tendría datos más grandes, no observados (por ejemplo, en neurociencia, grabados desde un trozo de corteza vs todo el cerebro).
Los efectos de tamaño finito se pueden probar variando experimentalmente el tamaño de la ventana de observación (y xmax) y determinando si los datos siguen una ley de potencia con el nuevo xmax [3, 4] (ver paper). La presencia de un límite superior se basa en la naturaleza de los datos y el contexto en el que se recopilaron, por lo que solo puede ser dictada por el usuario. Cualquier dato por encima de xmax se ignora para el ajuste.
= blackouts
data = powerlaw.Fit(data)
fit print(':')
print(fit.xmax)
print(fit.fixed_xmax)
####
= powerlaw.Fit(data, xmax=10000.0)
fit print(':')
print(fit.xmax)
print(fit.fixed_xmax)
Calculating best minimal value for power law fit
:min progress: 99%
None
False
Calculating best minimal value for power law fit
:min progress: 90%
10000.0
True
Figura 3
Para calcular o trazar CDF, CCDF y PDF, de forma predeterminada, los objetos Fit solo usan datos por encima de xmin y por debajo de xmax (si están presentes).
Los comandos de ploteo del objeto Fit pueden trazar todos los datos que se le dieron originalmente con el key original_data = True. Los objetos Distribution constituyentes solo se definen dentro del rango de xmin y xmax, pero pueden plotear cualquier subconjunto de ese rango pasando datos específicos con el key data.
Cuando se utiliza un xmax, el CDF y el CCDF de una ley de potencia no muestran una línea recta en un gráfico log-log, sino que se inclinan hacia abajo cuando se acercan al xmax (Figura 3). La PDF, en contraste, aparece como una línea recta en todo el rango hasta xmax. Debido a esta diferencia, las PDF son preferibles cuando se visualizan datos con un xmax, a fin de no oscurecer la escala.
= words
data #FigCCDFmax = powerlaw.plot_ccdf(data, linewidth=3)
= powerlaw.Fit(data, discrete=True, xmax=None)
fit = fit.plot_ccdf(color='b', label=r"Empirical, no $x_{max}$")
FigCCDFmax ='b', linestyle='--', ax=FigCCDFmax, label=r"Fit, no $x_{max}$")
fit.power_law.plot_ccdf(color
= powerlaw.Fit(data, discrete=True, xmax=1000)
fit ='r', label=r"Empirical, $x_{max}=1000$")
fit.plot_ccdf(color='r', linestyle='--', ax=FigCCDFmax, label=r"Fit, $x_{max}=1000$")
fit.power_law.plot_ccdf(color
#x, y = powerlaw.ccdf(data, xmax=max(data))
#fig1.plot(x,y)
####
#FigCCDFmax.set_ylabel(r"$p(X\geq x)$")
u"p(X≥x)")
FigCCDFmax.set_ylabel(r"Word Frequency")
FigCCDFmax.set_xlabel(= FigCCDFmax.get_legend_handles_labels()
handles, labels = FigCCDFmax.legend(handles, labels, loc=3)
leg False)
leg.draw_frame(
= 'FigCCDFmax'
figname +'.eps', bbox_inches='tight')
savefig(figname#savefig(figname+'.tiff', bbox_inches='tight', dpi=300)
Calculating best minimal value for power law fit
Calculating best minimal value for power law fit
xmin progress: 96%xmin progress: 99%
/Users/crcandia/anaconda3/envs/candialab/lib/python3.10/site-packages/powerlaw.py:1195: RuntimeWarning: divide by zero encountered in double_scalars
C = 1.0/C
/Users/crcandia/anaconda3/envs/candialab/lib/python3.10/site-packages/scipy/optimize/_optimize.py:811: RuntimeWarning: invalid value encountered in subtract
np.max(np.abs(fsim[0] - fsim[1:])) <= fatol):
/Users/crcandia/anaconda3/envs/candialab/lib/python3.10/site-packages/powerlaw.py:840: RuntimeWarning: invalid value encountered in multiply
likelihoods = f*C