docstr: Fit the SparseFascicleModel object to data.
  
  Parameters
  ----------
  data : array
      The measured signal.
  
  mask : array, optional
      A boolean array used to mark the coordinates in the data that
      should be analyzed. Has the shape `data.shape[:-1]`. Default: None,
      which implies that all points should be analyzed.
  
  num_processes : int, optional
      Split the `fit` calculation to a pool of children processes using
      joblib. This only applies to 4D `data` arrays. Default is 1,
      which does not require joblib and will run `fit` serially.
      If < 0 the maximal number of cores minus ``num_processes + 1``
      is used (enter -1 to use as many cores as possible).
      0 raises an error.
  
  parallel_backend: str, ParallelBackendBase instance or None
      Specify the parallelization backend implementation.
      Supported backends are:
      - "loky" used by default, can induce some
        communication and memory overhead when exchanging input and
        output data with the worker Python processes.
      - "multiprocessing" previous process-based backend based on
        `multiprocessing.Pool`. Less robust than `loky`.
      - "threading" is a very low-overhead backend but it suffers
        from the Python Global Interpreter Lock if the called function
        relies a lot on Python objects. "threading" is mostly useful
        when the execution bottleneck is a compiled extension that
        explicitly releases the GIL (for instance a Cython loop wrapped
        in a "with nogil" block or an expensive call to a library such
        as NumPy).
      Default: 'multiprocessing'.
  
  Returns
  -------
  SparseFascicleFit object
