|
| 1 | +def compute_distribution(v): |
| 2 | + """ |
| 3 | + v: vector de valores enteros |
| 4 | + devuelve un diccionario con la probabilidad de cada valor |
| 5 | + computado como la frecuencia de ocurrencia |
| 6 | + """ |
| 7 | + d= defaultdict(int) |
| 8 | + for e in v: d[e]+=1 |
| 9 | + s= float(sum(d.values())) |
| 10 | + return dict((k, v/s) for k, v in d.items()) |
| 11 | + |
| 12 | +def entropy(y): |
| 13 | + """ |
| 14 | + Computa la entropia de un vector discreto |
| 15 | + """ |
| 16 | + # P(Y) |
| 17 | + Py= compute_distribution(y) |
| 18 | + res=0.0 |
| 19 | + for k, v in Py.items(): |
| 20 | + res+=v*log2(v) |
| 21 | + return -res |
| 22 | + |
| 23 | + def conditional_entropy(x, y): |
| 24 | + """ |
| 25 | + x: vector de numeros reales |
| 26 | + y: vector de numeros enteros |
| 27 | + devuelve H(Y|X) |
| 28 | + """ |
| 29 | + # discretizacion de X |
| 30 | + #print(int(x.size/10)) |
| 31 | + # https://stats.stackexchange.com/questions/179674/number-of-bins-when-computing-mutual-information#:~:text=3%20Answers&text=There%20is%20no%20best%20number,on%20histograms%20have%20been%20proposed. |
| 32 | + # Choosing number of bins |
| 33 | + #hx, bx= histogram(x, bins=int(x.size/10), density=True) |
| 34 | + hx, bx= histogram(x, bins=int(np.sqrt(x.size/5)),density=True) |
| 35 | + |
| 36 | + Py= compute_distribution(y) |
| 37 | + Px= compute_distribution(digitize(x,bx)) |
| 38 | + |
| 39 | + res= 0 |
| 40 | + for ey in set(y): |
| 41 | + # P(X | Y) |
| 42 | + x1= x[y==ey] |
| 43 | + condPxy= compute_distribution(digitize(x1,bx)) |
| 44 | + |
| 45 | + for k, v in condPxy.items(): |
| 46 | + res+= (v*Py[ey]*(log2(Px[k]) - log2(v*Py[ey]))) |
| 47 | + |
| 48 | +def mutual_information(x,y): |
| 49 | + return entropy(y) - conditional_entropy(x,y) |
| 50 | + |
| 51 | +#https://course.ccs.neu.edu/cs6140sp15/7_locality_cluster/Assignment-6/NMI.pdf |
| 52 | +def normalized_mutual_information(x,y): |
| 53 | + return (2* mutual_information(x,y))/(entropy(x)+entropy(y)) |
| 54 | + |
| 55 | +from copent import transent |
| 56 | +from pandas import read_csv |
| 57 | +import numpy as np |
| 58 | + |
| 59 | +url = "https://archive.ics.uci.edu/ml/machine-learning-databases/00381/PRSA_data_2010.1.1-2014.12.31.csv" |
| 60 | +prsa2010 = read_csv(url) |
| 61 | +# index: 5(PM2.5),6(Dew Point),7(Temperature),8(Pressure),10(Cumulative Wind Speed) |
| 62 | +data = prsa2010.iloc[2200:2700,[5,8]].values |
| 63 | + |
| 64 | +te = np.zeros(24) |
| 65 | +for lag in range(1,2): |
| 66 | + te[lag-1] = transent(data[:,0],data[:,1],1) |
| 67 | + print(data[:,0].shape) |
| 68 | + str_ = "TE from pressure to PM2.5 at %d hours lag : %f" %(lag,te[lag-1]) |
| 69 | + print(str_) |
| 70 | + |
| 71 | +# TE from y to x |
| 72 | +def transfer_entropy(x,y): |
| 73 | + return transent(x,y,40) |
| 74 | + |
| 75 | +def multivariate_mutual_information(xs1,xs2,xtar): |
| 76 | + # https://stackoverflow.com/questions/20332750/python-joint-distribution-of-n-variables |
| 77 | + numBins =int(np.sqrt(xs1.shape[0]/5)) # number of bins in each dimension |
| 78 | + #print(xtar) |
| 79 | + xs1 = xs1[np.isfinite(xs1)] |
| 80 | + xs2 = xs2[np.isfinite(xs1)] |
| 81 | + xtar = xtar[np.isfinite(xs1)] |
| 82 | + |
| 83 | + xs2 = xs2[np.isfinite(xs2)] |
| 84 | + xs2 = xs2[np.isfinite(xtar)] |
| 85 | + |
| 86 | + xtar = xtar[np.isfinite(xs2)] |
| 87 | + xtar = xtar[np.isfinite(xtar)] |
| 88 | + #print(xtar) |
| 89 | + data = np.stack((xs1, xs2, xtar)).T |
| 90 | + #data = np.random.randn(100000, 3) # generate 100000 3-d random data points |
| 91 | + jointProbs3, edges = np.histogramdd(data, bins=numBins) |
| 92 | + jointProbs3 /= jointProbs3.sum() |
| 93 | + jointProbs2, edges = np.histogramdd(data[:,:2], bins=numBins) |
| 94 | + jointProbs2 /= jointProbs2.sum() |
| 95 | + jointProbs1, edges = np.histogramdd(data[:,2:], bins=numBins) |
| 96 | + jointProbs1 /= jointProbs1.sum() |
| 97 | + jointProbs3_ = jointProbs3.copy() |
| 98 | + for i in range(jointProbs1.shape[0]): |
| 99 | + jointProbs3_[i,:,:] = jointProbs1[i]*jointProbs2[:,:] |
| 100 | + arr = jointProbs3*(np.log2(jointProbs3)-np.log2(jointProbs3_)) |
| 101 | + return np.mean(arr[np.isfinite(arr)]) |
| 102 | + |
| 103 | +# TCI for control |
| 104 | +# mrsos_control[0].shape |
| 105 | +# mrsos_std = np.zeros((mrsos_control[0].shape[1], mrsos_control[0].shape[2])) |
| 106 | +# for i_lat in range(mrsos_control[0].shape[1]): |
| 107 | +# for j_lon in range(mrsos_control) |
| 108 | +# https://stackoverflow.com/questions/58546999/calculate-correlation-in-xarray-with-missing-data |
| 109 | +def linear_trend(x, y): |
| 110 | + #print(x.shape) |
| 111 | +# if np.sum(np.isnan(x))>0: |
| 112 | +# pf = np.empty((x.shape[0])) |
| 113 | +# else: |
| 114 | +# try: |
| 115 | + idx = np.isfinite(x) & np.isfinite(y) |
| 116 | + #print(x.shape) |
| 117 | + pf = np.polyfit(x[idx], y[idx], 1) |
| 118 | +# except: |
| 119 | +# pf = np.empty((x.shape[0])) |
| 120 | + return xr.DataArray(pf[0]) |
| 121 | + |
| 122 | +def compute_tci(sm, lh): |
| 123 | + print(sm.shape, lh.shape) |
| 124 | + sm_std = sm.std(dim='time') |
| 125 | + slopes = np.zeros_like(sm_std.values) |
| 126 | + |
| 127 | + x = sm |
| 128 | + y = lh |
| 129 | + n = y.notnull().sum(dim='time') |
| 130 | + xmean = x.mean(axis=0) |
| 131 | + ymean = y.mean(axis=0) |
| 132 | + xstd = x.std(axis=0) |
| 133 | + ystd = y.std(axis=0) |
| 134 | + cov = np.sum((x - xmean)*(y - ymean), axis=0)/(n) |
| 135 | + slopes = cov/(xstd**2) |
| 136 | + intercept = ymean - xmean*slopes |
| 137 | + sm_std['slopes'] = (('lat', 'lon'), slopes) |
| 138 | + tci = sm_std.slopes*sm_std |
| 139 | + return tci |
| 140 | +#mrsos_control[0].std(dim='time').plot() |
| 141 | + |
| 142 | +def compute_aci(tas, hfss): |
| 143 | + sm = tas |
| 144 | + lh = hfss |
| 145 | + |
| 146 | + print(sm.shape, lh.shape) |
| 147 | + sm_std = sm.std(dim='time') |
| 148 | + slopes = np.zeros_like(sm_std.values) |
| 149 | + |
| 150 | + x = sm |
| 151 | + y = lh |
| 152 | + n = y.notnull().sum(dim='time') |
| 153 | + xmean = x.mean(axis=0) |
| 154 | + ymean = y.mean(axis=0) |
| 155 | + xstd = x.std(axis=0) |
| 156 | + ystd = y.std(axis=0) |
| 157 | + cov = np.sum((x - xmean)*(y - ymean), axis=0)/(n) |
| 158 | + slopes = cov/(xstd**2) |
| 159 | + intercept = ymean - xmean*slopes |
| 160 | + sm_std['slopes'] = (('lat', 'lon'), slopes) |
| 161 | + tci = sm_std.slopes*sm_std |
| 162 | + return tci |
| 163 | +#mrsos_control[0].std(dim='time').plot() |
| 164 | + |
| 165 | +def soilm_memory(ds_soilm): |
| 166 | + threshold = 1./np.exp(1.) |
| 167 | + soilm = ds_soilm.values |
| 168 | + smemory = np.zeros_like((ds_soilm.values[0,:,:])) |
| 169 | + ntim = 50 # ds_piClim_control_MPIESM_r1i1p1f1_mrso.mrso.values.shape[0] |
| 170 | + correlation_ = np.zeros((ntim, \ |
| 171 | + ds_soilm.shape[1], \ |
| 172 | + ds_soilm.shape[2])) |
| 173 | + for tt in range(2,ntim): |
| 174 | + soilm_lagged = soilm[tt:,:,:] |
| 175 | + times = ds_soilm.time.values[tt:] |
| 176 | + lats = ds_soilm.lat.values |
| 177 | + lons = ds_soilm.lon.values |
| 178 | + ds = xr.Dataset({ |
| 179 | + 'soilm': xr.DataArray( |
| 180 | + data = soilm[:-tt], # enter data here |
| 181 | + dims = ['time', 'lat', 'lon'], |
| 182 | + coords = {'time': times, 'lat':lats, 'lon':lons}, |
| 183 | + ), |
| 184 | + 'soilm_lagged': xr.DataArray( |
| 185 | + data = soilm_lagged, # enter data here |
| 186 | + dims = ['time', 'lat', 'lon'], |
| 187 | + coords = {'time': times, 'lat':lats, 'lon':lons}, |
| 188 | + |
| 189 | + ) |
| 190 | + }, |
| 191 | + ) |
| 192 | + #print('lag = ', tt) |
| 193 | + x = ds['soilm'] |
| 194 | + y = ds['soilm_lagged'] |
| 195 | + n = y.notnull().sum(dim='time') |
| 196 | + xmean = x.mean(axis=0) |
| 197 | + ymean = y.mean(axis=0) |
| 198 | + xstd = x.std(axis=0) |
| 199 | + ystd = y.std(axis=0) |
| 200 | + |
| 201 | + #4. Compute covariance along time axis |
| 202 | + cov = np.sum((x - xmean)*(y - ymean), axis=0)/(n) |
| 203 | + |
| 204 | + #5. Compute correlation along time axis |
| 205 | + cor = cov/(xstd*ystd) |
| 206 | + correlation_[tt-2,:,:] = cor.values |
| 207 | + for i_lat in range(correlation_.shape[1]): |
| 208 | + for j_lon in range(correlation_.shape[2]): |
| 209 | + idx = np.where(correlation_[:,i_lat, j_lon] < 1/np.exp(1.))[0] |
| 210 | + #print(idx) |
| 211 | + #print(len(idx)) |
| 212 | + #print(np.sum(np.isnan(soilm[:,i_lat,j_lon]))) |
| 213 | + if len(idx)==0: |
| 214 | + smemory[i_lat, j_lon] = np.nan |
| 215 | + elif len(idx)==2: |
| 216 | + smemory[i_lat, j_lon] = np.nan |
| 217 | + else: |
| 218 | + print(idx) |
| 219 | + smemory[i_lat, j_lon] = idx[0]+1 |
| 220 | + ds = xr.Dataset({ |
| 221 | + 'smemory': xr.DataArray( |
| 222 | + data = smemory, # enter data here |
| 223 | + dims = [ 'lat', 'lon'], |
| 224 | + coords = {'lat':lats, 'lon':lons}, |
| 225 | + ) |
| 226 | + }, |
| 227 | + ) |
| 228 | + |
| 229 | + return ds |
| 230 | + |
| 231 | + def notaro_feedback_parameter(x,y): |
| 232 | + tau = 20 # daily data |
| 233 | + stptau = x.shift(time=tau) |
| 234 | + st = x |
| 235 | + atptau = y.shift(time=tau) |
| 236 | + n = atptau.notnull().sum(dim='time') |
| 237 | + xmean = st.mean(axis=0, skipna =True) |
| 238 | + ymean = atptau.mean(axis=0, skipna =True) |
| 239 | + xstd = st.std(axis=0, skipna =True) |
| 240 | + ystd = atptau.std(axis=0, skipna =True) |
| 241 | + cov_num = np.sum((st - xmean)*(atptau - ymean), axis=0)/(n) |
| 242 | + |
| 243 | + n = stptau.notnull().sum(dim='time') |
| 244 | + xmean = st.mean(axis=0, skipna =True) |
| 245 | + ymean = stptau.mean(axis=0, skipna =True) |
| 246 | + xstd = st.std(axis=0, skipna =True) |
| 247 | + ystd = stptau.std(axis=0, skipna =True) |
| 248 | + cov_den = np.sum((st - xmean)*(stptau - ymean), axis=0)/(n) |
| 249 | + |
| 250 | + nfp = cov_num/cov_den |
| 251 | + |
| 252 | + return nfp |
| 253 | + |
| 254 | + def zengs_gamma(x,y): |
| 255 | + n = y.notnull().sum(dim='time') |
| 256 | + xmean = x.mean(axis=0) |
| 257 | + ymean = y.mean(axis=0) |
| 258 | + xstd = x.std(axis=0) |
| 259 | + ystd = y.std(axis=0) |
| 260 | + |
| 261 | + #4. Compute covariance along time axis |
| 262 | + cov = np.sum((x - xmean)*(y - ymean), axis=0)/(n) |
| 263 | + |
| 264 | + #5. Compute correlation along time axis |
| 265 | + cor = cov/(xstd*ystd) |
| 266 | + |
| 267 | + cor = cor * (xstd/ystd) |
| 268 | + return cor |
| 269 | + |
| 270 | + |
0 commit comments