scmkl.calculate_z
1import numpy as np 2import scipy 3import anndata as ad 4 5from scmkl.tfidf_normalize import tfidf_train_test 6from scmkl.estimate_sigma import est_group_sigma, get_batches 7from scmkl.data_processing import process_data, get_group_mat, sample_cells 8from scmkl.projections import gaussian_trans, laplacian_trans, cauchy_trans 9 10 11def check_for_nan(adata: ad.AnnData): 12 """ 13 Ensures only valid values are in training and test matrices. 14 15 Parameters 16 ---------- 17 adata : ad.AnnData 18 Object with `'Z_train'` and `'Z_test'` keys in `.uns` 19 attribute. 20 21 Returns 22 ------- 23 None 24 """ 25 n_nans = np.sum(np.isnan(adata.uns['Z_train'])) 26 n_nans += np.sum(np.isnan(adata.uns['Z_test'])) 27 28 if n_nans: 29 raise ValueError( 30 "Some values in Z matrix are type `np.nan`. This is likely " 31 "due to a small kernel width or invalid values in input Z matrix." 32 ) 33 34 return None 35 36 37def check_for_inf(adata: ad.AnnData): 38 """ 39 Ensures only valid values are in training and test matrices. 40 41 Parameters 42 ---------- 43 adata : ad.AnnData 44 Object with `'Z_train'` and `'Z_test'` keys in `.uns` 45 attribute. 46 47 Returns 48 ------- 49 None 50 """ 51 n_infs = np.sum(np.isinf(adata.uns['Z_train'])) 52 n_infs += np.sum(np.isinf(adata.uns['Z_test'])) 53 54 if n_infs: 55 raise ValueError( 56 "Some values in Z matrix are type `np.inf`. This is likely " 57 "due to input matrix containing negative values." 58 ) 59 60 return None 61 62 63def get_z_indices(m, D): 64 """ 65 Takes the number associated with the group as `m` and returns the 66 indices for cos and sin functions to be applied. 67 68 Parameters 69 ---------- 70 m : int 71 The chronological number of the group being processed. 72 73 D : int 74 The number of dimensions per group. 75 76 Returns 77 ------- 78 cos_idx, sin_idx : np.ndarray, np.ndarray 79 The indices for cos and sin projections in overall Z matrix. 80 """ 81 x_idx = np.arange(m*2*D ,(m + 1)*2*D) 82 cos_idx = x_idx[:len(x_idx)//2] 83 sin_idx = x_idx[len(x_idx)//2:] 84 85 return cos_idx, sin_idx 86 87 88def calc_groupz(X_train, X_test, adata, D, sigma, proj_func, dtype): 89 """ 90 Calculates the Z matrix for grouping. 91 92 Parameters 93 ---------- 94 X_train : np.ndarray 95 The filtered data matrix to calculate train Z mat for. 96 97 X_test : np.ndarray 98 The filtered data matrix to calculate test Z mat for. 99 100 adata : anndata.AnnData 101 AnnData object containing `seed_obj` in `.uns` attribute. 102 103 D : int 104 Number of dimensions per grouping. 105 106 sigma : float 107 Kernel width for grouping. 108 109 proj_func : function 110 The projection direction function to be applied to data. 111 112 Returns 113 ------- 114 train_projections, test_projections : np.ndarray, np.ndarray 115 Training and testing Z matrices for group. 116 """ 117 if scipy.sparse.issparse(X_train): 118 X_train = X_train.toarray().astype(np.float16) 119 X_test = X_test.toarray().astype(np.float16) 120 121 W = proj_func(X_train, sigma, adata.uns['seed_obj'], D) 122 123 train_projection = np.matmul(X_train, W, dtype=dtype) 124 test_projection = np.matmul(X_test, W, dtype=dtype) 125 126 if np.isnan(train_projection).any() or np.isnan(test_projection).any(): 127 train_projection = np.matmul(X_train, W, dtype=np.float64) 128 test_projection = np.matmul(X_test, W, dtype=np.float64) 129 130 return train_projection, test_projection 131 132 133def calculate_z(adata, n_features=5000, batches=10, 134 batch_size=100) -> ad.AnnData: 135 """ 136 Function to calculate Z matrices for all groups in both training 137 and testing data. 138 139 Parameters 140 ---------- 141 adata : ad.AnnData 142 created by `scmkl.create_adata()` with `adata.uns.keys()`: 143 `'train_indices'`, and `'test_indices'`. 144 145 n_features : int 146 Number of random feature to use when calculating Z; used for 147 scalability. 148 149 batches : int 150 The number of batches to use for the distance calculation. 151 This will average the result of `batches` distance calculations 152 of `batch_size` randomly sampled cells. More batches will converge 153 to population distance values at the cost of scalability. 154 155 batch_size : int 156 The number of cells to include per batch for distance 157 calculations. Higher batch size will converge to population 158 distance values at the cost of scalability. 159 If `batches*batch_size > num_training_cells`, 160 `batch_size` will be reduced to 161 `int(num_training_cells / batches)`. 162 163 Returns 164 ------- 165 adata : ad.AnnData 166 `adata` with Z matrices accessible with `adata.uns['Z_train']` 167 and `adata.uns['Z_test']`. 168 169 Examples 170 -------- 171 >>> adata = scmkl.estimate_sigma(adata) 172 >>> adata = scmkl.calculate_z(adata) 173 >>> adata.uns.keys() 174 dict_keys(['Z_train', 'Z_test', 'sigmas', 'train_indices', 175 'test_indices']) 176 """ 177 # Number of groupings taking from group_dict 178 n_pathway = len(adata.uns['group_dict'].keys()) 179 D = adata.uns['D'] 180 181 sq_i_d = np.sqrt(1/D) 182 183 # Capturing training and testing sizes 184 train_len = len(adata.uns['train_indices']) 185 test_len = len(adata.uns['test_indices']) 186 187 if batch_size * batches > train_len: 188 old_batch_size = batch_size 189 batch_size = int(train_len/batches) 190 print("Specified batch size required too many cells for " 191 "independent batches. Reduced batch size from " 192 f"{old_batch_size} to {batch_size}") 193 194 if 'sigma' not in adata.uns.keys(): 195 n_samples = np.min((2000, train_len)) 196 sample_range = np.arange(n_samples) 197 batch_idx = get_batches(sample_range, adata.uns['seed_obj'], 198 batches=batches, batch_size=batch_size) 199 sigma_indices = sample_cells(adata.uns['train_indices'], n_samples, adata.uns['seed_obj']) 200 201 # Create Arrays to store concatenated group Zs 202 # Each group of features will have a corresponding entry in each array 203 n_cols = 2*adata.uns['D']*n_pathway 204 Z_train = np.zeros((train_len, n_cols), dtype=np.float16) 205 Z_test = np.zeros((test_len, n_cols), dtype=np.float16) 206 207 208 # Setting kernel function 209 match adata.uns['kernel_type'].lower(): 210 case 'gaussian': 211 proj_func = gaussian_trans 212 case 'laplacian': 213 proj_func = laplacian_trans 214 case 'cauchy': 215 proj_func = cauchy_trans 216 217 218 # Loop over each of the groups and creating Z for each 219 z_dtype = np.float16 220 sigma_list = list() 221 for m, group_features in enumerate(adata.uns['group_dict'].values()): 222 223 n_group_features = len(group_features) 224 225 X_train, X_test = get_group_mat(adata, n_features, group_features, 226 n_group_features, process_test=True) 227 228 if adata.uns['tfidf']: 229 X_train, X_test = tfidf_train_test(X_train, X_test) 230 231 # Data filtering, and transformation according to given data_type 232 # Will remove low variance (< 1e5) features regardless of data_type 233 # If scale/transform data depending on .uns values 234 X_train, X_test = process_data(X_train=X_train, X_test=X_test, 235 scale_data=adata.uns['scale_data'], 236 transform_data=adata.uns['transform_data'], 237 return_dense=True, 238 add_ones=adata.uns['add_ones']) 239 240 # Getting sigma 241 if 'sigma' in adata.uns.keys(): 242 sigma = adata.uns['sigma'][m] 243 else: 244 sigma = est_group_sigma(adata, X_train, n_group_features, 245 n_features, batch_idx=batch_idx) 246 sigma_list.append(sigma) 247 248 assert sigma > 0, "Sigma must be more than 0" 249 train_projection, test_projection = calc_groupz(X_train, X_test, 250 adata, D, sigma, 251 proj_func, z_dtype) 252 253 if train_projection.dtype != z_dtype: 254 print("Converting Z dtype from np.float16 to np.float64", 255 flush=True) 256 z_dtype = train_projection.dtype 257 Z_train = Z_train.astype(z_dtype) 258 Z_test = Z_test.astype(z_dtype) 259 260 # Store group Z in whole-Z object 261 # Preserves order to be able to extract meaningful groups 262 cos_idx, sin_idx = get_z_indices(m, D) 263 264 Z_train[0:, cos_idx] = np.cos(train_projection, dtype=z_dtype) 265 Z_train[0:, sin_idx] = np.sin(train_projection, dtype=z_dtype) 266 267 Z_test[0:, cos_idx] = np.cos(test_projection, dtype=z_dtype) 268 Z_test[0:, sin_idx] = np.sin(test_projection, dtype=z_dtype) 269 270 adata.uns['Z_train'] = Z_train*sq_i_d 271 adata.uns['Z_test'] = Z_test*sq_i_d 272 273 if 'sigma' not in adata.uns.keys(): 274 adata.uns['sigma'] = np.array(sigma_list) 275 276 check_for_nan(adata) 277 check_for_inf(adata) 278 279 return adata
def
check_for_nan(adata: anndata._core.anndata.AnnData):
12def check_for_nan(adata: ad.AnnData): 13 """ 14 Ensures only valid values are in training and test matrices. 15 16 Parameters 17 ---------- 18 adata : ad.AnnData 19 Object with `'Z_train'` and `'Z_test'` keys in `.uns` 20 attribute. 21 22 Returns 23 ------- 24 None 25 """ 26 n_nans = np.sum(np.isnan(adata.uns['Z_train'])) 27 n_nans += np.sum(np.isnan(adata.uns['Z_test'])) 28 29 if n_nans: 30 raise ValueError( 31 "Some values in Z matrix are type `np.nan`. This is likely " 32 "due to a small kernel width or invalid values in input Z matrix." 33 ) 34 35 return None
Ensures only valid values are in training and test matrices.
Parameters
- adata (ad.AnnData):
Object with
'Z_train'and'Z_test'keys in.unsattribute.
Returns
- None
def
check_for_inf(adata: anndata._core.anndata.AnnData):
38def check_for_inf(adata: ad.AnnData): 39 """ 40 Ensures only valid values are in training and test matrices. 41 42 Parameters 43 ---------- 44 adata : ad.AnnData 45 Object with `'Z_train'` and `'Z_test'` keys in `.uns` 46 attribute. 47 48 Returns 49 ------- 50 None 51 """ 52 n_infs = np.sum(np.isinf(adata.uns['Z_train'])) 53 n_infs += np.sum(np.isinf(adata.uns['Z_test'])) 54 55 if n_infs: 56 raise ValueError( 57 "Some values in Z matrix are type `np.inf`. This is likely " 58 "due to input matrix containing negative values." 59 ) 60 61 return None
Ensures only valid values are in training and test matrices.
Parameters
- adata (ad.AnnData):
Object with
'Z_train'and'Z_test'keys in.unsattribute.
Returns
- None
def
get_z_indices(m, D):
64def get_z_indices(m, D): 65 """ 66 Takes the number associated with the group as `m` and returns the 67 indices for cos and sin functions to be applied. 68 69 Parameters 70 ---------- 71 m : int 72 The chronological number of the group being processed. 73 74 D : int 75 The number of dimensions per group. 76 77 Returns 78 ------- 79 cos_idx, sin_idx : np.ndarray, np.ndarray 80 The indices for cos and sin projections in overall Z matrix. 81 """ 82 x_idx = np.arange(m*2*D ,(m + 1)*2*D) 83 cos_idx = x_idx[:len(x_idx)//2] 84 sin_idx = x_idx[len(x_idx)//2:] 85 86 return cos_idx, sin_idx
Takes the number associated with the group as m and returns the
indices for cos and sin functions to be applied.
Parameters
- m (int): The chronological number of the group being processed.
- D (int): The number of dimensions per group.
Returns
- cos_idx, sin_idx (np.ndarray, np.ndarray): The indices for cos and sin projections in overall Z matrix.
def
calc_groupz(X_train, X_test, adata, D, sigma, proj_func, dtype):
89def calc_groupz(X_train, X_test, adata, D, sigma, proj_func, dtype): 90 """ 91 Calculates the Z matrix for grouping. 92 93 Parameters 94 ---------- 95 X_train : np.ndarray 96 The filtered data matrix to calculate train Z mat for. 97 98 X_test : np.ndarray 99 The filtered data matrix to calculate test Z mat for. 100 101 adata : anndata.AnnData 102 AnnData object containing `seed_obj` in `.uns` attribute. 103 104 D : int 105 Number of dimensions per grouping. 106 107 sigma : float 108 Kernel width for grouping. 109 110 proj_func : function 111 The projection direction function to be applied to data. 112 113 Returns 114 ------- 115 train_projections, test_projections : np.ndarray, np.ndarray 116 Training and testing Z matrices for group. 117 """ 118 if scipy.sparse.issparse(X_train): 119 X_train = X_train.toarray().astype(np.float16) 120 X_test = X_test.toarray().astype(np.float16) 121 122 W = proj_func(X_train, sigma, adata.uns['seed_obj'], D) 123 124 train_projection = np.matmul(X_train, W, dtype=dtype) 125 test_projection = np.matmul(X_test, W, dtype=dtype) 126 127 if np.isnan(train_projection).any() or np.isnan(test_projection).any(): 128 train_projection = np.matmul(X_train, W, dtype=np.float64) 129 test_projection = np.matmul(X_test, W, dtype=np.float64) 130 131 return train_projection, test_projection
Calculates the Z matrix for grouping.
Parameters
- X_train (np.ndarray): The filtered data matrix to calculate train Z mat for.
- X_test (np.ndarray): The filtered data matrix to calculate test Z mat for.
- adata (anndata.AnnData):
AnnData object containing
seed_objin.unsattribute. - D (int): Number of dimensions per grouping.
- sigma (float): Kernel width for grouping.
- proj_func (function): The projection direction function to be applied to data.
Returns
- train_projections, test_projections (np.ndarray, np.ndarray): Training and testing Z matrices for group.
def
calculate_z( adata, n_features=5000, batches=10, batch_size=100) -> anndata._core.anndata.AnnData:
134def calculate_z(adata, n_features=5000, batches=10, 135 batch_size=100) -> ad.AnnData: 136 """ 137 Function to calculate Z matrices for all groups in both training 138 and testing data. 139 140 Parameters 141 ---------- 142 adata : ad.AnnData 143 created by `scmkl.create_adata()` with `adata.uns.keys()`: 144 `'train_indices'`, and `'test_indices'`. 145 146 n_features : int 147 Number of random feature to use when calculating Z; used for 148 scalability. 149 150 batches : int 151 The number of batches to use for the distance calculation. 152 This will average the result of `batches` distance calculations 153 of `batch_size` randomly sampled cells. More batches will converge 154 to population distance values at the cost of scalability. 155 156 batch_size : int 157 The number of cells to include per batch for distance 158 calculations. Higher batch size will converge to population 159 distance values at the cost of scalability. 160 If `batches*batch_size > num_training_cells`, 161 `batch_size` will be reduced to 162 `int(num_training_cells / batches)`. 163 164 Returns 165 ------- 166 adata : ad.AnnData 167 `adata` with Z matrices accessible with `adata.uns['Z_train']` 168 and `adata.uns['Z_test']`. 169 170 Examples 171 -------- 172 >>> adata = scmkl.estimate_sigma(adata) 173 >>> adata = scmkl.calculate_z(adata) 174 >>> adata.uns.keys() 175 dict_keys(['Z_train', 'Z_test', 'sigmas', 'train_indices', 176 'test_indices']) 177 """ 178 # Number of groupings taking from group_dict 179 n_pathway = len(adata.uns['group_dict'].keys()) 180 D = adata.uns['D'] 181 182 sq_i_d = np.sqrt(1/D) 183 184 # Capturing training and testing sizes 185 train_len = len(adata.uns['train_indices']) 186 test_len = len(adata.uns['test_indices']) 187 188 if batch_size * batches > train_len: 189 old_batch_size = batch_size 190 batch_size = int(train_len/batches) 191 print("Specified batch size required too many cells for " 192 "independent batches. Reduced batch size from " 193 f"{old_batch_size} to {batch_size}") 194 195 if 'sigma' not in adata.uns.keys(): 196 n_samples = np.min((2000, train_len)) 197 sample_range = np.arange(n_samples) 198 batch_idx = get_batches(sample_range, adata.uns['seed_obj'], 199 batches=batches, batch_size=batch_size) 200 sigma_indices = sample_cells(adata.uns['train_indices'], n_samples, adata.uns['seed_obj']) 201 202 # Create Arrays to store concatenated group Zs 203 # Each group of features will have a corresponding entry in each array 204 n_cols = 2*adata.uns['D']*n_pathway 205 Z_train = np.zeros((train_len, n_cols), dtype=np.float16) 206 Z_test = np.zeros((test_len, n_cols), dtype=np.float16) 207 208 209 # Setting kernel function 210 match adata.uns['kernel_type'].lower(): 211 case 'gaussian': 212 proj_func = gaussian_trans 213 case 'laplacian': 214 proj_func = laplacian_trans 215 case 'cauchy': 216 proj_func = cauchy_trans 217 218 219 # Loop over each of the groups and creating Z for each 220 z_dtype = np.float16 221 sigma_list = list() 222 for m, group_features in enumerate(adata.uns['group_dict'].values()): 223 224 n_group_features = len(group_features) 225 226 X_train, X_test = get_group_mat(adata, n_features, group_features, 227 n_group_features, process_test=True) 228 229 if adata.uns['tfidf']: 230 X_train, X_test = tfidf_train_test(X_train, X_test) 231 232 # Data filtering, and transformation according to given data_type 233 # Will remove low variance (< 1e5) features regardless of data_type 234 # If scale/transform data depending on .uns values 235 X_train, X_test = process_data(X_train=X_train, X_test=X_test, 236 scale_data=adata.uns['scale_data'], 237 transform_data=adata.uns['transform_data'], 238 return_dense=True, 239 add_ones=adata.uns['add_ones']) 240 241 # Getting sigma 242 if 'sigma' in adata.uns.keys(): 243 sigma = adata.uns['sigma'][m] 244 else: 245 sigma = est_group_sigma(adata, X_train, n_group_features, 246 n_features, batch_idx=batch_idx) 247 sigma_list.append(sigma) 248 249 assert sigma > 0, "Sigma must be more than 0" 250 train_projection, test_projection = calc_groupz(X_train, X_test, 251 adata, D, sigma, 252 proj_func, z_dtype) 253 254 if train_projection.dtype != z_dtype: 255 print("Converting Z dtype from np.float16 to np.float64", 256 flush=True) 257 z_dtype = train_projection.dtype 258 Z_train = Z_train.astype(z_dtype) 259 Z_test = Z_test.astype(z_dtype) 260 261 # Store group Z in whole-Z object 262 # Preserves order to be able to extract meaningful groups 263 cos_idx, sin_idx = get_z_indices(m, D) 264 265 Z_train[0:, cos_idx] = np.cos(train_projection, dtype=z_dtype) 266 Z_train[0:, sin_idx] = np.sin(train_projection, dtype=z_dtype) 267 268 Z_test[0:, cos_idx] = np.cos(test_projection, dtype=z_dtype) 269 Z_test[0:, sin_idx] = np.sin(test_projection, dtype=z_dtype) 270 271 adata.uns['Z_train'] = Z_train*sq_i_d 272 adata.uns['Z_test'] = Z_test*sq_i_d 273 274 if 'sigma' not in adata.uns.keys(): 275 adata.uns['sigma'] = np.array(sigma_list) 276 277 check_for_nan(adata) 278 check_for_inf(adata) 279 280 return adata
Function to calculate Z matrices for all groups in both training and testing data.
Parameters
- adata (ad.AnnData):
created by
scmkl.create_adatawithadata.uns.keys():'train_indices', and'test_indices'. - n_features (int): Number of random feature to use when calculating Z; used for scalability.
- batches (int):
The number of batches to use for the distance calculation.
This will average the result of
batchesdistance calculations ofbatch_sizerandomly sampled cells. More batches will converge to population distance values at the cost of scalability. - batch_size (int):
The number of cells to include per batch for distance
calculations. Higher batch size will converge to population
distance values at the cost of scalability.
If
batches*batch_size > num_training_cells,batch_sizewill be reduced toint(num_training_cells / batches).
Returns
- adata (ad.AnnData):
adatawith Z matrices accessible withadata.uns['Z_train']andadata.uns['Z_test'].
Examples
>>> adata = scmkl.estimate_sigma(adata)
>>> adata = scmkl.calculate_z(adata)
>>> adata.uns.keys()
dict_keys(['Z_train', 'Z_test', 'sigmas', 'train_indices',
'test_indices'])