SAM-SPOT 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python2
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Sat Mar 11 21:58:32 2017
5
+
6
+ @author: felix
7
+ """
8
+
@@ -0,0 +1,411 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Tue Oct 17 18:30:30 2023
4
+
5
+ @author: S205272
6
+ """
7
+ import numpy as np
8
+
9
+ def scale_normalize_curvature_features(all_feats, feature_names):
10
+ r""" Curvature features are not invariant to size of the object. It is of units length^-1. In order to allow like-wise comparison across different objects, we multiply features by the equivalent diameter of the object.
11
+
12
+ Parameters
13
+ ----------
14
+ all_feats : (n_objects, n_feats) np.array
15
+ numpy array of all features for all object instances to be analyzed.
16
+ feature_names : (n_feats,) np.array
17
+ numpy array of the names of each computed feature
18
+
19
+ Returns
20
+ -------
21
+ all_feats_corrected : (n_objects, n_feats) np.array
22
+ numpy array of all features with size-corrected curvature features
23
+ feature_names : (n_feats,) np.array
24
+ numpy array of the names of each computed feature. It is identical to the input and is output for consistent api
25
+
26
+ """
27
+
28
+ all_feats_corrected = all_feats.copy()
29
+
30
+ # correction for curvature features.
31
+ for feat_ii, feature_name in enumerate(feature_names):
32
+ if 'curvature' in feature_name:
33
+ all_feats_corrected[:,feat_ii] = all_feats[:,feat_ii] * all_feats[:,feature_names == 'equivalent_diameter'].ravel()
34
+
35
+ return all_feats_corrected, feature_names
36
+
37
+
38
+ # remove entirely zero-valued features
39
+ def remove_zero_features(all_feats, feature_names, return_index=False):
40
+ r""" remove any features that are zero-valued across all object instances as well as any that have zero standard deviation across all object instances as they are uninformative
41
+
42
+ Parameters
43
+ ----------
44
+ all_feats : (n_objects, n_feats) np.array
45
+ numpy array of all features for all object instances to be analyzed.
46
+ feature_names : (n_feats,) np.array
47
+ numpy array of the names of each computed feature
48
+
49
+ Returns
50
+ -------
51
+ all_feats_corrected : (n_objects, n_feats) np.array
52
+ numpy array of all features with zero-valued features removed
53
+ feature_names_corrected : (n_feats,) np.array
54
+ numpy array of the names of each retained feature
55
+
56
+ """
57
+ import numpy as np
58
+
59
+ zero_feats = np.nanmax(all_feats, axis=0) == 0
60
+
61
+ if return_index:
62
+ select_index = np.arange(len(zero_feats))
63
+ select_index = select_index[~zero_feats].copy()
64
+
65
+ feature_names_corrected = feature_names[~zero_feats].copy()
66
+ all_feats_corrected = all_feats[:, ~zero_feats].copy()
67
+
68
+ std_feats = np.std(all_feats_corrected, axis=0)
69
+ zero_std_feats = std_feats == 0
70
+
71
+ if return_index:
72
+ select_index = select_index[~zero_std_feats].copy()
73
+
74
+ feature_names_corrected = feature_names_corrected[~zero_std_feats]
75
+ all_feats_corrected = all_feats_corrected[:, ~zero_std_feats].copy() # so we have 400 feats.
76
+
77
+ if return_index:
78
+ return all_feats_corrected, feature_names_corrected, select_index
79
+ else:
80
+ return all_feats_corrected, feature_names_corrected
81
+
82
+
83
+ # remove entirely zero-valued features
84
+ def remove_nan_variance_features(all_feats, feature_names, return_index=False):
85
+ r""" remove any features that have zero variation across all object instances as well as any that have zero standard deviation across all object instances as they are uninformative
86
+
87
+ Parameters
88
+ ----------
89
+ all_feats : (n_objects, n_feats) np.array
90
+ numpy array of all features for all object instances to be analyzed.
91
+ feature_names : (n_feats,) np.array
92
+ numpy array of the names of each computed feature
93
+
94
+ Returns
95
+ -------
96
+ all_feats_corrected : (n_objects, n_feats) np.array
97
+ numpy array of all features with zero-valued features removed
98
+ feature_names_corrected : (n_feats,) np.array
99
+ numpy array of the names of each retained feature
100
+
101
+ """
102
+ import numpy as np
103
+
104
+ zero_feats = np.isnan(np.std(all_feats, axis=0))
105
+
106
+ if return_index:
107
+ select_index = np.arange(len(zero_feats))
108
+ select_index = select_index[~zero_feats].copy()
109
+
110
+ feature_names_corrected = feature_names[~zero_feats].copy()
111
+ all_feats_corrected = all_feats[:, ~zero_feats].copy()
112
+
113
+ if return_index:
114
+ return all_feats_corrected, feature_names_corrected, select_index
115
+ else:
116
+ return all_feats_corrected, feature_names_corrected
117
+
118
+
119
+ def remove_high_variance_features(all_feats, feature_names, variance_threshold_sigma=3, return_index=False):
120
+ r""" remove features that are highly variable and likely to represent outliers
121
+
122
+ Parameters
123
+ ----------
124
+ all_feats : (n_objects, n_feats) np.array
125
+ numpy array of all features for all object instances to be analyzed.
126
+ feature_names : (n_feats,) np.array
127
+ numpy array of the names of each computed feature
128
+
129
+ Returns
130
+ -------
131
+ all_feats_corrected : (n_objects, n_feats) np.array
132
+ numpy array of all features with high variance features removed
133
+ feature_names_corrected : (n_feats,) np.array
134
+ numpy array of the names of each retained feature.
135
+
136
+ """
137
+ import numpy as np
138
+
139
+ high_var_feats_thresh = np.mean(np.std(all_feats, axis=0)) + variance_threshold_sigma*np.std(np.std(all_feats, axis=0))
140
+ keep_feats = np.std(all_feats, axis=0)<=high_var_feats_thresh
141
+
142
+ if return_index:
143
+ select_index = np.arange(len(keep_feats))
144
+ select_index = select_index[keep_feats].copy()
145
+ # high_var_feats_thresh = np.mean(np.std(all_feats, axis=0)) + 2*np.std(np.std(all_feats, axis=0))
146
+ # feature_names = feature_names[np.std(all_feats, axis=0)<=high_var_feats_thresh]
147
+
148
+ feature_names_corrected = feature_names[keep_feats].copy()
149
+ all_feats_corrected = all_feats[:, keep_feats].copy()
150
+
151
+ if return_index:
152
+ return all_feats_corrected, feature_names_corrected, select_index
153
+ else:
154
+ return all_feats_corrected, feature_names_corrected
155
+
156
+
157
+ def select_time_varying_features(all_feats, feature_names, all_time, ridge_alpha=1., norm_time=True, cutoff_method='mean', offset_threshold=None):
158
+
159
+ r""" Selects features that are most strongly correlated with time using linear ridge regression. Features are kept if the absolute value of their regression coefficient is greater than the mean across all features
160
+
161
+ Parameters
162
+ ----------
163
+ all_feats : (n_objects, n_feats) np.array
164
+ numpy array of all features for all object instances to be analyzed.
165
+ feature_names : (n_feats,) np.array
166
+ numpy array of the names of each computed feature
167
+ all_time : (n_objects, n_feats) np.array
168
+ numpy array of the timepoint each object instance was extracted from.
169
+ ridge_alpha : non-negative float
170
+ Constant that multiplies the L2 term, controlling regularization strength. alpha must be a non-negative float i.e. in [0, inf).
171
+ norm_true : bool
172
+ if True, assumes time is given as frame number and performs (all_time-1.)/(np.max(all_time-1.)) to rescale to 0-1 float
173
+ cutoff_method : str
174
+ one of 'mean' or 'median' for computing the coeff cutoff threshold
175
+ offset_threshold : float
176
+ optional modification of the inferred cutoff: cutoff_new = cutoff + offset_threshold * np.std( coeffs )
177
+
178
+ Returns
179
+ -------
180
+ all_feats_corrected : (n_objects, n_feats) np.array
181
+ numpy array of all features with high variance features removed
182
+ feature_names_corrected : (n_feats,) np.array
183
+ numpy array of the names of each retained feature.
184
+ coeffs : (n_feats,) np.array
185
+ fitted Ridge regression coefficients. The larger the absolute magnitude, the more the feature covaries with time.
186
+ """
187
+
188
+ # what about straightforward regression of features with time?
189
+ from sklearn import linear_model
190
+ import numpy as np
191
+
192
+ reg = linear_model.Ridge(alpha=1.)
193
+
194
+ if norm_time:
195
+ all_time_score = all_time-1.
196
+ all_time_score = all_time_score/all_time_score.max() # to normalize.
197
+ else:
198
+ all_time_score = all_time.copy()
199
+
200
+ reg.fit(all_feats, all_time_score)
201
+ coeffs = reg.coef_.copy()
202
+
203
+ if cutoff_method=='mean':
204
+ coef_thresh = np.mean(np.abs(coeffs)) # thresh by the mean
205
+ elif cutoff_method == 'median':
206
+ coef_thresh = np.median(np.abs(coeffs)) # thresh by the mean
207
+ else:
208
+ coef_thresh = np.mean(np.abs(coeffs)) # thresh by the mean
209
+
210
+ if offset_threshold is not None:
211
+ coef_thresh = coef_thresh + offset_threshold*np.std(np.abs(coeffs))
212
+
213
+ keep_feats = np.abs(reg.coef_)>=coef_thresh # create a binary indicator
214
+
215
+ feature_names_corrected = feature_names[keep_feats].copy()
216
+ all_feats_corrected = all_feats[:, keep_feats].copy()
217
+
218
+ return all_feats_corrected, feature_names_corrected, coeffs
219
+
220
+
221
+ def kernel_dim_reduction_ECC_features(all_feats, feature_names, n_dim=100, gamma=None, random_state=1, return_index=False):
222
+ r""" finds Euler Characteristic Curve features and using Nystroem with RBF kernel to perform dimensional reduction to the specified dimension size.
223
+
224
+ Parameters
225
+ ----------
226
+ all_feats : (n_objects, n_feats) np.array
227
+ numpy array of all features for all object instances to be analyzed.
228
+ feature_names : (n_feats,) np.array
229
+ numpy array of the names of each computed feature
230
+
231
+ Returns
232
+ -------
233
+ all_feats_corrected : (n_objects, n_feats) np.array
234
+ numpy array of all features with transformed kernel ECC features
235
+ feature_names_corrected : (n_feats,) np.array
236
+ numpy array of the names of each retained feature.
237
+ ECT_rbf_feature_tformer : Scikit-learn Nystroem transformer object
238
+ the fitted sklearn.kernel_approximation.Nystroem object
239
+
240
+ """
241
+ from sklearn.kernel_approximation import Nystroem
242
+ import numpy as np
243
+
244
+ # drop all ECC/ECT feats
245
+ ECT_feats_index = np.arange(all_feats.shape[1])[np.hstack(['ECT_' in name for name in feature_names])]
246
+ non_ECT_feats_index = np.setdiff1d(np.arange(all_feats.shape[1]), ECT_feats_index)
247
+
248
+
249
+ # set up the transformer
250
+ ECT_rbf_feature_tformer = Nystroem(n_components=n_dim,
251
+ gamma=gamma,
252
+ random_state=random_state) # how many features? -> say 100 for now anyway.
253
+ ECT_rbf_feats = ECT_rbf_feature_tformer.fit_transform(all_feats[:,ECT_feats_index])
254
+
255
+ # now modify
256
+ all_feats_corrected = all_feats[:,non_ECT_feats_index].copy() # keep as before.
257
+ feature_names_corrected = feature_names[non_ECT_feats_index].copy()
258
+
259
+ # add in the transformed kernel features.
260
+ all_feats_corrected = np.hstack([all_feats_corrected,
261
+ ECT_rbf_feats])
262
+ feature_names_corrected = np.hstack([feature_names_corrected,
263
+ ['ECT_rbf_%d'%(dd+1) for dd in np.arange(ECT_rbf_feats.shape[1])]])
264
+
265
+ if return_index:
266
+ return all_feats_corrected, feature_names_corrected, ECT_rbf_feature_tformer, (non_ECT_feats_index, ECT_feats_index)
267
+ else:
268
+ return all_feats_corrected, feature_names_corrected, ECT_rbf_feature_tformer
269
+
270
+
271
+ def kernel_dim_reduction_ECC_features_with_transform(all_feats, indices, ECT_rbf_feature_tformer):
272
+ r""" finds Euler Characteristic Curve features and using Nystroem with RBF kernel to perform dimensional reduction to the specified dimension size.
273
+
274
+ Parameters
275
+ ----------
276
+ all_feats : (n_objects, n_feats) np.array
277
+ numpy array of all features for all object instances to be analyzed.
278
+ indices : ((M,), (N,)) np.array
279
+ non ECC features index, ECC features index
280
+ ECT_rbf_feature_tformer : Scikit-learn Nystroem transformer object
281
+ the fitted sklearn.kernel_approximation.Nystroem object
282
+
283
+ Returns
284
+ -------
285
+ all_feats_corrected : (n_objects, n_feats) np.array
286
+ numpy array of all features with transformed kernel ECC features
287
+
288
+ """
289
+ import numpy as np
290
+
291
+ non_ECT_feats_index, ECT_feats_index = indices
292
+
293
+ ECT_rbf_feats = ECT_rbf_feature_tformer.transform(all_feats[:,ECT_feats_index])
294
+
295
+ # now modify
296
+ all_feats_corrected = all_feats[:,non_ECT_feats_index].copy() # keep as before.
297
+
298
+ # add in the transformed kernel features.
299
+ all_feats_corrected = np.hstack([all_feats_corrected,
300
+ ECT_rbf_feats])
301
+
302
+ return all_feats_corrected
303
+
304
+
305
+
306
+ # individual feature normalization.
307
+ def power_transform_and_scale_features(all_feats, feature_names, all_conditions):
308
+ r""" Applies standard scaling (zscore) followed by power transform using Yeo-Johnson to normalize, whiten features and make more Gaussian-like for each unique condition to control
309
+
310
+ Parameters
311
+ ----------
312
+ all_feats : (n_objects, n_feats) np.array
313
+ numpy array of all features for all object instances to be analyzed.
314
+ feature_names : (n_feats,) np.array
315
+ numpy array of the names of each computed feature
316
+ all_conditions : integer or categorical np.array
317
+ each unique integer corresponds to a unique condition. Within each condition we fit a different power transformer and standard scale transformer
318
+
319
+ Returns
320
+ -------
321
+ all_feats_corrected : (n_objects, n_feats) np.array
322
+ numpy array of all features with transformed kernel ECC features
323
+ feature_names_corrected : (n_feats,) np.array
324
+ numpy array of the names of each retained feature.
325
+ pow_tformer_dict : dict
326
+ * 'all_obj_trajectories': list
327
+ This is a list of all the reconstructed trajectories. Each trajectory is given as a list of the input indices that make it up.
328
+ * 'all_obj_trajectories_times': list
329
+ This is a list of all the reconstructed trajectories. Each trajectory is a list of the frame number that the object instances occurred at
330
+ std_tformer_dict : dict
331
+ * str(condition) : sklearn.preprocessing StandardScaler object
332
+ Fitted StandardScaler object for the given unique condition
333
+ * 'all_obj_trajectories_times': list
334
+ This is a list of all the reconstructed trajectories. Each trajectory is a list of the frame number that the object instances occurred at
335
+ """
336
+ # =============================================================================
337
+ # Now we do individual feature normalisation -> modify in place.
338
+ # =============================================================================
339
+ import numpy as np
340
+ from sklearn.preprocessing import PowerTransformer, StandardScaler
341
+
342
+ all_feats_corrected = np.zeros(all_feats.shape)
343
+ feature_names_corrected = feature_names.copy()
344
+
345
+ pow_tformer_dict = {}
346
+ std_tformer_dict = {}
347
+
348
+ # normalizing over each condition
349
+ for uniq_condition in np.unique(all_conditions):
350
+
351
+ select = all_conditions == uniq_condition
352
+
353
+ pow_tformer = StandardScaler()
354
+ std_tformer = PowerTransformer()
355
+
356
+ feats_norm = pow_tformer.fit_transform(std_tformer.fit_transform(all_feats[select]))
357
+
358
+ pow_tformer_dict[str(uniq_condition)] = pow_tformer
359
+ std_tformer_dict[str(uniq_condition)] = std_tformer
360
+ pow_tformer_dict[str(uniq_condition)+'_data_select'] = select
361
+ std_tformer_dict[str(uniq_condition)+'_data_select'] = select
362
+
363
+ all_feats_corrected[select] = feats_norm.copy()
364
+
365
+ return all_feats_corrected, feature_names_corrected, pow_tformer_dict, std_tformer_dict
366
+
367
+
368
+ def preprocess_feats(X, std_tformer, pow_tformer):
369
+ r""" Applies already fitted scikit-learn standard scaler and powertransformer objects to the input matrix. The power transform is applied first then standard scale.
370
+
371
+ Parameters
372
+ ----------
373
+ X : (n_objects, n_feats) np.array
374
+ numpy array of all features for all object instances to be transformed
375
+ std_tformer : sklearn.preprocessing.StandardScaler object
376
+ pow_tformer : sklearn.preprocessing.power_transform object
377
+
378
+ Returns
379
+ -------
380
+ X_tfm : (n_objects, n_feats) np.array
381
+ numpy array of all features with transformed features
382
+ """
383
+ # apply learnt transformations to input features X.
384
+ X_tfm = std_tformer.transform(pow_tformer.transform(X))
385
+
386
+ return X_tfm
387
+
388
+
389
+ # def map_intensity_interp2(query_pts, grid_shape, I_ref, method='spline', cast_uint8=False, s=0):
390
+
391
+ # import numpy as np
392
+ # from scipy.interpolate import RectBivariateSpline, RegularGridInterpolator
393
+
394
+ # if method == 'spline':
395
+ # spl = RectBivariateSpline(np.arange(grid_shape[0]),
396
+ # np.arange(grid_shape[1]),
397
+ # I_ref,
398
+ # s=s)
399
+ # I_query = spl.ev(query_pts[...,0],
400
+ # query_pts[...,1])
401
+ # else:
402
+ # spl = RegularGridInterpolator((np.arange(grid_shape[0]),
403
+ # np.arange(grid_shape[1])),
404
+ # I_ref, method=method, bounds_error=False, fill_value=0)
405
+ # I_query = spl((query_pts[...,0],
406
+ # query_pts[...,1]))
407
+
408
+ # if cast_uint8:
409
+ # I_query = np.uint8(I_query)
410
+
411
+ # return I_query