docstr_tok: ["Fit","the","SparseFascicleModel","object","to","data",".","Parameters","--","--","--","--","--","data",":","array","The","measured","signal",".","mask",":","array",",","optional","A","boolean","array","used","to","mark","the","coordinates","in","the","data","that","should","be","analyzed",".","Has","the","shape","`","data.shape","[",":","-1","]","`",".","Default",":","None",",","which","implies","that","all","points","should","be","analyzed",".","num_processes",":","int",",","optional","Split","the","`","fit","`","calculation","to","a","pool","of","children","processes","using","joblib",".","This","only","applies","to","4D","`","data","`","arrays",".","Default","is","1",",","which","does","not","require","joblib","and","will","run","`","fit","`","serially",".","If","<","0","the","maximal","number","of","cores","minus","``","num_processes","+","1","``","is","used","(","enter","-1","to","use","as","many","cores","as","possible",")",".","0","raises","an","error",".","parallel_backend",":","str",",","ParallelBackendBase","instance","or","None","Specify","the","parallelization","backend","implementation",".","Supported","backends","are",":","-","``","loky","''","used","by","default",",","can","induce","some","communication","and","memory","overhead","when","exchanging","input","and","output","data","with","the","worker","Python","processes",".","-","``","multiprocessing","''","previous","process-based","backend","based","on","`","multiprocessing.Pool","`",".","Less","robust","than","`","loky","`",".","-","``","threading","''","is","a","very","low-overhead","backend","but","it","suffers","from","the","Python","Global","Interpreter","Lock","if","the","called","function","relies","a","lot","on","Python","objects",".","``","threading","''","is","mostly","useful","when","the","execution","bottleneck","is","a","compiled","extension","that","explicitly","releases","the","GIL","(","for","instance","a","Cython","loop","wrapped","in","a","``","with","nogil","''","block","or","an","expensive","call","to","a","library","such","as","NumPy",")",".","Default",":","'multiprocessing","'",".","Returns","--","--","--","-","SparseFascicleFit","object"]
code: def fit(
      self,
      data,
      mask=None,
      num_processes=1,
      parallel_backend="multiprocessing",
  ):
      """
      Fit the SparseFascicleModel object to data.
  
      Parameters
      ----------
      data : array
          The measured signal.
  
      mask : array, optional
          A boolean array used to mark the coordinates in the data that
          should be analyzed. Has the shape `data.shape[:-1]`. Default: None,
          which implies that all points should be analyzed.
  
      num_processes : int, optional
          Split the `fit` calculation to a pool of children processes using
          joblib. This only applies to 4D `data` arrays. Default is 1,
          which does not require joblib and will run `fit` serially.
          If < 0 the maximal number of cores minus ``num_processes + 1``
          is used (enter -1 to use as many cores as possible).
          0 raises an error.
  
      parallel_backend: str, ParallelBackendBase instance or None
          Specify the parallelization backend implementation.
          Supported backends are:
          - "loky" used by default, can induce some
            communication and memory overhead when exchanging input and
            output data with the worker Python processes.
          - "multiprocessing" previous process-based backend based on
            `multiprocessing.Pool`. Less robust than `loky`.
          - "threading" is a very low-overhead backend but it suffers
            from the Python Global Interpreter Lock if the called function
            relies a lot on Python objects. "threading" is mostly useful
            when the execution bottleneck is a compiled extension that
            explicitly releases the GIL (for instance a Cython loop wrapped
            in a "with nogil" block or an expensive call to a library such
            as NumPy).
          Default: 'multiprocessing'.
  
      Returns
      -------
      SparseFascicleFit object
      """
  
      if mask is None:
          # Flatten it to 2D either way:
          data_in_mask = np.reshape(data, (-1, data.shape[-1]))
      else:
          # Check for valid shape of the mask
          if mask.shape != data.shape[:-1]:
              raise ValueError("Mask is not the same shape as data.")
          mask = np.array(mask, dtype=bool, copy=False)
          data_in_mask = np.reshape(data[mask], (-1, data.shape[-1]))
  
      # Fitting is done on the relative signal (S/S0):
      flat_S0 = np.mean(data_in_mask[..., self.gtab.b0s_mask], -1)
      if not flat_S0.size or not flat_S0.max():
          flat_S = np.zeros(
              data_in_mask[..., ~self.gtab.b0s_mask].shape
          )
      else:
          flat_S = (
              data_in_mask[..., ~self.gtab.b0s_mask]
              / flat_S0[..., None]
          )
      isotropic = self.isotropic(self.gtab).fit(data, mask)
      flat_params = np.zeros(
          (data_in_mask.shape[0], self.design_matrix.shape[-1])
      )
      del data_in_mask
      gc.collect()
  
      isopredict = isotropic.predict()
      if mask is None:
          isopredict = np.reshape(
              isopredict, (-1, isopredict.shape[-1])
          )
      else:
          isopredict = isopredict[mask]
  
      if not num_processes:
          num_processes = determine_num_processes(num_processes)
  
      if num_processes > 1 and has_joblib:
          with joblib.Parallel(
              n_jobs=num_processes,
              backend=parallel_backend,
              mmap_mode="r+",
          ) as parallel:
              out = parallel(
                  joblib.delayed(self._fit_solver2voxels)(
                      isopredict, vox_data, vox, True
                  )
                  for vox, vox_data in enumerate(flat_S)
              )
  
          del parallel
  
          flat_params_dict = {}
          for d in out:
              flat_params_dict.update(d)
          flat_params = np.concatenate(
              [
                  np.array(i).reshape(1, flat_params.shape[1])
                  for i in list(
                      OrderedDict(
                          sorted(
                              flat_params_dict.items(),
                              key=lambda x: int(x[0]),
                          )
                      ).values()
                  )
              ]
          )
      else:
          for vox, vox_data in enumerate(flat_S):
              flat_params[vox] = self._fit_solver2voxels(
                  isopredict, vox_data, vox, False
              )
  
      del isopredict, flat_S
      gc.collect()
  
      if mask is None:
          out_shape = data.shape[:-1] + (-1,)
          beta = flat_params.reshape(out_shape)
          S0 = flat_S0.reshape(data.shape[:-1])
      else:
          beta = np.zeros(
              data.shape[:-1] + (self.design_matrix.shape[-1],)
          )
          beta[mask, :] = flat_params
          S0 = np.zeros(data.shape[:-1])
          S0[mask] = flat_S0
  
      return SparseFascicleFit(self, beta, S0, isotropic)
  
imports: import warnings
  import numpy
  import gc
  from collections import OrderedDict
  from dipy.utils.optpkg import optional_package
  from dipy.utils.multiproc import determine_num_processes
  import dipy.core.gradients
  import dipy.core.optimize
  import dipy.sims.voxel
  import dipy.data
  from dipy.reconst.base import ReconstModel, ReconstFit
  from dipy.reconst.cache import Cache
  from dipy.core.onetime import auto_attr
label_desc: Use image node_id 4 for calling the SparseFascicleModel obj's underlying member method code with example usage: obj.fit(data, mask, num_processes, parallel_backend) and returns: SparseFascicleFit