dietnetwork 0.3.0__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.
Files changed (33) hide show
  1. dietnet/__init__.py +11 -0
  2. dietnet/_launch.py +40 -0
  3. dietnet/_upstream/Dietnet_train_and_evaluate/__init__.py +0 -0
  4. dietnet/_upstream/Dietnet_train_and_evaluate/compute_input_features_statistics.py +221 -0
  5. dietnet/_upstream/Dietnet_train_and_evaluate/generate_embedding.py +216 -0
  6. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/__init__.py +0 -0
  7. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/dataset_utils.py +200 -0
  8. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/log_utils.py +148 -0
  9. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/mainloop_utils.py +395 -0
  10. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/model.py +489 -0
  11. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/model_handlers.py +89 -0
  12. dietnet/_upstream/Dietnet_train_and_evaluate/helpers/task_handlers.py +361 -0
  13. dietnet/_upstream/Dietnet_train_and_evaluate/partition_data.py +331 -0
  14. dietnet/_upstream/Dietnet_train_and_evaluate/train.py +959 -0
  15. dietnet/align.py +188 -0
  16. dietnet/alphagenome.py +208 -0
  17. dietnet/cli.py +479 -0
  18. dietnet/dataset.py +181 -0
  19. dietnet/features.py +267 -0
  20. dietnet/package.py +187 -0
  21. dietnet/plink.py +163 -0
  22. dietnet/predict.py +123 -0
  23. dietnet/published.py +87 -0
  24. dietnet/py.typed +0 -0
  25. dietnet/training.py +176 -0
  26. dietnet/upstream.py +161 -0
  27. dietnet/upstream_manifest.json +53 -0
  28. dietnetwork-0.3.0.dist-info/METADATA +249 -0
  29. dietnetwork-0.3.0.dist-info/RECORD +33 -0
  30. dietnetwork-0.3.0.dist-info/WHEEL +4 -0
  31. dietnetwork-0.3.0.dist-info/entry_points.txt +2 -0
  32. dietnetwork-0.3.0.dist-info/licenses/LICENSE +28 -0
  33. dietnetwork-0.3.0.dist-info/licenses/NOTICE +15 -0
