1 | import matplotlib.pyplot as plt |
---|
2 | from math import * |
---|
3 | |
---|
4 | # function h=plplot(x, xmin, alpha) |
---|
5 | # PLPLOT visualizes a power-law distributional model with empirical data. |
---|
6 | # Source: http://www.santafe.edu/~aaronc/powerlaws/ |
---|
7 | # |
---|
8 | # PLPLOT REQUIRES the use of the free library: matplotlib |
---|
9 | # |
---|
10 | # PLPLOT(x, xmin, alpha) plots (on log axes) the data contained in x |
---|
11 | # and a power-law distribution of the form p(x) ~ x^-alpha for |
---|
12 | # x >= xmin. For additional customization, PLPLOT returns a pair of |
---|
13 | # handles, one to the empirical and one to the fitted data series. By |
---|
14 | # default, the empirical data is plotted as 'bo' and the fitted form is |
---|
15 | # plotted as 'k--'. PLPLOT automatically detects whether x is composed |
---|
16 | # of real or integer values, and applies the appropriate plotting |
---|
17 | # method. For discrete data, if min(x) > 50, PLFIT uses the continuous |
---|
18 | # approximation, which is a reliable in this regime. |
---|
19 | # |
---|
20 | # Example: |
---|
21 | # xmin = 47; |
---|
22 | # alpha = 2.71; |
---|
23 | # x = [500,150,90,81,75,75,70,65,60,58,49,47,40] |
---|
24 | # h = plplot(x,xmin,alpha); |
---|
25 | # |
---|
26 | # For more information, try 'type plplot' |
---|
27 | # |
---|
28 | # See also PLFIT, PLVAR, PLPVA |
---|
29 | |
---|
30 | # Version 1.0 (2008 February) |
---|
31 | # Ported to python by Joel Ornstein(2011 July) |
---|
32 | # (joel_ornstein@hmc.edu) |
---|
33 | |
---|
34 | # Copyright (C) 2008-2011 Aaron Clauset (Santa Fe Institute) |
---|
35 | # Distributed under GPL 2.0 |
---|
36 | # http://www.gnu.org/copyleft/gpl.html |
---|
37 | # PLFIT comes with ABSOLUTELY NO WARRANTY |
---|
38 | # |
---|
39 | # The 'zeta' helper function is modified from the open-source library 'mpmath' |
---|
40 | # mpmath: a Python library for arbitrary-precision floating-point arithmetic |
---|
41 | # http://code.google.com/p/mpmath/ |
---|
42 | # version 0.17 (February 2011) by Fredrik Johansson and others |
---|
43 | # |
---|
44 | # No Notes |
---|
45 | # |
---|
46 | |
---|
47 | def plplot(x,xmin,alpha): |
---|
48 | # select method (discrete or continuous) for fitting |
---|
49 | if reduce(lambda X,Y:X==True and floor(Y)==float(Y),x,True): f_dattype = 'INTS' |
---|
50 | elif reduce(lambda X,Y:X==True and (type(Y)==int or type(Y)==float or type(Y)==long),x,True): f_dattype = 'REAL' |
---|
51 | else: f_dattype = 'UNKN' |
---|
52 | |
---|
53 | if f_dattype=='INTS' and min(x) > 1000 and len(x)>100: |
---|
54 | f_dattype = 'REAL' |
---|
55 | plt.close() |
---|
56 | plt.ion() |
---|
57 | h=[[],[]] |
---|
58 | # estimate xmin and alpha, accordingly |
---|
59 | if f_dattype== 'REAL': |
---|
60 | n = len(x) |
---|
61 | c1 = sorted(x) |
---|
62 | c2 = map(lambda X:X/float(n),range(n,0,-1)) |
---|
63 | q = sorted(filter(lambda X:X>=xmin,x)) |
---|
64 | cf = map(lambda X:pow(float(X)/xmin,1.-alpha),q) |
---|
65 | cf = map(lambda X:X*float(c2[c1.index(q[0])]),cf) |
---|
66 | |
---|
67 | h[0]=plt.loglog(c1, c2, 'bo',markersize=8,markerfacecolor=[1,1,1],markeredgecolor=[0,0,1]) |
---|
68 | h[1]=plt.loglog(q, cf, 'k--',linewidth=2) |
---|
69 | |
---|
70 | xr1 = pow(10,floor(log(min(x),10))) |
---|
71 | xr2 = pow(10,ceil(log(min(x),10))) |
---|
72 | yr1 = pow(10,floor(log(1./n,10))) |
---|
73 | yr2 = 1 |
---|
74 | |
---|
75 | |
---|
76 | plt.axhspan(ymin=yr1,ymax=yr2,xmin=xr1,xmax=xr2) |
---|
77 | plt.ylabel('Pr(X >= x)',fontsize=16); |
---|
78 | plt.xlabel('x',fontsize=16) |
---|
79 | plt.draw() |
---|
80 | |
---|
81 | elif f_dattype== 'INTS': |
---|
82 | n = len(x) |
---|
83 | q = sorted(unique(x)) |
---|
84 | c=[] |
---|
85 | for Q in q: |
---|
86 | c.append(len(filter(lambda X: floor(X)==Q,x))/float(n)) |
---|
87 | c1 = q+[q[-1]+1] |
---|
88 | c2 = map(lambda Z: 1.-Z,reduce(lambda X,Y: X+[Y+X[-1]],c,[0])) |
---|
89 | c2 = filter(lambda X:float(X)>=pow(10,-10.),c2) |
---|
90 | c1 = c1[0:len(c2)] |
---|
91 | cf = map(lambda X:pow(X,-alpha)/(float(zeta(alpha)) - sum(map(lambda Y:pow(Y,-alpha),range(1,xmin)))),range(xmin,q[-1]+1)) |
---|
92 | cf1 = range(xmin,q[-1]+2) |
---|
93 | cf2 = map(lambda Z: 1.-Z,reduce(lambda X,Y: X+[Y+X[-1]],cf,[0])) |
---|
94 | cf2 = map(lambda X: X*float(c2[c1.index(xmin)]),cf2) |
---|
95 | |
---|
96 | h[0]=plt.loglog(c1, c2, 'bo',markersize=8,markerfacecolor=[1,1,1],markeredgecolor=[0,0,1]) |
---|
97 | h[1]=plt.loglog(cf1, cf2, 'k--',linewidth=2) |
---|
98 | |
---|
99 | xr1 = pow(10,floor(log(min(x),10))) |
---|
100 | xr2 = pow(10,ceil(log(min(x),10))) |
---|
101 | yr1 = pow(10,floor(log(1./n,10))) |
---|
102 | yr2 = 1 |
---|
103 | |
---|
104 | |
---|
105 | plt.axhspan(ymin=yr1,ymax=yr2,xmin=xr1,xmax=xr2) |
---|
106 | plt.ylabel('Pr(X >= x)',fontsize=16); |
---|
107 | plt.xlabel('x',fontsize=16) |
---|
108 | plt.draw() |
---|
109 | |
---|
110 | |
---|
111 | |
---|
112 | return h |
---|
113 | |
---|
114 | # helper functions (unique and zeta) |
---|
115 | |
---|
116 | |
---|
117 | def unique(seq): |
---|
118 | # not order preserving |
---|
119 | set = {} |
---|
120 | map(set.__setitem__, seq, []) |
---|
121 | return set.keys() |
---|
122 | |
---|
123 | def _polyval(coeffs, x): |
---|
124 | p = coeffs[0] |
---|
125 | for c in coeffs[1:]: |
---|
126 | p = c + x*p |
---|
127 | return p |
---|
128 | |
---|
129 | _zeta_int = [\ |
---|
130 | -0.5, |
---|
131 | 0.0, |
---|
132 | 1.6449340668482264365,1.2020569031595942854,1.0823232337111381915, |
---|
133 | 1.0369277551433699263,1.0173430619844491397,1.0083492773819228268, |
---|
134 | 1.0040773561979443394,1.0020083928260822144,1.0009945751278180853, |
---|
135 | 1.0004941886041194646,1.0002460865533080483,1.0001227133475784891, |
---|
136 | 1.0000612481350587048,1.0000305882363070205,1.0000152822594086519, |
---|
137 | 1.0000076371976378998,1.0000038172932649998,1.0000019082127165539, |
---|
138 | 1.0000009539620338728,1.0000004769329867878,1.0000002384505027277, |
---|
139 | 1.0000001192199259653,1.0000000596081890513,1.0000000298035035147, |
---|
140 | 1.0000000149015548284] |
---|
141 | |
---|
142 | _zeta_P = [-3.50000000087575873, -0.701274355654678147, |
---|
143 | -0.0672313458590012612, -0.00398731457954257841, |
---|
144 | -0.000160948723019303141, -4.67633010038383371e-6, |
---|
145 | -1.02078104417700585e-7, -1.68030037095896287e-9, |
---|
146 | -1.85231868742346722e-11][::-1] |
---|
147 | |
---|
148 | _zeta_Q = [1.00000000000000000, -0.936552848762465319, |
---|
149 | -0.0588835413263763741, -0.00441498861482948666, |
---|
150 | -0.000143416758067432622, -5.10691659585090782e-6, |
---|
151 | -9.58813053268913799e-8, -1.72963791443181972e-9, |
---|
152 | -1.83527919681474132e-11][::-1] |
---|
153 | |
---|
154 | _zeta_1 = [3.03768838606128127e-10, -1.21924525236601262e-8, |
---|
155 | 2.01201845887608893e-7, -1.53917240683468381e-6, |
---|
156 | -5.09890411005967954e-7, 0.000122464707271619326, |
---|
157 | -0.000905721539353130232, -0.00239315326074843037, |
---|
158 | 0.084239750013159168, 0.418938517907442414, 0.500000001921884009] |
---|
159 | |
---|
160 | _zeta_0 = [-3.46092485016748794e-10, -6.42610089468292485e-9, |
---|
161 | 1.76409071536679773e-7, -1.47141263991560698e-6, -6.38880222546167613e-7, |
---|
162 | 0.000122641099800668209, -0.000905894913516772796, -0.00239303348507992713, |
---|
163 | 0.0842396947501199816, 0.418938533204660256, 0.500000000000000052] |
---|
164 | |
---|
165 | def zeta(s): |
---|
166 | """ |
---|
167 | Riemann zeta function, real argument |
---|
168 | """ |
---|
169 | if not isinstance(s, (float, int)): |
---|
170 | try: |
---|
171 | s = float(s) |
---|
172 | except (ValueError, TypeError): |
---|
173 | try: |
---|
174 | s = complex(s) |
---|
175 | if not s.imag: |
---|
176 | return complex(zeta(s.real)) |
---|
177 | except (ValueError, TypeError): |
---|
178 | pass |
---|
179 | raise NotImplementedError |
---|
180 | if s == 1: |
---|
181 | raise ValueError("zeta(1) pole") |
---|
182 | if s >= 27: |
---|
183 | return 1.0 + 2.0**(-s) + 3.0**(-s) |
---|
184 | n = int(s) |
---|
185 | if n == s: |
---|
186 | if n >= 0: |
---|
187 | return _zeta_int[n] |
---|
188 | if not (n % 2): |
---|
189 | return 0.0 |
---|
190 | if s <= 0.0: |
---|
191 | return 0 |
---|
192 | if s <= 2.0: |
---|
193 | if s <= 1.0: |
---|
194 | return _polyval(_zeta_0,s)/(s-1) |
---|
195 | return _polyval(_zeta_1,s)/(s-1) |
---|
196 | z = _polyval(_zeta_P,s) / _polyval(_zeta_Q,s) |
---|
197 | return 1.0 + 2.0**(-s) + 3.0**(-s) + 4.0**(-s)*z |
---|
198 | |
---|
199 | |
---|
200 | |
---|
201 | |
---|