# Path: crowdastro/crowd/util.py
# def majority_vote(y):
#     """Computes the majority vote of a set of crowd labels.
# 
#     y: (n_annotators, n_examples) NumPy masked array of labels.
#     -> (n_examples,) NumPy array of labels.
#     """
#     _, n_samples = y.shape
#     mv = numpy.zeros((n_samples,))
#     for i in range(n_samples):
#         labels = y[:, i]
# 
#         if labels.mask is False:
#             counter = collections.Counter(labels)
#         else:
#             counter = collections.Counter(labels[~labels.mask])
# 
#         if counter:
#             mv[i] = max(counter, key=counter.get)
#         else:
#             # No labels for this data point.
#             mv[i] = numpy.random.randint(2)  # ¯\_(ツ)_/¯
#     return mv
# 
# Path: crowdastro/crowd/util.py
# def logistic_regression(w, x):
#     """Logistic regression classifier model.
# 
#     w: Weights w. (n_features,) NumPy array
#     x: Data point x_i. (n_features,) NumPy array
#     -> float in [0, 1]
#     """
#     return scipy.special.expit(numpy.dot(x, w.T))


import logging
import numba
import numpy
import scipy.optimize
import scipy.special
import sklearn.linear_model
from crowdastro.crowd.util import majority_vote as compute_majority_vote
from crowdastro.crowd.util import logistic_regression
        w = numpy.random.normal(size=(n_annotators, n_dim))

        logging.debug('Initial a: %s', a)
        logging.debug('Initial w: %s', w)
        logging.debug('Iterating Yan method until convergence...')

        iters = 0
        while True:  # Until convergence (checked later).
            iters += 1
            logging.info('Iteration %d', iters)

            a_, w_ = self._em_step(n_samples, n_annotators, n_dim, a, w, X, Y)

            # Check convergence.
            dist = numpy.linalg.norm(a - a_) ** 2
            logging.debug('Distance: {}'.format(dist))
            if dist <= self.epsilon:
                return a_, w_

            a, w = a_, w_

    def _annotator_model(self, w, x, y, z):
        """Yan et al. (2010) Bernoulli annotator model.

        w: Annotator weights w_t. (n_dim,) NumPy array
        x: Data point x_i. (n_dim,) NumPy array
        y: Label y_i^(t). int
        z: "True" label z_i. int
        -> float in [0, 1]
        """

# Path: crowdastro/crowd/util.py
# def majority_vote(y):
#     """Computes the majority vote of a set of crowd labels.
# 
#     y: (n_annotators, n_examples) NumPy masked array of labels.
#     -> (n_examples,) NumPy array of labels.
#     """
#     _, n_samples = y.shape
#     mv = numpy.zeros((n_samples,))
#     for i in range(n_samples):
#         labels = y[:, i]
# 
#         if labels.mask is False:
#             counter = collections.Counter(labels)
#         else:
#             counter = collections.Counter(labels[~labels.mask])
# 
#         if counter:
#             mv[i] = max(counter, key=counter.get)
#         else:
#             # No labels for this data point.
#             mv[i] = numpy.random.randint(2)  # ¯\_(ツ)_/¯
#     return mv
# 
# Path: crowdastro/crowd/util.py
# def logistic_regression(w, x):
#     """Logistic regression classifier model.
# 
#     w: Weights w. (n_features,) NumPy array
#     x: Data point x_i. (n_features,) NumPy array
#     -> float in [0, 1]
#     """
#     return scipy.special.expit(numpy.dot(x, w.T))


# Path: crowdastro/crowd/yan.py
import logging
import numba
import numpy
import scipy.optimize
import scipy.special
import sklearn.linear_model
from crowdastro.crowd.util import majority_vote as compute_majority_vote
from crowdastro.crowd.util import logistic_regression

        w = numpy.random.normal(size=(n_annotators, n_dim))

        logging.debug('Initial a: %s', a)
        logging.debug('Initial w: %s', w)
        logging.debug('Iterating Yan method until convergence...')

        iters = 0
        while True:  # Until convergence (checked later).
            iters += 1
            logging.info('Iteration %d', iters)

            a_, w_ = self._em_step(n_samples, n_annotators, n_dim, a, w, X, Y)

            # Check convergence.
            dist = numpy.linalg.norm(a - a_) ** 2
            logging.debug('Distance: {}'.format(dist))
            if dist <= self.epsilon:
                return a_, w_

            a, w = a_, w_

    def _annotator_model(self, w, x, y, z):
        """Yan et al. (2010) Bernoulli annotator model.

        w: Annotator weights w_t. (n_dim,) NumPy array
        x: Data point x_i. (n_dim,) NumPy array
        y: Label y_i^(t). int
        z: "True" label z_i. int
        -> float in [0, 1]
        """

        eta = logistic_regression(w, x)