Exemplo n.º 1
0
    def compute_precision(self, errors, remove_chance_level=True, correct_orientation=False, use_wrong_precision=True):
        '''
            Compute the precision (1./circ_std**2). Remove the chance level if desired.
        '''

        # if correct_orientation:
        #     # Correct for the fact that bars are modelled in [0, pi] and not [0, 2pi]
        #     errors = errors.copy()*2.0

        # Circular standard deviation estimate
        error_std_dev_error = utils.angle_circular_std_dev(errors)

        # Precision
        if use_wrong_precision:
            precision = 1./error_std_dev_error
        else:
            precision = 1./error_std_dev_error**2.

        if remove_chance_level:
            # Remove the chance level
            precision -= utils.compute_precision_chance(errors.size)

        if correct_orientation:
            # The obtained precision is for half angles, correct it
            precision *= 2.

        return precision
def fit(responses, target_angle, nontarget_angles=np.array([[]]), kappa=None, initialisation_method='mixed', nb_initialisations=5, debug=False, force_random_less_than=None):
  '''
        Return maximum likelihood values for a different mixture model, with:
            - 1 target Von Mises component
            - K nontarget Von Mises components
            - 1 circular uniform random component
            - Kappa fixed and set by Fisher Information. Should be provided
        Inputs in radian, in the -pi:pi range.
            - responses: Nx1
            - target_angle: Nx1
            - nontarget_angles NxK

        Modified from Bays et al 2009
    '''

  # Clean inputs
  not_nan_indices = ~np.isnan(responses)
  responses = responses[not_nan_indices]
  target_angle = target_angle[not_nan_indices]

  if nontarget_angles.size > 0:
    nontarget_angles = nontarget_angles[:, ~np.all(np.isnan(nontarget_angles), axis=0)]

    nontarget_angles = nontarget_angles[not_nan_indices]

  if kappa is None:
    # No Kappa provided, let's use the one from the Circular Std Dev. (Bound to fail for multiple items)
    kappa = utils.stddev_to_kappa_single(utils.angle_circular_std_dev(responses))

  N = float(np.sum(~np.isnan(responses)))
  K = float(nontarget_angles.shape[1])
  max_iter = 1000
  epsilon = 1e-5

  # Initial parameters
  initial_parameters_list = initialise_parameters(responses.size, K, initialisation_method, nb_initialisations)
  overall_LL = -np.inf
  LL = np.nan
  initial_i = 0
  best_mixt_target, best_mixt_random, best_mixt_nontargets = (np.nan, np.nan, np.nan)

  for (mixt_target, mixt_random, mixt_nontargets, resp_ik) in initial_parameters_list:

    if debug:
      print "New initialisation point: ", (mixt_target, mixt_random, mixt_nontargets)

    old_LL = -np.inf

    i = 0
    converged = False

    # Precompute some matrices
    error_to_target = wrap(target_angle - responses)
    error_to_nontargets = wrap(nontarget_angles - responses[:, np.newaxis])

    # EM loop
    while i < max_iter and not converged:

      # E-step
      if debug:
        print "E", i, LL, kappa, mixt_target, mixt_nontargets, mixt_random
      resp_ik[:, 0] = mixt_target * vonmisespdf(error_to_target, 0.0, kappa)
      resp_r = mixt_random/(2.*np.pi)
      if K > 0:
        resp_ik[:, 1:] = mixt_nontargets*vonmisespdf(error_to_nontargets, 0.0, kappa)
      W = np.sum(resp_ik, axis=1) + resp_r


      # Compute likelihood
      LL = np.nansum(np.log(W))
      dLL = LL - old_LL
      old_LL = LL

      if (np.abs(dLL) < epsilon):
        converged = True
        break

      # M-step
      mixt_target = np.nansum(resp_ik[:, 0]/W)/N
      mixt_nontargets = np.nansum(resp_ik[:, 1:]/W[:, np.newaxis], axis=0)/N
      mixt_random = np.nansum(resp_r/W)/N

      if force_random_less_than is not None:
        # Hacky, force mixt_random to be below this value
        mixt_random = np.min((mixt_random, force_random_less_than))

      if debug:
        print "M", i, LL, mixt_target, mixt_nontargets, mixt_random

      i += 1

    # if not converged:
    #     if debug:
    #         print "Warning, Em_circularmixture.fit() did not converge before ", max_iter, "iterations"
    #     kappa = np.nan
    #     mixt_target = np.nan
    #     mixt_nontargets = np.nan
    #     mixt_random = np.nan
    #     rw = np.nan

    if LL > overall_LL and np.isfinite(LL):
      if debug:
        print "New best!", initial_i, overall_LL, LL
      overall_LL = LL
      (best_mixt_target, best_mixt_nontargets, best_mixt_random) = (mixt_target, mixt_nontargets, mixt_random)

    initial_i += 1

  result_dict = dict(kappa=kappa, mixt_target=best_mixt_target, mixt_nontargets=best_mixt_nontargets, mixt_random=best_mixt_random, train_LL=overall_LL)

  # Compute BIC and AIC scores
  result_dict['bic'] = bic(result_dict, N)
  result_dict['aic'] = aic(result_dict)

  return result_dict