From 48ce33971bb00a2ac3aa8ce330b1c8eb0d9d6f63 Mon Sep 17 00:00:00 2001 From: Andre Marquand Date: Tue, 5 Jan 2021 14:46:20 +0100 Subject: [PATCH] updated documentation --- doc/build/doctrees/environment.pickle | Bin 185153 -> 206155 bytes doc/build/doctrees/modindex.doctree | Bin 424927 -> 459345 bytes doc/build/html/_modules/fileio.html | 30 +- doc/build/html/_modules/normative.html | 56 ++-- .../html/_modules/normative_parallel.html | 296 +++++++++++++++++- doc/build/html/_modules/utils.html | 169 +++++++++- doc/build/html/genindex.html | 16 +- doc/build/html/modindex.html | 143 ++++++++- doc/build/html/objects.inv | Bin 1125 -> 1166 bytes doc/build/html/searchindex.js | 2 +- 10 files changed, 659 insertions(+), 53 deletions(-) diff --git a/doc/build/doctrees/environment.pickle b/doc/build/doctrees/environment.pickle index 1607ba72e6f8b9807c4da379e84e2335cef7461a..8e93c8cefa83e3f5a935c7f0d2afb363938136f8 100644 GIT binary patch delta 18920 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 LWXrSukuLo|rILQo delta 8346 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 delta 40757 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 Lgh|;Source code for fileio
 from __future__ import print_function
 
 import os
+import sys
 import numpy as np
 import nibabel as nib
 import tempfile
 import pandas as pd
 import re
 
+try:  # run as a package if installed
+    from pcntoolkit import configs
+except ImportError:
+    pass
+
+    path = os.path.abspath(os.path.dirname(__file__))
+    if path not in sys.path:
+        sys.path.append(path)
+    del path
+    import configs
+
 CIFTI_MAPPINGS = ('dconn', 'dtseries', 'pconn', 'ptseries', 'dscalar',
                   'dlabel', 'pscalar', 'pdconn', 'dpconn',
                   'pconnseries', 'pconnscalar')
 
 CIFTI_VOL_ATLAS = 'Atlas_ROIs.2.nii.gz'
 
+PICKLE_PROTOCOL = configs.PICKLE_PROTOCOL
+
 # ------------------------
 # general utility routines
 # ------------------------
 
+
[docs]def predictive_interval(s2_forward, + cov_forward, + multiplicator): + # calculates a predictive interval + + PI=np.zeros(len(cov_forward)) + for i,xdot in enumerate(cov_forward): + s=np.sqrt(s2_forward[i]) + PI[i]=multiplicator*s + return PI
[docs]def create_mask(data_array, mask, verbose=False): # create a (volumetric) mask either from an input nifti or the nifti itself @@ -170,8 +194,8 @@

Source code for fileio

     img = nib.load(datafile)
     dat = img.get_data()
 
-#    if mask is not None:
-#        mask=load_nifti(mask, vol=True)
+    if mask is not None:
+        mask=load_nifti(mask, vol=True)
 
     if not vol:
         dat = vol2vec(dat, mask)
@@ -390,7 +414,7 @@ 

Source code for fileio

         save_ascii(data, filename)
     elif file_type(filename) == 'binary':
         data = pd.DataFrame(data)
-        data.to_pickle(filename)
+ data.to_pickle(filename, protocol=PICKLE_PROTOCOL)
[docs]def load(filename, mask=None, text=False, vol=True): diff --git a/doc/build/html/_modules/normative.html b/doc/build/html/_modules/normative.html index 0f80f4a8..1d53a8ed 100644 --- a/doc/build/html/_modules/normative.html +++ b/doc/build/html/_modules/normative.html @@ -70,6 +70,7 @@

Source code for normative

 from sklearn.model_selection import KFold
 try:  # run as a package if installed
     from pcntoolkit import fileio
+    from pcntoolkit import configs
     from pcntoolkit.normative_model.norm_utils import norm_init
     from pcntoolkit.utils import compute_pearsonr, CustomCV, explained_var, compute_MSLL
 except ImportError:
@@ -82,9 +83,11 @@ 

Source code for normative

     del path
 
     import fileio
+    import configs
     from utils import compute_pearsonr, CustomCV, explained_var, compute_MSLL
     from normative_model.norm_utils import norm_init
 
+PICKLE_PROTOCOL = configs.PICKLE_PROTOCOL
 
 
[docs]def load_response_vars(datafile, maskfile=None, vol=True): """ load response variables (of any data type)""" @@ -445,7 +448,7 @@

Source code for normative

                 yhat, s2 = nm.predict(Xz[te, :], Xz[tr, :], Yz[tr, nz[i]], **kwargs)
                 
                 if savemodel:
-                    nm.save('Models/NM_' + str(fold) + '_' + str(nz[i]) + '.pkl' )
+                    nm.save('Models/NM_' + str(fold) + '_' + str(nz[i]) + outputsuffix + '.pkl' )
                 
                 if standardize:
                     Yhat[te, nz[i]] = yhat * sY[i] + mY[i]
@@ -498,7 +501,7 @@ 

Source code for normative

             pickle.dump({'valid_voxels':nz, 'fold_num':cvfolds, 
                          'mean_resp':mean_resp, 'std_resp':std_resp, 
                          'mean_cov':mean_cov, 'std_cov':std_cov, 
-                         'regressor':alg, 'standardize':standardize}, file)    
+                         'regressor':alg, 'standardize':standardize}, file, protocol=PICKLE_PROTOCOL)    
 
     # compute performance metrics
     if (run_cv or testresp is not None):
@@ -539,6 +542,7 @@ 

Source code for normative

     alg = kwargs.pop('alg','gpr')
     savemodel = kwargs.pop('savemodel','True')=='True'
     standardize = kwargs.pop('standardize',True)
+    outputsuffix = kwargs.pop('outputsuffix','_fit')
     
     if savemodel and not os.path.isdir('Models'):
         os.mkdir('Models')
@@ -588,7 +592,7 @@ 

Source code for normative

         nm = nm.estimate(Xz, Yz[:, nz[i]], **kwargs)     
             
         if savemodel:
-            nm.save('Models/NM_' + str(0) + '_' + str(nz[i]) + '.pkl' )
+            nm.save('Models/NM_' + str(0) + '_' + str(nz[i]) + outputsuffix + '.pkl' )
 
     if savemodel:
         print('Saving model meta-data...')
@@ -596,7 +600,7 @@ 

Source code for normative

             pickle.dump({'valid_voxels':nz,
                          'mean_resp':mean_resp, 'std_resp':std_resp, 
                          'mean_cov':mean_cov, 'std_cov':std_cov, 
-                         'regressor':alg, 'standardize':standardize}, file)
+                         'regressor':alg, 'standardize':standardize}, file, protocol=PICKLE_PROTOCOL)
         
     return nm
@@ -617,7 +621,9 @@

Source code for normative

     :param covfile: test covariates used to predict the response variable
     :param respfile: test response variables for the normative model
     :param maskfile: mask used to apply to the data (nifti only)
-    :param model_path: Directory containing the normative model and metadata
+    :param model_path: Directory containing the normative model and metadata.
+     When using parallel prediction, do not pass the model path. It will be automatically
+     decided.
     :param output_path: Directory to store the results
     :param outputsuffix: Text string to add to the output filenames
     :param batch_size: batch size (for use with normative_parallel)
@@ -636,6 +642,8 @@ 

Source code for normative

     batch_size = kwargs.pop('batch_size', None)
     output_path = kwargs.pop('output_path', '')
     outputsuffix = kwargs.pop('outputsuffix', '_predict')
+    inputsuffix = kwargs.pop('inputsuffix', '_estimate')
+    alg = kwargs.pop('alg')
         
     if respfile is not None and not os.path.exists(respfile):
         print("Response file does not exist. Only returning predictions")
@@ -669,7 +677,7 @@ 

Source code for normative

         X = X[:, np.newaxis]
     
     sample_num = X.shape[0]
-    feature_num = len(glob.glob(os.path.join(model_path, 'NM_*.pkl')))
+    feature_num = len(glob.glob(os.path.join(model_path, 'NM_*' + inputsuffix + '.pkl')))
 
     Yhat = np.zeros([sample_num, feature_num])
     S2 = np.zeros([sample_num, feature_num])
@@ -686,8 +694,13 @@ 

Source code for normative

         print("Prediction by model ", i+1, "of", feature_num)      
         nm = norm_init(Xz)
         nm = nm.load(os.path.join(model_path, 'NM_' + str(0) + '_' + 
-                                  str(i) + '.pkl'))
-        yhat, s2 = nm.predict(Xz, **kwargs)
+                                  str(i) + inputsuffix + '.pkl'))
+        if (alg!='hbr' or nm.configs['transferred']==False):
+            yhat, s2 = nm.predict(Xz, **kwargs)
+        else:
+            tsbefile = kwargs.pop('tsbefile') 
+            batch_effects_test = fileio.load(tsbefile)
+            yhat, s2 = nm.predict_on_new_sites(Xz, batch_effects_test)
         
         if standardize:
             Yhat[:, i] = yhat.squeeze() * sY[0][i] + mY[0][i]
@@ -771,6 +784,7 @@ 

Source code for normative

         batch_effects_train = fileio.load(trbefile)
     
     outputsuffix = kwargs.pop('outputsuffix', '_transfer')
+    inputsuffix = kwargs.pop('inputsuffix', '_estimate')
     tsbefile = kwargs.pop('tsbefile', None)
     
     job_id = kwargs.pop('job_id', None)
@@ -821,20 +835,22 @@ 

Source code for normative

               
         nm = norm_init(X)
         if batch_size is not None: # when using normative_parallel
