'Calculate approximate perplexity for data X with ability to accept
precomputed doc_topic_distr
Perplexity is defined as exp(-1. * log-likelihood per word)
Parameters
X : array-like or sparse matrix, [n_samples, n_features]
Document word matrix.
doc_topic_distr : None or array, shape=(n_samples, n_components)
Document topic distribution.
If it is None, it will be generated by applying transform on X.
Returns
score : float
Perplexity score.'

def _perplexity_precomp_distr(self, X, doc_topic_distr=None, sub_sampling=False):

    if (not hasattr(self, 'components_')):
        raise NotFittedError("no    'components_'    attribute    in    model.    Please    fit    model    first.")
    X = self._check_non_neg_array(X, 'LatentDirichletAllocation.perplexity')
    if (doc_topic_distr is None):
        doc_topic_distr = self._unnormalized_transform(X)
    else:
        (n_samples, n_components) = doc_topic_distr.shape
        if (n_samples != X.shape[0]):
            raise ValueError('Number    of    samples    in    X    and    doc_topic_distr    do    not    match.')
        if (n_components != self._n_components):
            raise ValueError('Number    of    topics    does    not    match.')
    current_samples = X.shape[0]
    bound = self._approx_bound(X, doc_topic_distr, sub_sampling)
    if sub_sampling:
        word_cnt = (X.sum() * (float(self.total_samples) / current_samples))
    else:
        word_cnt = X.sum()
    perword_bound = (bound / word_cnt)
    return np.exp(((-1.0) * perword_bound))