dietnet/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ """Diet Network for genetic ancestry prediction.
2
+
3
+ The model, training loop and the statistics it is trained on are HussinLab's
4
+ published code (Rochefort-Boulanger, Scicluna et al., AJHG 2026), shipped
5
+ unmodified and called from here; see :mod:`dietnet.upstream`. This package adds
6
+ what the published scripts leave to the user: building their HDF5 input from
7
+ PLINK, allele-aware matching of new cohorts, portable model packages, ensembles,
8
+ biobank-scale inference and a command line around all of it.
9
+ """
10
+
11
+ __version__ = "0.3.0"
dietnet/_launch.py ADDED
@@ -0,0 +1,40 @@
1
+ """Run one of upstream's scripts, unmodified, under current torch.
2
+
3
+ Usage (by :func:`dietnet.upstream.run`): ``python -m dietnet._launch SCRIPT [ARGS...]``.
4
+
5
+ upstream's train.py saves its validation results (numpy float64 scalars) in its
6
+ checkpoint, then reloads it with a bare ``torch.load``. Since torch 2.6 that
7
+ call defaults to ``weights_only=True`` and refuses numpy scalars. Rather than
8
+ switching the safe loader off, this allowlists exactly the numpy types such a
9
+ checkpoint holds -- the remedy torch's own error message gives -- and then runs
10
+ the script as ``python SCRIPT`` would, from its own directory.
11
+ """
12
+
13
+ import runpy
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ import numpy as np
18
+ import torch
19
+
20
+
21
+ def _allow_numpy_scalars() -> None:
22
+ try:
23
+ from numpy._core.multiarray import scalar # numpy >= 2
24
+ except ImportError: # pragma: no cover - numpy 1.x
25
+ from numpy.core.multiarray import scalar
26
+ torch.serialization.add_safe_globals(
27
+ [scalar, np.dtype, type(np.dtype(np.float64)), type(np.dtype(np.int64))]
28
+ )
29
+
30
+
31
+ def main() -> None:
32
+ script = Path(sys.argv[1]).resolve()
33
+ _allow_numpy_scalars()
34
+ sys.argv = [str(script), *sys.argv[2:]]
35
+ sys.path.insert(0, str(script.parent))
36
+ runpy.run_path(str(script), run_name="__main__")
37
+
38
+
39
+ if __name__ == "__main__":
40
+ main()
@@ -0,0 +1,221 @@
1
+ import argparse
2
+ import os
3
+ import multiprocessing as mp
4
+ import time
5
+ from datetime import datetime
6
+
7
+ import numpy as np
8
+
9
+ import h5py
10
+
11
+
12
+ def main():
13
+ start_time = time.time()
14
+ args = parse_args()
15
+
16
+ # Flag to compute only mean (True or False)
17
+ mean_only = args.mean_only
18
+
19
+ # Load indices of every fold
20
+ partition_data = np.load(args.partition, allow_pickle=True)
21
+ indices_byfold = partition_data['folds_indexes']
22
+
23
+ # Dataset
24
+ dataset_file = h5py.File(args.dataset, 'r')
25
+
26
+ # Compute inp feat stats by fold
27
+ means_by_fold = []
28
+ sds_by_fold = []
29
+ for fold in range(len(indices_byfold)):
30
+ print('\n---\nComputing input features statistic of fold', str(fold))
31
+ fold_start_time = time.time()
32
+
33
+ # Indices of the fold
34
+ fold_indices = indices_byfold[fold]
35
+
36
+ # Genotypes of training samples
37
+ train_indices = np.sort(fold_indices[0]) # sort is a hdf5 requirement
38
+ x_train = dataset_file['inputs'][train_indices]
39
+
40
+ # Compute statistics of every features in parallel
41
+ ncpus = args.ncpus
42
+ print('Computing input features statistics of {} SNPs for {} '
43
+ 'samples using {} cpu(s)'.format(
44
+ x_train.shape[1], x_train.shape[0], ncpus))
45
+
46
+ pool = mp.Pool(processes=ncpus) #this starts ncpus nb of processes
47
+
48
+ # Results that will be returned by processes
49
+ results = []
50
+
51
+ # The statistics of every snp feature is computed by a different process
52
+ nb_snps = x_train.shape[1]
53
+ for i in range(nb_snps):
54
+ # Compute snps mean
55
+ if mean_only :
56
+ results.append(
57
+ pool.apply_async(
58
+ compute_feature_mean, args=(i, x_train[:,i])))
59
+
60
+ # Compute mean and standard deviation (sd)
61
+ else:
62
+ results.append(
63
+ pool.apply_async(
64
+ compute_feature_mean_and_sd, args=(i, x_train[:,i])))
65
+
66
+ # Get order (snp nb) and mean of features from multiprocess results
67
+ print('Computed statistics of all input features, getting the results')
68
+ results_values = np.array([np.array(p.get()) for p in results])
69
+
70
+ # Order stats based on snp nb
71
+ print('Ordering {} means returned by multiprocessing'.format(
72
+ len(results_values[:,1])))
73
+ idx = results_values[:,0].astype(int)
74
+ ordered_idx_pos = idx.argsort()
75
+
76
+ # Ordered means
77
+ means = results_values[:,1][ordered_idx_pos]
78
+
79
+ # Ordered sd
80
+ if not mean_only:
81
+ print('Ordering {} standard deviations returned by multiprocessing'.format(
82
+ len(results_values[:,2])))
83
+ sds = results_values[:,2][ordered_idx_pos]
84
+
85
+ # Append fold statistics
86
+ means_by_fold.append(means)
87
+ sds_by_fold.append(sds)
88
+
89
+ print('Computed fold input features stats in {} seconds\n---\n'.format(
90
+ time.time()-fold_start_time))
91
+
92
+ # Close access to h5py dataset file
93
+ dataset_file.close()
94
+
95
+ # Write input features stats to file
96
+ if args.out is not None:
97
+ stats_filename = args.out
98
+ else:
99
+ stats_filename = 'input_features_stats_' \
100
+ + args.dataset.split('/')[-1][0:-5] \
101
+ + '_' \
102
+ + datetime.now().strftime("%Y_%m_%d_%Hh%Mmin%Ssec")
103
+
104
+ stats_fullpath = os.path.join(args.exp_path, stats_filename)
105
+
106
+ if mean_only:
107
+ np.savez(stats_fullpath,
108
+ means_by_fold=means_by_fold)
109
+
110
+ else:
111
+ np.savez(stats_fullpath,
112
+ means_by_fold=means_by_fold,
113
+ sd_by_fold=sds_by_fold)
114
+
115
+ print('\n---')
116
+ print('Input features stats were saved to {}'.format(stats_fullpath))
117
+ print('Execution time {} seconds\n---\n'.format(
118
+ time.time() - start_time))
119
+
120
+
121
+ def compute_feature_mean(i, x):
122
+ """
123
+ i is the snp nb (from 0 to nb_snps-1)
124
+ x is the vector of genotypes for the snp (dim : nb_samples x 1)
125
+ """
126
+ # Set to false missing value (missing values are encoded with -1)
127
+ mask = (x >= 0)
128
+
129
+ # Compute mean :
130
+ # in numerator, missing values are 0
131
+ # in the denominator we divise by the nb of non missing values
132
+ mean = np.sum(x*mask) / np.sum(mask)
133
+
134
+ return (i,mean)
135
+
136
+
137
+ def compute_feature_mean_and_sd(i, x):
138
+ """
139
+ i is the snp nb (from 0 to nb_snps-1)
140
+ x is the vector of genotypes for the snp (dim : nb_samples x 1)
141
+ """
142
+ # Compute mean
143
+ _,mean = compute_feature_mean(i,x)
144
+
145
+ # --- Compute sd ---
146
+ mask = (x >= 0) #set missing values (-1) to False
147
+
148
+ numerator = np.sum((x*mask - mean*mask)**2)
149
+
150
+ denominator = np.sum(mask) - 1
151
+
152
+ sd = np.sqrt(numerator/denominator)
153
+
154
+ sd += 1e-6
155
+
156
+ return (i,mean,sd)
157
+
158
+
159
+ def parse_args():
160
+ parser = argparse.ArgumentParser(
161
+ description=('Compute features means and standard deviations '
162
+ 'for missing values filing and input normalization '
163
+ 'at training time')
164
+ )
165
+
166
+ # Path
167
+ parser.add_argument(
168
+ '--exp-path',
169
+ type=str,
170
+ required=True,
171
+ help=('Path to directory where input features statistics will '
172
+ 'be written')
173
+ )
174
+
175
+ # Files
176
+ parser.add_argument(
177
+ '--dataset',
178
+ type=str,
179
+ required=True,
180
+ help=('Hdf5 dataset created with create_dataset.py. '
181
+ 'Provide full path')
182
+ )
183
+
184
+ parser.add_argument(
185
+ '--partition',
186
+ type=str,
187
+ required=True,
188
+ help=('Npz dataset partition returned by partition_data.py '
189
+ 'Provide full path')
190
+ )
191
+
192
+ # Which statistic to compute (mean or mean+sd)
193
+ parser.add_argument(
194
+ '--mean-only',
195
+ action='store_true',
196
+ help=('Use this flag to compute only input features means '
197
+ 'and not the standard deviations')
198
+ )
199
+
200
+ parser.add_argument(
201
+ '--ncpus',
202
+ type=int,
203
+ default=1,
204
+ help=('Number of cpus for parallel computation of means '
205
+ 'and of standard deviations. Default: %(default)i')
206
+ )
207
+
208
+ # Output
209
+ parser.add_argument(
210
+ '--out',
211
+ type=str,
212
+ help=('Optional filename for input features statistics file. '
213
+ 'If not provided the file will be named '
214
+ 'input_features_stats_datasetFilename_date')
215
+ )
216
+
217
+ return parser.parse_args()
218
+
219
+
220
+ if __name__ == '__main__':
221
+ main()
@@ -0,0 +1,216 @@
1
+ import argparse
2
+ import os
3
+ import time
4
+ from datetime import datetime
5
+ import multiprocessing as mp
6
+
7
+ import numpy as np
8
+
9
+ import h5py
10
+
11
+ import helpers.dataset_utils as du
12
+
13
+
14
+ # Additive encoding : genotypes 0, 1 and 2
15
+ NB_POSSIBLE_GENOTYPES = 3
16
+
17
+ # Class label key in dataset file
18
+ CLASS_LABEL = 'class_labels'
19
+
20
+
21
+ def main():
22
+ start_time = time.time()
23
+ args = parse_args()
24
+
25
+ # Hdf5 dataset
26
+ dataset_file = h5py.File(args.dataset, 'r')
27
+
28
+ # Indices by fold
29
+ partition_data = np.load(args.partition, allow_pickle=True)
30
+ indices_byfold = partition_data['folds_indexes']
31
+
32
+ print('\n---')
33
+ print('Computing embedding by fold using {} cpu(s)'.format(args.ncpus))
34
+ if args.ncpus > 1:
35
+ pool = mp.Pool(processes=args.ncpus) #this starts ncpus nb of processes
36
+
37
+ # Results that will be returned by processes (embedding for a given fold)
38
+ results = []
39
+
40
+ for fold in range(len(indices_byfold)):
41
+ # Fold indices
42
+ fold_indices = indices_byfold[fold]
43
+ # Get fold data
44
+ (_,_,_,
45
+ x_train, y_train, _,
46
+ x_valid, y_valid, _,
47
+ x_test, y_test,_) = du.get_fold_data(fold, indices_byfold, dataset_file, label=CLASS_LABEL)
48
+
49
+ # Embedding on train+valid sets
50
+ if args.include_valid:
51
+ print('Including valid samples in emb computation')
52
+ x = np.concatenate((x_train, x_valid))
53
+ y = np.concatenate((y_train, y_valid))
54
+ # Embedding on valid set
55
+ elif args.only_valid:
56
+ x = x_valid
57
+ y = y_valid
58
+ # Embedding on test set
59
+ elif args.only_test:
60
+ x = x_test
61
+ y = y_test
62
+ # Embedding on training set
63
+ else:
64
+ x = x_train
65
+ y = y_train
66
+
67
+ # Compute embedding
68
+ #emb = compute_fold_embedding(x, y)
69
+
70
+ print('Computing embedding using {} samples'.format(len(y)))
71
+ # One cpu
72
+ if args.ncpus == 1:
73
+ results.append(compute_fold_embedding(x, y, fold))
74
+ else:
75
+ results.append(pool.apply_async(
76
+ compute_fold_embedding, args=(x,y,fold)))
77
+
78
+ # Close access to dataset file
79
+ dataset_file.close()
80
+
81
+ # Results values: [(fold0, embedding0), (fold1, embedding1) ...]
82
+ print('Computed embedding of every fold, getting the results')
83
+ if args.ncpus > 1:
84
+ results_values = [p.get() for p in results]
85
+ else:
86
+ results_values = results
87
+
88
+ # Order results by fold
89
+ print('Putting embeddings by fold order')
90
+ folds_order = np.array([i[0] for i in results_values])
91
+
92
+ # Order counts (nb samples) per class
93
+ classes_counts = np.array([i[1] for i in results_values])
94
+ classes_counts_ordered = classes_counts[folds_order]
95
+
96
+ # Order embeddings
97
+ embeddings = np.array([i[2] for i in results_values])
98
+ embeddings_ordered = embeddings[folds_order]
99
+
100
+ print('Computed embedding of {} folds with following '
101
+ 'number of samples per class for each fold: {}'.format(
102
+ len(folds_order), classes_counts_ordered))
103
+ print('---')
104
+
105
+ # Write embedding to file
106
+ if args.out is not None:
107
+ emb_filename = args.out
108
+ else:
109
+ emb_filename = 'genotype_class_freq_embedding_' \
110
+ + args.dataset.split('/')[-1][0:-5] \
111
+ + '_' \
112
+ + datetime.now().strftime("%Y_%m_%d_%Hh%Mmin%Ssec")
113
+
114
+ emb_fullpath = os.path.join(args.exp_path, emb_filename)
115
+
116
+ print('\n---\nEmbeddings generated in {} seconds'.format(
117
+ time.time()-start_time))
118
+
119
+ print('Saving results to {}'.format(emb_fullpath))
120
+ np.savez(emb_fullpath, emb=embeddings_ordered)
121
+
122
+ print('---\n')
123
+
124
+
125
+ def compute_fold_embedding(xs, ys, fold):
126
+ # Total number of classes
127
+ nb_class = ys.max() + 1 #class 0
128
+ class_to_count = {}
129
+
130
+ # Compute sum of genotypes (0-1-2) per class
131
+ xs = xs.transpose() # rows are snps, col are inds
132
+ embedding = np.zeros((xs.shape[0],nb_class*NB_POSSIBLE_GENOTYPES))
133
+ for c in range(nb_class):
134
+ # Select genotypes for samples of same class
135
+ class_genotypes = xs[:,ys==c]
136
+ nb = class_genotypes.shape[1] #nb of samples in that class
137
+ #print('Class:', c, 'NB:', nb)
138
+ class_to_count[c] = nb
139
+ for genotype in range(NB_POSSIBLE_GENOTYPES):
140
+ col = NB_POSSIBLE_GENOTYPES*c+genotype
141
+ embedding[:,col] = (class_genotypes == genotype).sum(axis=1)/nb
142
+
143
+ return fold, class_to_count, embedding
144
+
145
+
146
+
147
+ def parse_args():
148
+ parser = argparse.ArgumentParser(
149
+ description='Generate embedding'
150
+ )
151
+
152
+ parser.add_argument(
153
+ '--exp-path',
154
+ type=str,
155
+ required=True,
156
+ help='Path to directory where embedding will be saved. '
157
+ )
158
+
159
+ parser.add_argument(
160
+ '--dataset',
161
+ type=str,
162
+ required=True,
163
+ help=('Hdf5 dataset created with create_dataset.py '
164
+ 'Provide full path')
165
+ )
166
+
167
+ parser.add_argument(
168
+ '--partition',
169
+ type=str,
170
+ required=True,
171
+ help=('Npz dataset partition returned by partition_data.py '
172
+ 'Provide full path')
173
+ )
174
+
175
+ parser.add_argument(
176
+ '--ncpus',
177
+ type=int,
178
+ default=1,
179
+ help=('Number of cpus available to compute folds embedding in '
180
+ 'parallel. Default:%(default)i')
181
+ )
182
+
183
+ parser.add_argument(
184
+ '--include-valid',
185
+ action='store_true',
186
+ help=('Use this flag to include samples from the validation set '
187
+ 'in the embedding computation.')
188
+ )
189
+
190
+ parser.add_argument(
191
+ '--only-valid',
192
+ action='store_true',
193
+ help=('Use this flag to compute embedding only on samples '
194
+ ' in the validation set')
195
+ )
196
+
197
+ parser.add_argument(
198
+ '--only-test',
199
+ action='store_true',
200
+ help=('Use this flag to compute embedding only on samples '
201
+ ' in the test set')
202
+ )
203
+
204
+ parser.add_argument(
205
+ '--out',
206
+ type=str,
207
+ help=('Optional filename for embedding file. If not provided '
208
+ 'the file will be named '
209
+ 'genotype_class_freq_embedding_datasetFilename_date')
210
+ )
211
+
212
+ return parser.parse_args()
213
+
214
+
215
+ if __name__ == '__main__':
216
+ main()
@@ -0,0 +1,200 @@
1
+ import math
2
+
3
+ import numpy as np
4
+
5
+ import h5py
6
+
7
+ import torch
8
+
9
+ class FoldDataset(torch.utils.data.Dataset):
10
+ # These variables are set in train.py
11
+ dataset_file = None #path to h5py dataset file
12
+ f = None # Dataset file handler (h5py.File in reading mode)
13
+ task_handler = None # Classification or regression
14
+ data_x = None
15
+ data_y = None
16
+ data_samples = None
17
+
18
+ def __init__(self, set_indexes):
19
+ self.set_indexes = set_indexes
20
+
21
+ def __len__(self):
22
+ return len(self.set_indexes)
23
+
24
+ def __getitem__(self, index):
25
+ # dataloader index goes from 0 to length of set
26
+ # data_x, data_y, data_samples groups data from all sets (train + valid + test)
27
+ # to get the item corresponding to dataloader index, we get the index of the sample
28
+ # in the whole dataset
29
+ file_index = self.set_indexes[index]
30
+
31
+ # Input features
32
+ #x = np.array(self.f['inputs'][file_index], dtype=np.int8)
33
+ x = self.data_x[file_index]
34
+
35
+
36
+ # Label
37
+ #y = self.task_handler.get_label(self.f, file_index)
38
+ y = self.data_y[file_index]
39
+ """
40
+ if self.task == 'classification':
41
+ #y = (self.f['class_labels'][file_index]).astype(np.int64)
42
+ y = np.array(self.f['class_labels'][file_index],
43
+ dtype=np.int64)
44
+ elif self.task == 'regression':
45
+ #y = (self.f['regression_labels'][file_index]).astype(np.float32)
46
+ y = np.array(self.f['regression_labels'][file_index],
47
+ dtype=np.float32)
48
+ """
49
+ # Sample id
50
+ #sample = (self.f['samples'][file_index]).astype(np.str_)
51
+ # SAMPLES ARE INDEX in dataset file (hdf5)
52
+ sample = file_index
53
+
54
+
55
+ return x, y, sample
56
+
57
+ def get_samples(self):
58
+ indexes = np.sort(self.set_indexes)
59
+ samples = (self.f['samples'][indexes]).astype(np.str_)
60
+
61
+ return samples
62
+
63
+ class FoldDataset_forBigdataset(torch.utils.data.Dataset):
64
+ # These variables are set in train.py
65
+ dataset_file = None #path to h5py dataset file
66
+ f = None # Dataset file handler (h5py.File in reading mode)
67
+ task_handler = None # Classification or regression
68
+
69
+ def __init__(self, set_indexes):
70
+ self.set_indexes = set_indexes
71
+
72
+ def __len__(self):
73
+ return len(self.set_indexes)
74
+
75
+ def __getitem__(self, index):
76
+ # Data of all sets (train, valid, test) is in one file
77
+ # so we convert the index to match file index
78
+ file_index = self.set_indexes[index]
79
+
80
+ # Input features
81
+ x = np.array(self.f['inputs'][file_index], dtype=np.int8)
82
+
83
+ # Label
84
+ y = self.task_handler.get_label(self.f, file_index)
85
+ """
86
+ if self.task == 'classification':
87
+ #y = (self.f['class_labels'][file_index]).astype(np.int64)
88
+ y = np.array(self.f['class_labels'][file_index],
89
+ dtype=np.int64)
90
+ elif self.task == 'regression':
91
+ #y = (self.f['regression_labels'][file_index]).astype(np.float32)
92
+ y = np.array(self.f['regression_labels'][file_index],
93
+ dtype=np.float32)
94
+ """
95
+ # Sample id
96
+ #sample = (self.f['samples'][file_index]).astype(np.str_)
97
+ # SAMPLES ARE INDEX
98
+ sample = np.array(index)
99
+
100
+
101
+ return x, y, sample
102
+
103
+ def get_samples(self):
104
+ indexes = np.sort(self.set_indexes)
105
+ samples = (self.f['samples'][indexes]).astype(np.str_)
106
+
107
+ return samples
108
+
109
+
110
+ class IndepTestDataset(torch.utils.data.Dataset):
111
+
112
+ # These variables are set in test_independent_dataset.py
113
+ dataset_file = None # path to h5py dataset file
114
+ f = None # Dataset file handler (h5py.File in reading mode)
115
+ task_handler = None # Classification or regression
116
+ data_x = None
117
+
118
+ def __init__(self, samples):
119
+ self.set_indexes = np.arange(len(samples))
120
+
121
+ def __len__(self):
122
+ return len(self.set_indexes)
123
+
124
+ def __getitem__(self, index):
125
+ # Input features
126
+ #x = np.array(self.f['inputs'][file_index], dtype=np.int8)
127
+ x = self.data_x[index]
128
+
129
+ return index,x
130
+
131
+
132
+
133
+ def get_fold_data(which_fold, folds_indexes, data, label='labels'):
134
+ # Indices of each set for the fold (0:train, 1:valid, 2:test)
135
+ fold_indexes = folds_indexes[which_fold]
136
+ train_indexes = np.sort(fold_indexes[0]) # sort is a hdf5 requirement
137
+ valid_indexes = np.sort(fold_indexes[1])
138
+ test_indexes = np.sort(fold_indexes[2])
139
+
140
+ # Get data (x,y,samples) of each set (train, valid, test)
141
+ x_train = data['inputs'][train_indexes]
142
+ y_train = data[label][train_indexes]
143
+ samples_train = data['samples'][train_indexes]
144
+
145
+ x_valid = data['inputs'][valid_indexes]
146
+ y_valid = data[label][valid_indexes]
147
+ samples_valid = data['samples'][valid_indexes]
148
+
149
+ x_test = data['inputs'][test_indexes]
150
+ y_test = data[label][test_indexes]
151
+ samples_test = data['samples'][test_indexes]
152
+
153
+ return train_indexes, valid_indexes, test_indexes,\
154
+ x_train, y_train, samples_train,\
155
+ x_valid, y_valid, samples_valid,\
156
+ x_test, y_test, samples_test
157
+
158
+
159
+ def compute_norm_values(x):
160
+ """
161
+ x is a tensor
162
+ """
163
+ # Non missing values
164
+ mask = (x >= 0)
165
+
166
+ # Compute mean of every column (feature)
167
+ with torch.no_grad():
168
+ per_feature_mean = torch.sum(x*mask, dim=0) / torch.sum(mask, dim=0)
169
+
170
+ print('Computed per feature mean')
171
+
172
+ # S.d. of every column (feature)
173
+ per_feature_sd = torch.sqrt(
174
+ torch.sum((x*mask-mask*per_feature_mean)**2, dim=0) / \
175
+ (torch.sum(mask, dim=0) - 1)
176
+ )
177
+ per_feature_sd += 1e-6
178
+
179
+ print('Computed per feature sd')
180
+
181
+ return per_feature_mean, per_feature_sd
182
+
183
+
184
+ def replace_missing_values(x, per_feature_mean):
185
+ """
186
+ x and per_feature_mean are tensors
187
+ """
188
+ mask = (x >= 0)
189
+
190
+ for i in range(x.shape[0]):
191
+ x[i] = mask[i]*x[i] + (~mask[i])*per_feature_mean
192
+
193
+
194
+ def normalize(x, per_feature_mean, per_feature_sd):
195
+ """
196
+ x, per_feature_mean and per_feature_sd are tensors
197
+ """
198
+ x_norm = (x - per_feature_mean) / per_feature_sd
199
+
200
+ return x_norm