-            print("Transferting model ", job_id*batch_size+i)
+            print("Transferring model ", job_id*batch_size+i)
             nm = nm.load(os.path.join(model_path, 'NM_0_' + 
-                                      str(job_id*batch_size+i) + '.pkl'))
+                                      str(job_id*batch_size+i) + inputsuffix + '.pkl'))
         else:
-            print("Transferting model ", i+1, "of", feature_num)
-            nm = nm.load(os.path.join(model_path, 'NM_0_' + str(i) + '.pkl'))
+            print("Transferring model ", i+1, "of", feature_num)
+            nm = nm.load(os.path.join(model_path, 'NM_0_' + str(i) + inputsuffix + '.pkl'))
         
         nm = nm.estimate_on_new_sites(X, Y[:,i], batch_effects_train)
         if batch_size is not None: 
             nm.save(os.path.join(output_path, 'NM_0_' + 
-                             str(job_id*batch_size+i) + '.pkl'))
+                             str(job_id*batch_size+i) + outputsuffix + '.pkl'))
+            nm.save(os.path.join('Models', 'NM_0_' + 
+                             str(i) + outputsuffix + '.pkl'))
         else:
             nm.save(os.path.join(output_path, 'NM_0_' + 
-                             str(i) + '.pkl'))
+                             str(i) + outputsuffix + '.pkl'))
         
         if testcov is not None:
             yhat, s2 = nm.predict_on_new_sites(Xte, batch_effects_test)
@@ -876,6 +892,8 @@ 

Source code for normative

         dummycovfile = kwargs.pop('dummycovfile')
         dummybefile = kwargs.pop('dummybefile')
     
+    outputsuffix = kwargs.pop('outputsuffix', '_extend')
+    inputsuffix = kwargs.pop('inputsuffix', '_estimate')
     informative_prior = kwargs.pop('job_id', 'False') == 'True'
     generation_factor = int(kwargs.pop('generation_factor', '10'))
     job_id = kwargs.pop('job_id', None)
@@ -910,20 +928,22 @@ 

Source code for normative

         if batch_size is not None: # when using nirmative_parallel
             print("Extending model ", job_id*batch_size+i)
             nm = nm.load(os.path.join(model_path, 'NM_0_' + 
-                                      str(job_id*batch_size+i) + '.pkl'))
+                                      str(job_id*batch_size+i) + inputsuffix + '.pkl'))
         else:
             print("Extending model ", i+1, "of", feature_num)
-            nm = nm.load(os.path.join(model_path, 'NM_0_' + str(i) + '.pkl'))
+            nm = nm.load(os.path.join(model_path, 'NM_0_' + str(i) + inputsuffix +'.pkl'))
         
         nm = nm.extend(X, Y[:,i:i+1], batch_effects_train, X_dummy, batch_effects_dummy, 
                samples=generation_factor, informative_prior=informative_prior)
         
         if batch_size is not None: 
             nm.save(os.path.join(output_path, 'NM_0_' + 
-                             str(job_id*batch_size+i) + '.pkl'))
+                             str(job_id*batch_size+i) + outputsuffix + '.pkl'))
+            nm.save(os.path.join('Models', 'NM_0_' + 
+                             str(i) + outputsuffix + '.pkl'))
         else:
             nm.save(os.path.join(output_path, 'NM_0_' + 
-                             str(i) + '.pkl'))
+ str(i) + outputsuffix + '.pkl'))
[docs]def main(*args): diff --git a/doc/build/html/_modules/normative_parallel.html b/doc/build/html/_modules/normative_parallel.html index e1439e1d..0e78f723 100644 --- a/doc/build/html/_modules/normative_parallel.html +++ b/doc/build/html/_modules/normative_parallel.html @@ -72,12 +72,15 @@

Source code for normative_parallel

 import glob
 import shutil
 import pickle
+import fileinput
 import numpy as np
 import pandas as pd
 from subprocess import call
 
 try:
+    import pcntoolkit as ptk
     import pcntoolkit.fileio as fileio
+    from pcntoolkit import configs
 except ImportError:
     pass
     path = os.path.abspath(os.path.dirname(__file__))
@@ -85,17 +88,20 @@ 

Source code for normative_parallel

         sys.path.append(path)
         del path
     import fileio
+    import configs
+    
+PICKLE_PROTOCOL = configs.PICKLE_PROTOCOL
 
 
 
[docs]def execute_nm(processing_dir, python_path, - normative_path, job_name, covfile_path, respfile_path, batch_size, memory, duration, + normative_path=None, func='estimate', **kwargs): @@ -107,7 +113,9 @@

Source code for normative_parallel

     :Parameters:
         * processing_dir     -> Full path to the processing dir
         * python_path        -> Full path to the python distribution
-        * normative_path     -> Full path to the normative.py
+        * normative_path     -> Full path to the normative.py. If None (default)
+                                then it will automatically retrieves the path from 
+                                the installed packeage.
         * job_name           -> Name for the bash script that is the output of
                                 this function
         * covfile_path       -> Full path to a .txt file that contains all
@@ -133,6 +141,9 @@ 

