[943] | 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 | |
---|