# 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
        return numpy.hstack([a, w.ravel()])

    def _Q(self, params, n_dim, n_annotators, n_samples, posteriors,
           posteriors_0, x, y):
        """Maximisation step minimisation target."""
        a, w = self._unpack(params, n_dim, n_annotators)

        expectation = (
                posteriors.dot(
                        (numpy.log(self._annotator_model(w, x, y, 1) + EPS) +
                         numpy.log(logistic_regression(a, x) + EPS)).T) +
                posteriors_0.dot(
                        (numpy.log(self._annotator_model(w, x, y, 0) + EPS) +
                         numpy.log(1 - logistic_regression(a, x) + EPS)).T)
        ).sum()

        # Also need the gradients.
        dQ_da = n_annotators * (
                numpy.dot(posteriors * logistic_regression(-a, x) +
                          posteriors_0 * (logistic_regression(-a, x) - 1),
                          x))

        dQ_dw = numpy.zeros(w.shape)
        # Inefficient, but unrolled for clarity.
        # TODO(MatthewJA): Speed this up. (Numba?)
        for t in range(n_annotators):
            dQ_dw[t] += sum(
                    x[i] * posteriors[i] *
                    (logistic_regression(-w[t], x[i]) - abs(y[t, i] - 1)) +
                    x[i] * posteriors_0[i] *

# 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

        return numpy.hstack([a, w.ravel()])

    def _Q(self, params, n_dim, n_annotators, n_samples, posteriors,
           posteriors_0, x, y):
        """Maximisation step minimisation target."""
        a, w = self._unpack(params, n_dim, n_annotators)

        expectation = (
                posteriors.dot(
                        (numpy.log(self._annotator_model(w, x, y, 1) + EPS) +
                         numpy.log(logistic_regression(a, x) + EPS)).T) +
                posteriors_0.dot(
                        (numpy.log(self._annotator_model(w, x, y, 0) + EPS) +
                         numpy.log(1 - logistic_regression(a, x) + EPS)).T)
        ).sum()

        # Also need the gradients.
        dQ_da = n_annotators * (
                numpy.dot(posteriors * logistic_regression(-a, x) +
                          posteriors_0 * (logistic_regression(-a, x) - 1),
                          x))

        dQ_dw = numpy.zeros(w.shape)
        # Inefficient, but unrolled for clarity.
        # TODO(MatthewJA): Speed this up. (Numba?)
        for t in range(n_annotators):
            dQ_dw[t] += sum(
                    x[i] * posteriors[i] *
                    (logistic_regression(-w[t], x[i]) - abs(y[t, i] - 1)) +
                    x[i] * posteriors_0[i] *

                    (logistic_regression(-w[t], x[i]) - abs(y[t, i] - 0))