Source code for normative_parallel

     written by (primarily) T Wolfers, (adapted) SM Kia
     """
     
+    if normative_path is None:
+        normative_path = ptk.__path__[0] + '/normative.py'
+        
     cv_folds = kwargs.get('cv_folds', None)
     testcovfile_path = kwargs.get('testcovfile_path', None)
     testrespfile_path= kwargs.get('testrespfile_path', None)
@@ -174,7 +185,7 @@ 

Source code for normative_parallel

                                            'testresp_batch_' +
                                            str(n) + file_extentions)
                 batch_job_path = batch_processing_dir + batch_job_name
-                if cluster_spec is 'torque':
+                if cluster_spec == 'torque':
                     # update the response file 
                     kwargs.update({'testrespfile_path': \
                                    batch_testrespfile_path})
@@ -190,11 +201,27 @@ 

Source code for normative_parallel

                             log_path=log_path,
                             memory=memory,
                             duration=duration)
-                elif cluster_spec is 'new':
-                    # this part requires addition in different envioronment [
-                    bashwrap_nm(processing_dir=batch_processing_dir, func=func,
+                elif cluster_spec == 'sbatch':
+                    # update the response file 
+                    kwargs.update({'testrespfile_path': \
+                                   batch_testrespfile_path})
+                    sbatchwrap_nm(batch_processing_dir,
+                                python_path,
+                                normative_path,
+                                batch_job_name,
+                                covfile_path,
+                                batch_respfile_path,
+                                func=func,
+                                memory=memory,
+                                duration=duration,
                                 **kwargs)
-                    qsub_nm(processing_dir=batch_processing_dir)
+                    sbatch_nm(job_path=batch_job_path,
+                            log_path=log_path)
+                elif cluster_spec == 'new':
+                    # this part requires addition in different envioronment [
+                    sbatchwrap_nm(processing_dir=batch_processing_dir, func=func,
+                                  **kwargs)
+                    sbatch_nm(processing_dir=batch_processing_dir)
                     # ]
         if testrespfile_path is None:
             if testcovfile_path is not None:
@@ -204,7 +231,7 @@ 

Source code for normative_parallel

                 batch_respfile_path = (batch_processing_dir + 'resp_batch_' +
                                        str(n) + file_extentions)
                 batch_job_path = batch_processing_dir + batch_job_name
-                if cluster_spec is 'torque':
+                if cluster_spec == 'torque':
                     bashwrap_nm(batch_processing_dir,
                                 python_path,
                                 normative_path,
@@ -217,7 +244,20 @@ 

Source code for normative_parallel

                             log_path=log_path,
                             memory=memory,
                             duration=duration)
-                elif cluster_spec is 'new':
+                elif cluster_spec == 'sbatch':
+                    sbatchwrap_nm(batch_processing_dir,
+                                python_path,
+                                normative_path,
+                                batch_job_name,
+                                covfile_path,
+                                batch_respfile_path,
+                                func=func,
+                                memory=memory,
+                                duration=duration,
+                                **kwargs)
+                    sbatch_nm(job_path=batch_job_path,
+                              log_path=log_path)
+                elif cluster_spec == 'new':
                     # this part requires addition in different envioronment [
                     bashwrap_nm(processing_dir=batch_processing_dir, func=func,
                                 **kwargs)
@@ -232,7 +272,7 @@ 

Source code for normative_parallel

                                        'resp_batch_' + str(n) +
                                        file_extentions)
                 batch_job_path = batch_processing_dir + batch_job_name
-                if cluster_spec is 'torque':
+                if cluster_spec == 'torque':
                     bashwrap_nm(batch_processing_dir,
                                 python_path,
                                 normative_path,
@@ -245,7 +285,20 @@ 

Source code for normative_parallel

                             log_path=log_path,
                             memory=memory,
                             duration=duration)
-                elif cluster_spec is 'new':
+                elif cluster_spec == 'sbatch':
+                    sbatchwrap_nm(batch_processing_dir,
+                                python_path,
+                                normative_path,
+                                batch_job_name,
+                                covfile_path,
+                                batch_respfile_path,
+                                func=func,
+                                memory=memory,
+                                duration=duration,
+                                **kwargs)
+                    sbatch_nm(job_path=batch_job_path,
+                            log_path=log_path)
+                elif cluster_spec == 'new':
                     # this part requires addition in different envioronment [
                     bashwrap_nm(processing_dir=batch_processing_dir, func=func,
                                 **kwargs)
@@ -312,13 +365,14 @@ 

Source code for normative_parallel

             batch = str('batch_' + str(n+1))
             if not os.path.exists(processing_dir + batch):
                 os.makedirs(processing_dir + batch)
+                os.makedirs(processing_dir + batch + '/Models/')
             if (binary==False):
                 fileio.save_pd(resp_batch,
                                processing_dir + batch + '/' +
                                resp + '.txt')
             else:
                 resp_batch.to_pickle(processing_dir + batch + '/' +
-                                     resp + '.pkl')
+                                     resp + '.pkl', protocol=PICKLE_PROTOCOL)
 
     # splits response and test responsefile into batches
     else:
@@ -355,6 +409,7 @@ 

Source code for normative_parallel

             batch = str('batch_' + str(n+1))
             if not os.path.exists(processing_dir + batch):
                 os.makedirs(processing_dir + batch)
+                os.makedirs(processing_dir + batch + '/Models/')
             if (binary==False):
                 fileio.save_pd(resp_batch,
                                processing_dir + batch + '/' +
@@ -364,9 +419,9 @@ 

Source code for normative_parallel

                                '.txt')
             else:
                 resp_batch.to_pickle(processing_dir + batch + '/' +
-                                     resp + '.pkl')
+                                     resp + '.pkl', protocol=PICKLE_PROTOCOL)
                 testresp_batch.to_pickle(processing_dir + batch + '/' +
-                                         testresp + '.pkl')
+ testresp + '.pkl', protocol=PICKLE_PROTOCOL)
[docs]def collect_nm(processing_dir, @@ -620,20 +675,20 @@

Source code for normative_parallel

                     
                 with open(os.path.join(processing_dir, 'Models', 'meta_data.md'), 
                           'wb') as file:
-                    pickle.dump(meta_data, file)
+                    pickle.dump(meta_data, file, protocol=PICKLE_PROTOCOL)
             
             batch_dirs = glob.glob(processing_dir + 'batch_*/')
             if batch_dirs:
                 batch_dirs = fileio.sort_nicely(batch_dirs)
                 for b, batch_dir in enumerate(batch_dirs):
-                    src_files = glob.glob(batch_dir + 'Models/*.pkl')
+                    src_files = glob.glob(batch_dir + 'Models/NM*' + outputsuffix + '.pkl')
                     if src_files:
                         src_files = fileio.sort_nicely(src_files)
                         for f, full_file_name in enumerate(src_files):
                             if os.path.isfile(full_file_name):
                                 file_name = full_file_name.split('/')[-1]
                                 n = file_name.split('_')
-                                n[-1] = str(b * batch_size + f) + '.pkl'
+                                n[-2] = str(b * batch_size + f)
                                 n = '_'.join(n)
                                 shutil.copy(full_file_name, processing_dir + 'Models/' + n)
                     elif func=='fit':
@@ -863,6 +918,213 @@ 

Source code for normative_parallel

 
 # COPY the rotines above here and aadapt those to your cluster
 # bashwarp_nm; qsub_nm; rerun_nm
+
+
[docs]def sbatchwrap_nm(processing_dir, + python_path, + normative_path, + job_name, + covfile_path, + respfile_path, + memory, + duration, + func='estimate', + **kwargs): + + """ This function wraps normative modelling into a bash script to run it + on a torque cluster system. + + :Parameters: + * processing_dir -> Full path to the processing dir + * python_path -> Full path to the python distribution + * normative_path -> Full path to the normative.py + * job_name -> Name for the bash script that is the output of + this function + * covfile_path -> Full path to a .txt file that contains all + covariats (subjects x covariates) for the + responsefile + * respfile_path -> Full path to a .txt that contains all features + (subjects x features) + * cv_folds -> Number of cross validations + * testcovfile_path -> Full path to a .txt file that contains all + covariats (subjects x covariates) for the + testresponse file + * testrespfile_path -> Full path to a .txt file that contains all + test features + * alg -> which algorithm to use + * configparam -> configuration parameters for this algorithm + + :outputs: + * A bash.sh file containing the commands for normative modelling saved + to the processing directory (written to disk) + + written by (primarily) T Wolfers + """ + + # here we use pop not get to remove the arguments as they used + cv_folds = kwargs.pop('cv_folds',None) + testcovfile_path = kwargs.pop('testcovfile_path', None) + testrespfile_path = kwargs.pop('testrespfile_path', None) + alg = kwargs.pop('alg', None) + configparam = kwargs.pop('configparam', None) + standardize = kwargs.pop('standardize', True) + + # change to processing dir + os.chdir(processing_dir) + output_changedir = ['cd ' + processing_dir + '\n'] + + sbatch_init='#!/bin/bash\n' + sbatch_jobname='#SBATCH --job-name=' + processing_dir + '\n' + sbatch_account='#SBATCH --account=p33_norment\n' + sbatch_nodes='#SBATCH --nodes=1\n' + sbatch_tasks='#SBATCH --ntasks=1\n' + sbatch_time='#SBATCH --time=' + str(duration) + '\n' + sbatch_memory='#SBATCH --mem-per-cpu=' + str(memory) + '\n' + sbatch_module='module purge\n' + sbatch_anaconda='module load anaconda3\n' + sbatch_exit='set -o errexit\n' + + #echo -n "This script is running on " + #hostname + + bash_environment = [sbatch_init + + sbatch_jobname + + sbatch_account + + sbatch_nodes + + sbatch_tasks + + sbatch_time + + sbatch_module + + sbatch_anaconda] + + # creates call of function for normative modelling + if (testrespfile_path is not None) and (testcovfile_path is not None): + job_call = [python_path + ' ' + normative_path + ' -c ' + + covfile_path + ' -t ' + testcovfile_path + ' -r ' + + testrespfile_path + ' -f ' + func] + elif (testrespfile_path is None) and (testcovfile_path is not None): + job_call = [python_path + ' ' + normative_path + ' -c ' + + covfile_path + ' -t ' + testcovfile_path + ' -f ' + func] + elif cv_folds is not None: + job_call = [python_path + ' ' + normative_path + ' -c ' + + covfile_path + ' -k ' + str(cv_folds) + ' -f ' + func] + elif func != 'estimate': + job_call = [python_path + ' ' + normative_path + ' -c ' + + covfile_path + ' -f ' + func] + else: + raise(ValueError, """For 'estimate' function either testcov or cvfold + must be specified.""") + + # add algorithm-specific parameters + if alg is not None: + job_call = [job_call[0] + ' -a ' + alg] + if configparam is not None: + job_call = [job_call[0] + ' -x ' + str(configparam)] + + # add standardization flag if it is false + if not standardize: + job_call = [job_call[0] + ' -s'] + + # add responses file + job_call = [job_call[0] + ' ' + respfile_path] + + # add in optional arguments. + for k in kwargs: + job_call = [job_call[0] + ' ' + k + '=' + kwargs[k]] + + # writes bash file into processing dir + with open(processing_dir+job_name, 'w') as bash_file: + bash_file.writelines(bash_environment + output_changedir + \ + job_call + ["\n"] + [sbatch_exit]) + + # changes permissoins for bash.sh file + os.chmod(processing_dir + job_name, 0o700)
+ +
[docs]def sbatch_nm(job_path, + log_path): + """ + This function submits a job.sh scipt to the torque custer using the qsub + command. + + ** Input: + * job_path -> Full path to the job.sh file + * log_path -> The logs are currently stored in the working dir + + ** Output: + * Submission of the job to the (torque) cluster + + witten by (primarily) T Wolfers + """ + + # created qsub command + sbatch_call = ['sbatch ' + job_path] + + # submits job to cluster + call(sbatch_call, shell=True) + + def rerun_nm(processing_dir, + memory, + duration, + new_memory=False, + new_duration=False, + binary=False, + **kwargs): + """ + This function reruns all failed batched in processing_dir after collect_nm + has identified he failed batches + + * Input: + * processing_dir -> Full path to the processing directory + * memory -> Memory requirements written as string + for example 4gb or 500mb + * duration -> The approximate duration of the job, a + string with HH:MM:SS for example 01:01:01 + * new_memory -> If you want to change the memory + you have to indicate it here. + * new_duration -> If you want to change the duration + you have to indicate it here. + * Outputs: + * Reruns failed batches. + + written by (primarily) T Wolfers + """ + log_path = kwargs.pop('log_path', None) + + if binary: + file_extentions = '.pkl' + failed_batches = fileio.load(processing_dir + + 'failed_batches' + + file_extentions) + shape = failed_batches.shape + for n in range(0, shape[0]): + jobpath = failed_batches[n, 0] + print(jobpath) + if new_duration != False: + with fileinput.FileInput(jobpath, inplace=True) as file: + for line in file: + print(line.replace(duration, new_duration), end='') + if new_memory != False: + with fileinput.FileInput(jobpath, inplace=True) as file: + for line in file: + print(line.replace(memory, new_memory), end='') + sbatch_nm(jobpath, + log_path) + else: + file_extentions = '.txt' + failed_batches = fileio.load_pd(processing_dir + + 'failed_batches' + file_extentions) + shape = failed_batches.shape + for n in range(0, shape[0]): + jobpath = failed_batches.iloc[n, 0] + print(jobpath) + if new_duration != False: + with fileinput.FileInput(jobpath, inplace=True) as file: + for line in file: + print(line.replace(duration, new_duration), end='') + if new_memory != False: + with fileinput.FileInput(jobpath, inplace=True) as file: + for line in file: + print(line.replace(memory, new_memory), end='') + sbatch_nm(jobpath, + log_path)
diff --git a/doc/build/html/_modules/utils.html b/doc/build/html/_modules/utils.html index c0ea6533..d669eaff 100644 --- a/doc/build/html/_modules/utils.html +++ b/doc/build/html/_modules/utils.html @@ -47,6 +47,7 @@

Source code for utils

 from __future__ import print_function
 
 import os
+import sys
 import numpy as np
 from scipy import stats
 from subprocess import call
@@ -60,6 +61,20 @@ 

Source code for utils

 from bspline import splinelab
 from sklearn.datasets import make_regression
 import pymc3 as pm
+from io import StringIO
+
+try:  # run as a package if installed
+    from pcntoolkit import configs
+except ImportError:
+    pass
+
+    path = os.path.abspath(os.path.dirname(__file__))
+    if path not in sys.path:
+        sys.path.append(path)
+    del path
+    import configs
+    
+PICKLE_PROTOCOL = configs.PICKLE_PROTOCOL
 
 # -----------------
 # Utility functions
@@ -368,6 +383,22 @@ 

Source code for utils

     """ Sin-hyperbolic arcsin warp having two parameters (a, b) and defined by 
     
         y = sinh(b *  arcsinh(x) - a)
+        
+        Using the parametrisation of Rios et al, Neural Networks 118 (2017)
+        where a controls skew and b controls kurtosis, such that:
+            a = 0 : symmetric
+            a > 0 : positive skew
+            a < 0 : negative skew
+            b = 1 : mesokurtic
+            b > 1 : leptokurtic
+            b < 1 : platykurtic
+        
+        where b > 0. However, it is more convenentent to use an alternative 
+        parameterisation, where
+
+        y = sinh(b * arcsinh(x) + epsilon * b)
+        
+        and a = -epsilon*b
     
         see Jones and Pewsey A (2009) Biometrika, 96 (4) (2009)
     """
@@ -379,7 +410,12 @@ 

Source code for utils

         if len(param) != self.n_params:
             raise(ValueError, 
                   'number of parameters must be ' + str(self.n_params))
-        return param[0], param[1]
+
+        epsilon = param[0]
+        b = np.exp(param[1])
+        a = -epsilon*b
+        
+        return a, b
 
 
[docs] def f(self, x, params): a, b = self._get_params(params) @@ -757,17 +793,17 @@

Source code for utils

         if not os.path.isdir(working_dir):
             os.mkdir(working_dir)
         with open(os.path.join(working_dir ,'trbefile.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(grp_id_train),file)
+            pickle.dump(pd.DataFrame(grp_id_train),file, protocol=PICKLE_PROTOCOL)
         with open(os.path.join(working_dir ,'tsbefile.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(grp_id_test),file)
+            pickle.dump(pd.DataFrame(grp_id_test),file, protocol=PICKLE_PROTOCOL)
         with open(os.path.join(working_dir ,'X_train.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(X_train),file)
+            pickle.dump(pd.DataFrame(X_train),file, protocol=PICKLE_PROTOCOL)
         with open(os.path.join(working_dir ,'X_test.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(X_test),file)
+            pickle.dump(pd.DataFrame(X_test),file, protocol=PICKLE_PROTOCOL)
         with open(os.path.join(working_dir ,'Y_train.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(Y_train),file)
+            pickle.dump(pd.DataFrame(Y_train),file, protocol=PICKLE_PROTOCOL)
         with open(os.path.join(working_dir ,'Y_test.pkl'), 'wb') as file:
-            pickle.dump(pd.DataFrame(Y_test),file)
+            pickle.dump(pd.DataFrame(Y_test),file, protocol=PICKLE_PROTOCOL)
         
     return X_train, Y_train, grp_id_train, X_test, Y_test, grp_id_test, coef
@@ -794,6 +830,125 @@

Source code for utils

     plt.xticks(rotation=90, fontsize=7)
     plt.tight_layout()
     plt.show()
+ + +
[docs]def load_freesurfer_measure(measure, data_path, subjects_list): + + """ + This is a utility function to load different Freesurfer measures in a pandas + Dataframe. + + Inputs: + - measure: a string that defines the type of Freesurfer measure we want + to load. The options include: + - 'NumVert': Number of Vertices in each cortical area based on Destrieux atlas. + - 'SurfArea: Surface area for each cortical area based on Destrieux atlas. + - 'GrayVol': Gary matter volume in each cortical area based on Destrieux atlas. + - 'ThickAvg': Average Cortical thinckness in each cortical area based on Destrieux atlas. + - 'ThickStd': STD of Cortical thinckness in each cortical area based on Destrieux atlas. + - 'MeanCurv': Integrated Rectified Mean Curvature in each cortical area based on Destrieux atlas. + - 'GausCurv': Integrated Rectified Gaussian Curvature in each cortical area based on Destrieux atlas. + - 'FoldInd': Folding Index in each cortical area based on Destrieux atlas. + - 'CurvInd': Intrinsic Curvature Index in each cortical area based on Destrieux atlas. + - 'brain': Brain Segmentation Statistics from aseg.stats file. + - 'subcortical_volumes': Subcortical areas volume. + + - data_path: a string that specifies the path to the main Freesurfer folder. + + - subjects_list: A Pythin list containing the list of subject names to load the data for. + The subject names should match the folder name for each subject's Freesurfer data folder. + + Outputs: + - df: A pandas datafrmae containing the subject names as Index and target Freesurfer measures. + - missing_subs: A Python list of subject names that miss the target Freesurefr measures. + + """ + + df = pd.DataFrame() + missing_subs = [] + + if measure in ['NumVert', 'SurfArea', 'GrayVol', 'ThickAvg', + 'ThickStd', 'MeanCurv', 'GausCurv', 'FoldInd', 'CurvInd']: + l = ['NumVert', 'SurfArea', 'GrayVol', 'ThickAvg', + 'ThickStd', 'MeanCurv', 'GausCurv', 'FoldInd', 'CurvInd'] + col = l.index(measure) + 1 + for i, sub in enumerate(subjects_list): + try: + data = dict() + + a = pd.read_csv(data_path + sub + '/stats/lh.aparc.a2009s.stats', + delimiter='\s+', comment='#', header=None) + temp = dict(zip(a[0], a[col])) + for key in list(temp.keys()): + temp['L_'+key] = temp.pop(key) + data.update(temp) + + a = pd.read_csv(data_path + sub + '/stats/rh.aparc.a2009s.stats', + delimiter='\s+', comment='#', header=None) + temp = dict(zip(a[0], a[col])) + for key in list(temp.keys()): + temp['R_'+key] = temp.pop(key) + data.update(temp) + + df_temp = pd.DataFrame(data,index=[sub]) + df = pd.concat([df, df_temp]) + print('%d / %d: %s is done!' %(i, len(subjects_list), sub)) + except: + missing_subs.append(sub) + print('%d / %d: %s is missing!' %(i, len(subjects_list), sub)) + continue + + elif measure == 'brain': + for i, sub in enumerate(subjects_list): + try: + data = dict() + s = StringIO() + with open(data_path + sub + '/stats/aseg.stats') as f: + for line in f: + if line.startswith('# Measure'): + s.write(line) + s.seek(0) # "rewind" to the beginning of the StringIO object + a = pd.read_csv(s, header=None) # with further parameters? + data_brain = dict(zip(a[1], a[3])) + data.update(data_brain) + df_temp = pd.DataFrame(data,index=[sub]) + df = pd.concat([df, df_temp]) + print('%d / %d: %s is done!' %(i, len(subjects_list), sub)) + except: + missing_subs.append(sub) + print('%d / %d: %s is missing!' %(i, len(subjects_list), sub)) + continue + + elif measure == 'subcortical_volumes': + for i, sub in enumerate(subjects_list): + try: + data = dict() + s = StringIO() + with open(data_path + sub + '/stats/aseg.stats') as f: + for line in f: + if line.startswith('# Measure'): + s.write(line) + s.seek(0) # "rewind" to the beginning of the StringIO object + a = pd.read_csv(s, header=None) # with further parameters? + a = dict(zip(a[1], a[3])) + if ' eTIV' in a.keys(): + tiv = a[' eTIV'] + else: + tiv = a[' ICV'] + a = pd.read_csv(data_path + sub + '/stats/aseg.stats', delimiter='\s+', comment='#', header=None) + data_vol = dict(zip(a[4]+'_mm3', a[3])) + for key in data_vol.keys(): + data_vol[key] = data_vol[key]/tiv + data.update(data_vol) + data = pd.DataFrame(data,index=[sub]) + df = pd.concat([df, data]) + print('%d / %d: %s is done!' %(i, len(subjects_list), sub)) + except: + missing_subs.append(sub) + print('%d / %d: %s is missing!' %(i, len(subjects_list), sub)) + continue + + return df, missing_subs
diff --git a/doc/build/html/genindex.html b/doc/build/html/genindex.html index 89417bed..ca00b338 100644 --- a/doc/build/html/genindex.html +++ b/doc/build/html/genindex.html @@ -335,10 +335,12 @@

L

  • load_data() (in module trendsurf)
  • -
  • load_nifti() (in module fileio) +
  • load_freesurfer_measure() (in module utils)
  • - - +

    Q

    @@ -478,10 +482,14 @@

    S

  • save_nifti() (in module fileio)
  • save_pd() (in module fileio) +
  • +
  • save_results() (in module normative)
    • -
    • save_results() (in module normative) +
    • sbatch_nm() (in module normative_parallel) +
    • +
    • sbatchwrap_nm() (in module normative_parallel)
    • simulate_data() (in module utils)
    • diff --git a/doc/build/html/modindex.html b/doc/build/html/modindex.html index 95a14547..320674cc 100644 --- a/doc/build/html/modindex.html +++ b/doc/build/html/modindex.html @@ -498,7 +498,9 @@

      Navigation

    • covfile – test covariates used to predict the response variable

    • respfile – test response variables for the normative model

    • maskfile – mask used to apply to the data (nifti only)

    • -
    • model_path – Directory containing the normative model and metadata

    • +
    • model_path – Directory containing the normative model and metadata. +When using parallel prediction, do not pass the model path. It will be automatically +decided.

    • output_path – Directory to store the results

    • outputsuffix – Text string to add to the output filenames

    • batch_size – batch size (for use with normative_parallel)

    • @@ -659,7 +661,7 @@

      Navigation

      -normative_parallel.execute_nm(processing_dir, python_path, normative_path, job_name, covfile_path, respfile_path, batch_size, memory, duration, func='estimate', **kwargs)[source]
      +normative_parallel.execute_nm(processing_dir, python_path, job_name, covfile_path, respfile_path, batch_size, memory, duration, normative_path=None, func='estimate', **kwargs)[source]

      This function is a mother function that executes all parallel normative modelling routines. Different specifications are possible using the sub- functions.

      @@ -668,7 +670,12 @@

      Navigation

      • processing_dir -> Full path to the processing dir

      • python_path -> Full path to the python distribution

      • -
      • normative_path -> Full path to the normative.py

      • +
      • +
        normative_path -> Full path to the normative.py. If None (default)

        then it will automatically retrieves the path from +the installed packeage.

        +
        +
        +
      • job_name -> Name for the bash script that is the output of

        this function

        @@ -775,6 +782,78 @@

        Navigation

        written by (primarily) T Wolfers, (adapted) SM Kia

      +
      +
      +normative_parallel.sbatch_nm(job_path, log_path)[source]
      +

      This function submits a job.sh scipt to the torque custer using the qsub +command.

      +
      +
      ** Input:
        +
      • job_path -> Full path to the job.sh file

      • +
      • log_path -> The logs are currently stored in the working dir

      • +
      +
      +
      ** Output:
        +
      • Submission of the job to the (torque) cluster

      • +
      +
      +
      +

      witten by (primarily) T Wolfers

      +
      + +
      +
      +normative_parallel.sbatchwrap_nm(processing_dir, python_path, normative_path, job_name, covfile_path, respfile_path, memory, duration, func='estimate', **kwargs)[source]
      +

      This function wraps normative modelling into a bash script to run it +on a torque cluster system.

      +
      +
      Parameters
      +
        +
      • processing_dir -> Full path to the processing dir

      • +
      • python_path -> Full path to the python distribution

      • +
      • normative_path -> Full path to the normative.py

      • +
      • +
        job_name -> Name for the bash script that is the output of

        this function

        +
        +
        +
      • +
      • +
        covfile_path -> Full path to a .txt file that contains all

        covariats (subjects x covariates) for the +responsefile

        +
        +
        +
      • +
      • +
        respfile_path -> Full path to a .txt that contains all features

        (subjects x features)

        +
        +
        +
      • +
      • cv_folds -> Number of cross validations

      • +
      • +
        testcovfile_path -> Full path to a .txt file that contains all

        covariats (subjects x covariates) for the +testresponse file

        +
        +
        +
      • +
      • +
        testrespfile_path -> Full path to a .txt file that contains all

        test features

        +
        +
        +
      • +
      • alg -> which algorithm to use

      • +
      • configparam -> configuration parameters for this algorithm

      • +
      +
      +
      Outputs
      +
        +
      • A bash.sh file containing the commands for normative modelling saved +to the processing directory (written to disk)

      • +
      +
      +
      +

      written by (primarily) T Wolfers

      +
      +
      normative_parallel.split_nm(processing_dir, respfile_path, batch_size, binary, **kwargs)[source]
      @@ -1009,6 +1088,11 @@

      Navigation

      fileio.load_pd(filename)[source]
      +
      +
      +fileio.predictive_interval(s2_forward, cov_forward, multiplicator)[source]
      +
      +
      fileio.save(data, filename, example=None, mask=None, text=False)[source]
      @@ -1338,6 +1422,20 @@

      Navigation

      Bases: utils.WarpBase

      Sin-hyperbolic arcsin warp having two parameters (a, b) and defined by

      y = sinh(b * arcsinh(x) - a)

      +

      Using the parametrisation of Rios et al, Neural Networks 118 (2017) +where a controls skew and b controls kurtosis, such that:

      +
      +

      a = 0 : symmetric +a > 0 : positive skew +a < 0 : negative skew +b = 1 : mesokurtic +b > 1 : leptokurtic +b < 1 : platykurtic

      +
      +

      where b > 0. However, it is more convenentent to use an alternative +parameterisation, where

      +

      y = sinh(b * arcsinh(x) + epsilon * b)

      +

      and a = -epsilon*b

      see Jones and Pewsey A (2009) Biometrika, 96 (4) (2009)

      @@ -1538,6 +1636,45 @@

      Navigation

      utils.extreme_value_prob_fit(NPM, perc)[source]
      +
      +
      +utils.load_freesurfer_measure(measure, data_path, subjects_list)[source]
      +

      This is a utility function to load different Freesurfer measures in a pandas +Dataframe.

      +
      +
      Inputs:
        +
      • measure: a string that defines the type of Freesurfer measure we want

      • +
      +
      +
      to load. The options include:
        +
      • ‘NumVert’: Number of Vertices in each cortical area based on Destrieux atlas.

      • +
      • ‘SurfArea: Surface area for each cortical area based on Destrieux atlas.

      • +
      • ‘GrayVol’: Gary matter volume in each cortical area based on Destrieux atlas.

      • +
      • ‘ThickAvg’: Average Cortical thinckness in each cortical area based on Destrieux atlas.

      • +
      • ‘ThickStd’: STD of Cortical thinckness in each cortical area based on Destrieux atlas.

      • +
      • ‘MeanCurv’: Integrated Rectified Mean Curvature in each cortical area based on Destrieux atlas.

      • +
      • ‘GausCurv’: Integrated Rectified Gaussian Curvature in each cortical area based on Destrieux atlas.

      • +
      • ‘FoldInd’: Folding Index in each cortical area based on Destrieux atlas.

      • +
      • ‘CurvInd’: Intrinsic Curvature Index in each cortical area based on Destrieux atlas.

      • +
      • ‘brain’: Brain Segmentation Statistics from aseg.stats file.

      • +
      • ‘subcortical_volumes’: Subcortical areas volume.

      • +
      +
      +
      +
        +
      • data_path: a string that specifies the path to the main Freesurfer folder.

      • +
      • subjects_list: A Pythin list containing the list of subject names to load the data for.

      • +
      +

      The subject names should match the folder name for each subject’s Freesurfer data folder.

      +
      +
      Outputs:
        +
      • df: A pandas datafrmae containing the subject names as Index and target Freesurfer measures.

      • +
      • missing_subs: A Python list of subject names that miss the target Freesurefr measures.

      • +
      +
      +
      +
      +
      utils.qsub(job_path, memory, duration, logdir=None)[source]
      diff --git a/doc/build/html/objects.inv b/doc/build/html/objects.inv index 9165952e0c74cf0967c2797cff4d3a8dd05cd975..08fc4148da1254b53b34f5dcb3a60486fafeb9e5 100644 GIT binary patch delta 1026 zcmV+d1pWKv2#yJmnt!F4!EW0)5Qgu03IW?|gl&(#rB1sjkQ9akv`2v^M-~x^R7gs( z-@Zf1vg9sc&8Q~}^8cB`pX6``-is3i4~MKdeXgBq4P^gj_@J$VV_wDD{4>11|B&6^ z?a%7`%hN6q(ufeUkADDvDsyGr!RXh142YFe%Ls(1YY~CN@P9{XT!<{a2c_i_QfdR* z(HtGLxiC#7Y+Dzva7tj=S{b#oH-0~t9?+no7U7kOq>loQ5o}0G4izHQEFhj5paRAT z#nBcbNUd3f)MexmmQ6I|Nt`#5?x4^%g71W(qCs@P(ek|N36@tqVc7)TtKfXZ0VEjm z(TM(pwo=udGk>2tkc;v|Lp#%lCf~U3iwJN#M^3t2x^5w<%*2YNJ^;E`G{TEIkf*qiYH$e{KM{%96xG#Q%Hbf6a0y^HE9lQO%ETn ziX-L){oi)C7%^&yCCph&EMCrP&My-RmQhJ6Rjl(EsDB=Al;zBJkzY;mX40G?c*(U) zB$Xg6@MC|No(axLEBL%OlfZS?csL%o^-?%J_Cqpd`2+to*BiBi*O0d)uf9cdQ7yT z^(D>zi+t=t@i^<{lrv%E`(r}L*?L0yY^_8T42G1XC;7YADHjkrtTt*BX!iEfeA9;L z>dnvFJN#NZ9JPhT9*}R3J6g>7FX5YqveXtRp?^&3T$Q9qW&|5x9J&9o+IH;m-tn;* z+jlGi$oz6Yc&+7_*Xx<`RmSxs%eJ0aZ<;%9+>vZsuVxuH5Nu$bc>~L{Z(vp%xN$XJ z7vzn1mUAo|5k9fX#1Uq>I6|v!e9`v7%b;yVb#fv&X3nTp&?-x3Jj>M?x60VD1t8u+ zQhyk|_adnZ@ZNbUhl`);_2-wTCnnMWHh9jGM>^L+=?=Ekn&=8`oH?;Lg>|++fR)G^ z7l{-c8-ryIsMNud87zA0)bpAa2lH;f8Z0Pn`T+M8TC|iyr5;;n zQ+#?P%7d<3lU9sWU7ne@R^SmSln&JC$9oF9`N|np{MbGdnbwl$f*YrQlZB{08?ncJ z{{CY&zU_6{_w;x-$&`~xG*fIZe`aJG-1r&~YW4$K?}F56XJ*kk^QzCwol?Jnyo)28VY8^D=zD6$iNc4UuO_r%Gr0Z2$lO delta 985 zcmV;~119{A3FQcontz>_O>f&U3_$Pw6$Z9zjcv!>x^x`|v_p^r+tE-gIuR;Mu0Gu4 z-;c7B+S!1Z)G3DZo<-3TO>M;yyn|iQ9ly3#Mh(TM0xy)2a47eo)gQ*&w;zk!o9&4% zzdde}QETCS@%bO&U$T_i?zDOt#(=Q5a#;Z%R4W2-9R4Vs^?!lIJCLegQW~W}Sz1O% zwiLSC3lrPw1&&EP39l z(KhC;D_6GvCVxC!FLV=E*0x`$3^Q1==pA78s!ll3dXn|13?**F$YCc|a$t7Q&#&JP z9VP4mBnLjyl85I7f48|O$B!&;3Q3S`gFlhjlI9Rwdicmn4$KSs$9l6EF*3wH$GNJ1@lcavbScieC@r$xt+1~MsDPAp_Go=?gGJloSZ%BsFsKB7pQW0+F8Ordn zcHlc}JXF1K9Jv+BF!0$cBpSn)6{CwfaN-J17~g=SE5rWM8Z>j=ynE$V`2Cv`U1i#g zVX=JRPaQIC2^z5f&6D8(b{!_D&H@g=X_`cfEj49I=Sb z1Y#kb8GnrGKeM=T5z6qKCY9pgu+;hJ8e00_@$+F0H5He0MH z2jx*t2Nojg@c5~#FZV>;t2XMCb5ehJa$cjrMP5nesS^l$JQ44$mesHI6VZu=JQsZR z!=1th`BjT8o{4Wi7w5YJSNu$uHxnjpol>9~u|DnG9*Pw%U4>h%_yy5fU#qmXieRmN zQQ_ts!2CHEK^0G9b32ZCfxk!B9dEBVvws(~^$`nUZYB diff --git a/doc/build/html/searchindex.js b/doc/build/html/searchindex.js index c2866856..1073c19b 100644 --- a/doc/build/html/searchindex.js +++ b/doc/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["index","modindex"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst","modindex.rst"],objects:{"":{bayesreg:[1,0,0,"-"],fileio:[1,0,0,"-"],gp:[1,0,0,"-"],normative:[1,0,0,"-"],normative_parallel:[1,0,0,"-"],rfa:[1,0,0,"-"],trendsurf:[1,0,0,"-"],utils:[1,0,0,"-"]},"bayesreg.BLR":{dloglik:[1,2,1,""],estimate:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"gp.CovBase":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovLin":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSqExp":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSqExpARD":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSum":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.GPR":{dloglik:[1,2,1,""],estimate:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"rfa.GPRRFA":{dloglik:[1,2,1,""],estimate:[1,2,1,""],get_n_params:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"utils.CustomCV":{split:[1,2,1,""]},"utils.WarpAffine":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpBase":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpBoxCox":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpCompose":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpSinArcsinh":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},bayesreg:{BLR:[1,1,1,""]},fileio:{alphanum_key:[1,3,1,""],create_mask:[1,3,1,""],file_extension:[1,3,1,""],file_stem:[1,3,1,""],file_type:[1,3,1,""],load:[1,3,1,""],load_ascii:[1,3,1,""],load_cifti:[1,3,1,""],load_nifti:[1,3,1,""],load_pd:[1,3,1,""],save:[1,3,1,""],save_ascii:[1,3,1,""],save_cifti:[1,3,1,""],save_nifti:[1,3,1,""],save_pd:[1,3,1,""],sort_nicely:[1,3,1,""],tryint:[1,3,1,""],vol2vec:[1,3,1,""]},gp:{CovBase:[1,1,1,""],CovLin:[1,1,1,""],CovSqExp:[1,1,1,""],CovSqExpARD:[1,1,1,""],CovSum:[1,1,1,""],GPR:[1,1,1,""]},normative:{estimate:[1,3,1,""],evaluate:[1,3,1,""],extend:[1,3,1,""],fit:[1,3,1,""],get_args:[1,3,1,""],load_response_vars:[1,3,1,""],main:[1,3,1,""],predict:[1,3,1,""],save_results:[1,3,1,""],transfer:[1,3,1,""]},normative_parallel:{bashwrap_nm:[1,3,1,""],collect_nm:[1,3,1,""],delete_nm:[1,3,1,""],execute_nm:[1,3,1,""],qsub_nm:[1,3,1,""],rerun_nm:[1,3,1,""],split_nm:[1,3,1,""]},rfa:{GPRRFA:[1,1,1,""]},trendsurf:{create_basis:[1,3,1,""],estimate:[1,3,1,""],get_args:[1,3,1,""],load_data:[1,3,1,""],main:[1,3,1,""],write_nii:[1,3,1,""]},utils:{CustomCV:[1,1,1,""],FDR:[1,3,1,""],WarpAffine:[1,1,1,""],WarpBase:[1,1,1,""],WarpBoxCox:[1,1,1,""],WarpCompose:[1,1,1,""],WarpSinArcsinh:[1,1,1,""],bashwrap:[1,3,1,""],calibration_error:[1,3,1,""],compute_MSLL:[1,3,1,""],compute_pearsonr:[1,3,1,""],create_bspline_basis:[1,3,1,""],create_poly_basis:[1,3,1,""],divergence_plot:[1,3,1,""],explained_var:[1,3,1,""],extreme_value_prob:[1,3,1,""],extreme_value_prob_fit:[1,3,1,""],qsub:[1,3,1,""],ravel_2D:[1,3,1,""],simulate_data:[1,3,1,""],squared_dist:[1,3,1,""],threshold_NPM:[1,3,1,""],unravel_2D:[1,3,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:function"},terms:{"001":1,"025":1,"100":1,"1981":1,"2006":1,"2009":1,"2019":1,"4gb":1,"500mb":1,"975":1,"abstract":1,"boolean":1,"case":1,"class":1,"default":1,"function":1,"int":1,"new":1,"return":1,"true":1,For:1,That:1,The:1,These:1,_estim:1,abs:1,accord:1,account:1,accross:1,adapt:1,add:1,added:1,affin:1,after:1,alg:1,algorithm:1,all:1,allow:1,alpha:1,alphanum_kei:1,also:1,ani:1,appli:1,approach:1,appropri:1,approxim:1,arcsin:1,arcsinh:1,ard:1,arg:1,argument:1,arrai:1,articl:1,ascii:1,assum:1,automat:1,base:1,bash:1,bash_environ:1,bashwrap:1,bashwrap_nm:1,basi:1,basic:1,batch:1,batch_siz:1,bayesian:1,bayesreg:1,below:1,beta:1,between:1,bicken:1,binari:1,biometrika:1,bishop:1,blr:1,both:1,box:1,bspline:1,cal_level:1,calibration_error:1,can:1,cell:1,cfold:1,check:1,cifti:1,cluster:1,coef:1,coeffici:1,collect:1,collect_nm:1,column:1,com:1,combin:1,command:1,common:1,compat:1,composit:1,composition:1,comput:1,compute_msl:1,compute_pearsonr:1,configparam:1,configur:1,conjug:1,contain:1,content:0,control:1,correl:1,count:1,cov:1,covari:1,covariat:1,covbas:1,covfil:1,covfile_path:1,covfunc:1,covfuncnam:1,covfunct:1,covlin:1,covsqexp:1,covsqexpard:1,covsum:1,cox:1,creat:1,create_basi:1,create_bspline_basi:1,create_mask:1,create_poly_basi:1,creation:1,cross:1,cubic:1,current:1,custer:1,custom:1,customcv:1,cv_fold:1,cvfold:1,dat:1,data:1,data_arrai:1,datafil:1,dataset:1,dcov:1,decid:1,defaul:1,defin:1,degre:1,delet:1,delete_nm:1,delimit:1,depend:1,deriv:1,design:1,desir:1,determin:1,devianc:1,deviat:1,diag:1,diagon:1,differ:1,dimension:1,diment:1,dimpoli:1,dir:1,directori:1,discoveri:1,disk:1,distribut:1,divergence_plot:1,dloglik:1,doe:1,doksum:1,duation:1,durat:1,each:1,effect:1,either:1,ell:1,ell_1:1,ell_d:1,ell_i:1,endpoint:1,entri:1,enviorn:1,environ:[],error:1,estim:1,evalu:1,exampl:1,examplenii:1,execut:1,execute_nm:1,exp:1,exp_var:1,expans:1,explain:1,explained_var:1,explainedvar:1,explicit:1,exponenti:1,expv:1,extend:1,extra_argu:1,extreme_value_prob:1,extreme_value_prob_fit:1,fail:1,fals:1,fdr:1,fdr_thr:1,featur:1,field:1,file:1,file_extens:1,file_stem:1,file_typ:1,fileio:1,filenam:1,fit:1,fold:1,folder:1,follow:1,format:1,formul:1,forward:1,from:1,full:1,func:1,gassian:1,gaussian:1,gener:1,get_arg:1,get_n_param:1,given:1,gpml:1,gpr:1,gprrfa:1,gradient:1,group:1,grp_id_test:1,grp_id_train:1,has:1,have:1,hbr:1,hetero_gaussian:1,http:1,hyp0:1,hyp:1,hyperbol:1,hyperparamet:1,hyperparmat:1,identifi:1,imag:1,implement:1,independ:1,index:0,indic:1,inform:1,input:1,integ:1,interest:1,intermedi:1,intern:1,interpol:1,interv:1,intialis:1,invers:1,invf:1,isigma:1,itself:1,jasa:1,job:1,job_id:1,job_nam:1,job_path:1,jone:1,just:1,keep:1,kia:1,knot:1,kwarg:1,lambda:1,lambda_a:1,lamda:1,larg:1,latent:1,lbfg:1,learn:1,length:1,lengthscal:1,likelihood:1,limit:1,line:1,linear:1,list:1,load:1,load_ascii:1,load_cifti:1,load_data:1,load_nifti:1,load_pd:1,load_response_var:1,log:1,log_ell_d:1,log_path:1,logdir:1,loglik:1,loss:1,machin:1,mai:1,main:1,make:1,manual:1,map:1,margin:1,marquand:1,mask:1,maskfil:1,maskvol:1,matric:1,matrix:1,mean:1,median:1,memori:1,mere:1,metadata:1,method:1,metric:1,mll:1,model:1,model_path:1,model_select:1,modul:0,mostli:1,mother:1,motherfunct:[],msll:1,much:1,multipl:1,must:1,n_feat:1,n_featur:1,n_grp:1,n_iter:1,n_sampl:1,name:1,necessari:[],neg:1,negloglik:1,neuroimag:1,nifti:1,nknot:1,nois:1,noise_vari:1,non:1,none:1,norm:1,normative_parallel:1,normative_path:1,notat:1,note:1,npm:1,npm_thr:1,nte:1,number:1,numpi:1,object:1,onc:1,one:1,onli:1,optim:1,optimis:1,option:1,order:1,ordinari:1,otherwis:1,ouptut:1,ouput:1,output:1,output_path:1,outputal:1,outputsuffix:1,over:1,p_valu:1,page:0,parallel:1,param:1,paramet:1,parametr:1,pars:1,particular:[],pass:1,path:1,pathfor:1,pattern:1,pcntoolkit:1,pearson:1,perc:1,percentil:1,pewsei:1,pii:1,pkl:1,plot:1,polynomi:1,posit:1,possibl:1,post:1,posterior:1,pre:1,precis:1,pred_interv:1,predict:1,prepar:1,prho:1,primarili:1,prior:1,process:1,processing_dir:1,provid:1,python:1,python_path:1,qsub:1,qsub_nm:1,quantiti:1,random:1,random_st:1,rasmussen:1,rate:1,ravel_2d:1,recognit:1,refer:1,regress:1,relev:1,report:1,requir:1,rerun:1,rerun_nm:1,reshap:1,respect:1,respfil:1,respfile_path:1,respon:1,respons:1,responsefil:1,result:1,rfa:1,rho:1,rio:1,rmse:1,rmtmp:1,root:1,routin:1,row:1,run:1,s0893608019301856:1,same:1,sampl:1,save:1,save_ascii:1,save_cifti:1,save_nifti:1,save_path:1,save_pd:1,save_result:1,saveoutput:1,scalar:1,scheme:1,scienc:1,sciencedirect:1,scikit:1,scipt:1,score:1,script:1,script_command:1,search:0,second:1,see:1,self:1,sesst:[],set:1,sf2:1,should:1,sigma:1,sigma_a:1,sign:1,signal:1,signific:1,simul:1,simulate_data:1,sin:1,singl:1,sinh:1,size:1,sklearn:1,smse:1,sn2:1,sort_nic:1,sourc:1,space:1,specif:1,specifi:1,spline:1,split:1,split_nm:1,springer:1,squar:1,squared_dist:1,standard:1,standardis:1,start:1,state:1,step:1,store:1,string:1,strutur:1,sub:1,subject:1,submiss:1,submit:1,sum:1,support:1,surfac:1,synthet:1,system:1,tab:1,take:1,target:1,tes:1,test:1,testcov:1,testcovfile_path:1,testresp:1,testrespfile_path:1,testrespons:1,text:1,theparticular:1,theta:1,thi:1,thoma:1,those:1,threshold_npm:1,thu:1,tol:1,toolbox:1,torab:1,torqu:1,train:1,train_mean:1,train_var:1,transfer:1,transform:1,trbefil:1,trend:1,trendcoeff:1,trendsurf:1,tryint:1,two:1,txt:1,type:1,under:1,unravel_2d:1,updat:1,usag:1,use:1,used:1,useful:1,uses:1,using:1,util:1,valid:1,valu:1,var_group:1,var_groups_test:1,variabl:1,varianc:1,vector:1,verbos:1,vol2vec:1,vol:1,volatla:1,voxel:1,warp:1,warp_predict:1,warpaffin:1,warpbas:1,warpboxcox:1,warpcompos:1,warpnam:1,warpsinarcsinh:1,when:1,where:1,which:1,william:1,wise:1,witten:1,wolfer:1,work:[],working_dir:1,wrap:1,wrapper:1,write:1,write_nii:1,written:1,www:1,x_test:1,x_train:1,xcov:1,xmax:1,xmin:1,y_test:1,y_train:1,yhat:1,yield:1,ylim:1,your:[],ypred:1,ypred_var:1,ys2:1,ytrue:1,ytrue_sig:1,zero:1},titles:["Predictive Clinical Neuroscience toolkit","Module Index"],titleterms:{clinic:0,index:1,indic:0,method:[],modul:1,neuroimag:[],neurosci:0,predict:0,spatial:[],tabl:0,toolkit:0}}) \ No newline at end of file +Search.setIndex({docnames:["index","modindex"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst","modindex.rst"],objects:{"":{bayesreg:[1,0,0,"-"],fileio:[1,0,0,"-"],gp:[1,0,0,"-"],normative:[1,0,0,"-"],normative_parallel:[1,0,0,"-"],rfa:[1,0,0,"-"],trendsurf:[1,0,0,"-"],utils:[1,0,0,"-"]},"bayesreg.BLR":{dloglik:[1,2,1,""],estimate:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"gp.CovBase":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovLin":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSqExp":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSqExpARD":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.CovSum":{cov:[1,2,1,""],dcov:[1,2,1,""],get_n_params:[1,2,1,""]},"gp.GPR":{dloglik:[1,2,1,""],estimate:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"rfa.GPRRFA":{dloglik:[1,2,1,""],estimate:[1,2,1,""],get_n_params:[1,2,1,""],loglik:[1,2,1,""],post:[1,2,1,""],predict:[1,2,1,""]},"utils.CustomCV":{split:[1,2,1,""]},"utils.WarpAffine":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpBase":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpBoxCox":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpCompose":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},"utils.WarpSinArcsinh":{df:[1,2,1,""],f:[1,2,1,""],get_n_params:[1,2,1,""],invf:[1,2,1,""],warp_predictions:[1,2,1,""]},bayesreg:{BLR:[1,1,1,""]},fileio:{alphanum_key:[1,3,1,""],create_mask:[1,3,1,""],file_extension:[1,3,1,""],file_stem:[1,3,1,""],file_type:[1,3,1,""],load:[1,3,1,""],load_ascii:[1,3,1,""],load_cifti:[1,3,1,""],load_nifti:[1,3,1,""],load_pd:[1,3,1,""],predictive_interval:[1,3,1,""],save:[1,3,1,""],save_ascii:[1,3,1,""],save_cifti:[1,3,1,""],save_nifti:[1,3,1,""],save_pd:[1,3,1,""],sort_nicely:[1,3,1,""],tryint:[1,3,1,""],vol2vec:[1,3,1,""]},gp:{CovBase:[1,1,1,""],CovLin:[1,1,1,""],CovSqExp:[1,1,1,""],CovSqExpARD:[1,1,1,""],CovSum:[1,1,1,""],GPR:[1,1,1,""]},normative:{estimate:[1,3,1,""],evaluate:[1,3,1,""],extend:[1,3,1,""],fit:[1,3,1,""],get_args:[1,3,1,""],load_response_vars:[1,3,1,""],main:[1,3,1,""],predict:[1,3,1,""],save_results:[1,3,1,""],transfer:[1,3,1,""]},normative_parallel:{bashwrap_nm:[1,3,1,""],collect_nm:[1,3,1,""],delete_nm:[1,3,1,""],execute_nm:[1,3,1,""],qsub_nm:[1,3,1,""],rerun_nm:[1,3,1,""],sbatch_nm:[1,3,1,""],sbatchwrap_nm:[1,3,1,""],split_nm:[1,3,1,""]},rfa:{GPRRFA:[1,1,1,""]},trendsurf:{create_basis:[1,3,1,""],estimate:[1,3,1,""],get_args:[1,3,1,""],load_data:[1,3,1,""],main:[1,3,1,""],write_nii:[1,3,1,""]},utils:{CustomCV:[1,1,1,""],FDR:[1,3,1,""],WarpAffine:[1,1,1,""],WarpBase:[1,1,1,""],WarpBoxCox:[1,1,1,""],WarpCompose:[1,1,1,""],WarpSinArcsinh:[1,1,1,""],bashwrap:[1,3,1,""],calibration_error:[1,3,1,""],compute_MSLL:[1,3,1,""],compute_pearsonr:[1,3,1,""],create_bspline_basis:[1,3,1,""],create_poly_basis:[1,3,1,""],divergence_plot:[1,3,1,""],explained_var:[1,3,1,""],extreme_value_prob:[1,3,1,""],extreme_value_prob_fit:[1,3,1,""],load_freesurfer_measure:[1,3,1,""],qsub:[1,3,1,""],ravel_2D:[1,3,1,""],simulate_data:[1,3,1,""],squared_dist:[1,3,1,""],threshold_NPM:[1,3,1,""],unravel_2D:[1,3,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:function"},terms:{"001":1,"025":1,"100":1,"118":1,"1981":1,"2006":1,"2009":1,"2017":1,"2019":1,"4gb":1,"500mb":1,"975":1,"abstract":1,"boolean":1,"case":1,"class":1,"default":1,"function":1,"int":1,"new":1,"return":1,"true":1,For:1,That:1,The:1,These:1,Using:1,_estim:1,abs:1,accord:1,account:1,accross:1,adapt:1,add:1,added:1,affin:1,after:1,alg:1,algorithm:1,all:1,allow:1,alpha:1,alphanum_kei:1,also:1,altern:1,ani:1,appli:1,approach:1,appropri:1,approxim:1,arcsin:1,arcsinh:1,ard:1,area:1,arg:1,argument:1,arrai:1,articl:1,ascii:1,aseg:1,assum:1,atla:1,automat:1,averag:1,base:1,bash:1,bash_environ:1,bashwrap:1,bashwrap_nm:1,basi:1,basic:1,batch:1,batch_siz:1,bayesian:1,bayesreg:1,below:1,beta:1,between:1,bicken:1,binari:1,biometrika:1,bishop:1,blr:1,both:1,box:1,brain:1,bspline:1,cal_level:1,calibration_error:1,can:1,cell:1,cfold:1,check:1,cifti:1,cluster:1,coef:1,coeffici:1,collect:1,collect_nm:1,column:1,com:1,combin:1,command:1,common:1,compat:1,composit:1,composition:1,comput:1,compute_msl:1,compute_pearsonr:1,configparam:1,configur:1,conjug:1,contain:1,content:0,control:1,convenent:1,correl:1,cortic:1,count:1,cov:1,cov_forward:1,covari:1,covariat:1,covbas:1,covfil:1,covfile_path:1,covfunc:1,covfuncnam:1,covfunct:1,covlin:1,covsqexp:1,covsqexpard:1,covsum:1,cox:1,creat:1,create_basi:1,create_bspline_basi:1,create_mask:1,create_poly_basi:1,creation:1,cross:1,cubic:1,current:1,curvatur:1,curvind:1,custer:1,custom:1,customcv:1,cv_fold:1,cvfold:1,dat:1,data:1,data_arrai:1,data_path:1,datafil:1,datafram:1,datafrma:1,dataset:1,dcov:1,decid:1,defaul:1,defin:1,degre:1,delet:1,delete_nm:1,delimit:1,depend:1,deriv:1,design:1,desir:1,destrieux:1,determin:1,devianc:1,deviat:1,diag:1,diagon:1,differ:1,dimension:1,diment:1,dimpoli:1,dir:1,directori:1,discoveri:1,disk:1,distribut:1,divergence_plot:1,dloglik:1,doe:1,doksum:1,duation:1,durat:1,each:1,effect:1,either:1,ell:1,ell_1:1,ell_d:1,ell_i:1,endpoint:1,entri:1,enviorn:1,environ:[],epsilon:1,error:1,estim:1,evalu:1,exampl:1,examplenii:1,execut:1,execute_nm:1,exp:1,exp_var:1,expans:1,explain:1,explained_var:1,explainedvar:1,explicit:1,exponenti:1,expv:1,extend:1,extra_argu:1,extreme_value_prob:1,extreme_value_prob_fit:1,fail:1,fals:1,fdr:1,fdr_thr:1,featur:1,field:1,file:1,file_extens:1,file_stem:1,file_typ:1,fileio:1,filenam:1,fit:1,fold:1,folder:1,foldind:1,follow:1,format:1,formul:1,forward:1,freesurefr:1,freesurf:1,from:1,full:1,func:1,gari:1,gassian:1,gauscurv:1,gaussian:1,gener:1,get_arg:1,get_n_param:1,given:1,gpml:1,gpr:1,gprrfa:1,gradient:1,grayvol:1,group:1,grp_id_test:1,grp_id_train:1,has:1,have:1,hbr:1,hetero_gaussian:1,howev:1,http:1,hyp0:1,hyp:1,hyperbol:1,hyperparamet:1,hyperparmat:1,identifi:1,imag:1,implement:1,includ:1,independ:1,index:0,indic:1,inform:1,input:1,instal:1,integ:1,integr:1,interest:1,intermedi:1,intern:1,interpol:1,interv:1,intialis:1,intrins:1,invers:1,invf:1,isigma:1,itself:1,jasa:1,job:1,job_id:1,job_nam:1,job_path:1,jone:1,just:1,keep:1,kia:1,knot:1,kurtosi:1,kwarg:1,lambda:1,lambda_a:1,lamda:1,larg:1,latent:1,lbfg:1,learn:1,length:1,lengthscal:1,leptokurt:1,likelihood:1,limit:1,line:1,linear:1,list:1,load:1,load_ascii:1,load_cifti:1,load_data:1,load_freesurfer_measur:1,load_nifti:1,load_pd:1,load_response_var:1,log:1,log_ell_d:1,log_path:1,logdir:1,loglik:1,loss:1,machin:1,mai:1,main:1,make:1,manual:1,map:1,margin:1,marquand:1,mask:1,maskfil:1,maskvol:1,match:1,matric:1,matrix:1,matter:1,mean:1,meancurv:1,measur:1,median:1,memori:1,mere:1,mesokurt:1,metadata:1,method:1,metric:1,miss:1,missing_sub:1,mll:1,model:1,model_path:1,model_select:1,modul:0,more:1,mostli:1,mother:1,motherfunct:[],msll:1,much:1,multipl:1,must:1,n_feat:1,n_featur:1,n_grp:1,n_iter:1,n_sampl:1,name:1,necessari:[],neg:1,negloglik:1,network:1,neural:1,neuroimag:1,nifti:1,nknot:1,nois:1,noise_vari:1,non:1,none:1,norm:1,normative_parallel:1,normative_path:1,notat:1,note:1,npm:1,npm_thr:1,nte:1,number:1,numpi:1,numvert:1,object:1,onc:1,one:1,onli:1,optim:1,optimis:1,option:1,order:1,ordinari:1,otherwis:1,ouptut:1,ouput:1,output:1,output_path:1,outputal:1,outputsuffix:1,over:1,p_valu:1,packeag:1,page:0,panda:1,parallel:1,param:1,paramet:1,parameteris:1,parametr:1,parametris:1,pars:1,particular:[],pass:1,path:1,pathfor:1,pattern:1,pcntoolkit:1,pearson:1,perc:1,percentil:1,pewsei:1,pii:1,pkl:1,platykurt:1,plot:1,polynomi:1,posit:1,possibl:1,post:1,posterior:1,pre:1,precis:1,pred_interv:1,predict:1,predictive_interv:1,prepar:1,prho:1,primarili:1,prior:1,process:1,processing_dir:1,provid:1,pythin:1,python:1,python_path:1,qsub:1,qsub_nm:1,quantiti:1,random:1,random_st:1,rasmussen:1,rate:1,ravel_2d:1,recognit:1,rectifi:1,refer:1,regress:1,relev:1,report:1,requir:1,rerun:1,rerun_nm:1,reshap:1,respect:1,respfil:1,respfile_path:1,respon:1,respons:1,responsefil:1,result:1,retriev:1,rfa:1,rho:1,rio:1,rmse:1,rmtmp:1,root:1,routin:1,row:1,run:1,s0893608019301856:1,s2_forward:1,same:1,sampl:1,save:1,save_ascii:1,save_cifti:1,save_nifti:1,save_path:1,save_pd:1,save_result:1,saveoutput:1,sbatch_nm:1,sbatchwrap_nm:1,scalar:1,scheme:1,scienc:1,sciencedirect:1,scikit:1,scipt:1,score:1,script:1,script_command:1,search:0,second:1,see:1,segment:1,self:1,sesst:[],set:1,sf2:1,should:1,sigma:1,sigma_a:1,sign:1,signal:1,signific:1,simul:1,simulate_data:1,sin:1,singl:1,sinh:1,size:1,skew:1,sklearn:1,smse:1,sn2:1,sort_nic:1,sourc:1,space:1,specif:1,specifi:1,spline:1,split:1,split_nm:1,springer:1,squar:1,squared_dist:1,standard:1,standardis:1,start:1,stat:1,state:1,statist:1,std:1,step:1,store:1,string:1,strutur:1,sub:1,subcort:1,subcortical_volum:1,subject:1,subjects_list:1,submiss:1,submit:1,sum:1,support:1,surfac:1,surfarea:1,symmetr:1,synthet:1,system:1,tab:1,take:1,target:1,tes:1,test:1,testcov:1,testcovfile_path:1,testresp:1,testrespfile_path:1,testrespons:1,text:1,theparticular:1,theta:1,thi:1,thickavg:1,thickstd:1,thinck:1,thoma:1,those:1,threshold_npm:1,thu:1,tol:1,toolbox:1,torab:1,torqu:1,train:1,train_mean:1,train_var:1,transfer:1,transform:1,trbefil:1,trend:1,trendcoeff:1,trendsurf:1,tryint:1,two:1,txt:1,type:1,under:1,unravel_2d:1,updat:1,usag:1,use:1,used:1,useful:1,uses:1,using:1,util:1,valid:1,valu:1,var_group:1,var_groups_test:1,variabl:1,varianc:1,vector:1,verbos:1,vertic:1,vol2vec:1,vol:1,volatla:1,volum:1,voxel:1,want:1,warp:1,warp_predict:1,warpaffin:1,warpbas:1,warpboxcox:1,warpcompos:1,warpnam:1,warpsinarcsinh:1,when:1,where:1,which:1,william:1,wise:1,witten:1,wolfer:1,work:1,working_dir:1,wrap:1,wrapper:1,write:1,write_nii:1,written:1,www:1,x_test:1,x_train:1,xcov:1,xmax:1,xmin:1,y_test:1,y_train:1,yhat:1,yield:1,ylim:1,your:[],ypred:1,ypred_var:1,ys2:1,ytrue:1,ytrue_sig:1,zero:1},titles:["Predictive Clinical Neuroscience toolkit","Module Index"],titleterms:{clinic:0,index:1,indic:0,method:[],modul:1,neuroimag:[],neurosci:0,predict:0,spatial:[],tabl:0,toolkit:0}}) \ No newline at end of file