def create_critical_need_topics(Data, curModel, curLP,
                                              fracKeep=0.5, 
                                              allSS=None,
                                              Kfresh=10, **kwargs):
  K = curModel.obsModel.K

  DocWordMat = Data.to_sparse_docword_matrix()

  # Build empirical distribution for each document
  # DocWordFreq : nDoc x vocab_size
  DocWordFreq_empirical = DocWordMat.toarray()
  DocWordFreq_empirical /= (1e-9 + DocWordFreq_empirical.sum(axis=1)[:,np.newaxis])

  # Build model's mixture distribution for each document
  #   Prior : nDoc x K
  #   Lik   : K x vocab_size
  Prior = np.exp(curLP['E_logPi'][:,:K])
  Lik = np.exp(curModel.obsModel.getElogphiMatrix())
  DocWordFreq_model = np.dot(Prior, Lik)
  DocWordFreq_model /= DocWordFreq_model.sum(axis=1)[:,np.newaxis]
  
  if kwargs['doVizBirth'] == 2:
    viz_missing_docwordfreq_stats(DocWordFreq_empirical, DocWordFreq_model)

  # If desired, filter out docs that are "too small"
  if kwargs['birthWordsPerDocThr'] > 0:
    wordsPerDoc = np.squeeze(np.asarray(DocWordMat.sum(axis=1)))
    bigEnoughDocIDs = np.flatnonzero(wordsPerDoc >= kwargs['birthWordsPerDocThr'])
    if len(bigEnoughDocIDs) < DocWordMat.shape[0]:
      # this can happen with targeted dataset
      DocWordFreq_empirical = DocWordFreq_empirical[bigEnoughDocIDs]
      DocWordFreq_model = DocWordFreq_model[bigEnoughDocIDs]
  

  # Rank documents in terms of KL divergence
  KLperDoc = calcKLdivergence_discrete(DocWordFreq_empirical, DocWordFreq_model)

  if kwargs['birthVerbose']:
    print '           %5.0f %5.0f %5.0f' % (5, 50, 95)
    print ' KLperDoc  %5.2f %5.2f %5.2f' % (np.percentile(KLperDoc,5),
                                            np.percentile(KLperDoc,50),
                                            np.percentile(KLperDoc,95),
                                           )

  # Construct good "missing topics" for each document
  DocWordFreq_missing = DocWordFreq_empirical - DocWordFreq_model
  DocWordFreq_missing = np.maximum(0, DocWordFreq_missing)
  #DocWordFreq_missing /= DocWordFreq_missing.sum(axis=1)[:,np.newaxis]
  #DocWordFreq_missing = DocWordFreq_missing.copy(order='F')


  if kwargs['creationroutine'].count('targetwords'):

    nDocPerWord = np.sum(DocWordFreq_missing > 0, axis=0)
    perWordScores = np.sum(DocWordFreq_missing, axis=0)

    candidateWords = np.flatnonzero(nDocPerWord >= kwargs['targetMinDocPerWord'])

    if len(candidateWords) < 2:
      raise BirthProposalError('No candidate words available.')

    # Score each candidate vocab word by how often it is "missing"
    #   and then create small list of "most missed" words
    candidateScores = perWordScores[candidateWords]
    sortIDs = np.argsort(-1 * candidateScores)    
    rankedWords = candidateWords[sortIDs][:2 * Data.nDoc]

    nTargetsPerDoc = np.sum(DocWordFreq_missing[:,rankedWords] > 0, axis=1)
    relevantDocs = np.flatnonzero(nTargetsPerDoc > kwargs['targetRelDocThr'])

    # Cluster relevant documents X into indicators Z
    #   based on their use of the ranked, targeted words
    if len(relevantDocs) < Kfresh:
      X = DocWordFreq_missing
    else:
      X = DocWordFreq_missing[relevantDocs,:]

    if X.shape[0] < Kfresh or X.ndim == 1:
      raise BirthProposalError('target data size too small.')

    _, Z = KMeansRex.RunKMeans(X[:, rankedWords], Kfresh,
                               initname='plusplus',
                               Niter=10, seed=kwargs['randstate'].randint(1000))
    Z = np.squeeze(Z)
    if Z.ndim != 1 or Z.min() != 0 or Z.max() != Kfresh - 1:
      raise BirthProposalError('Badness. Kmeans went wrong.')

    # Propose new topics from the empirical distribution
    #   of each cluster of relevant documents
    DocWordFreq_clusterctrs = np.zeros((Kfresh, Data.vocab_size))
    for k in xrange(Kfresh):
      DocWordFreq_clusterctrs[k,:] = np.sum(X[Z==k], axis=0)
  else:
    X = DocWordFreq_missing
    if X.shape[0] < Kfresh or X.ndim == 1:
      raise BirthProposalError('target data size too small.')
    DocWordFreq_clusterctrs, Z = KMeansRex.RunKMeans(X, Kfresh,
                               initname='plusplus',
                               Niter=10, seed=kwargs['randstate'].randint(1000))

  # Filter out very small clusters, replace with subclusters of biggest cluster
  if kwargs['creationFixOutliers']:
    Z = np.squeeze(Z)
    Nk, bins = np.histogram(Z, range=(0,Kfresh), bins=Kfresh)
    bigClusterID = np.argmax(Nk)
    bigDocs = np.flatnonzero(Z==bigClusterID)      
    outliers = np.flatnonzero( Nk < 3)
    for k in outliers:
      nDocToPick = np.maximum(5, len(bigDocs)/10)
      if len(bigDocs) < nDocToPick:
        Log.error("bigDocs is TOO SMALL!")
        continue 
      chosenDocs = kwargs['randstate'].choice(bigDocs, nDocToPick,
                                                     replace=False)
      DocWordFreq_clusterctrs[k,:] = X[chosenDocs].mean(axis=0)

  if kwargs['creationSmoothTopics']:
    DocWordFreq_clusterctrs /= DocWordFreq_clusterctrs.sum(axis=1)[:,np.newaxis] \
                                 + 1e-7
    nRow, nCol = DocWordFreq_clusterctrs.shape
    NearlyUniformWordFreq = np.random.rand(nRow, nCol)
    NearlyUniformWordFreq /= NearlyUniformWordFreq.sum(axis=1)[:,np.newaxis]
    DocWordFreq_clusterctrs = 0.95 * DocWordFreq_clusterctrs \
                            + 0.05 * NearlyUniformWordFreq
  else:
    DocWordFreq_clusterctrs += 1e-7
    DocWordFreq_clusterctrs /= DocWordFreq_clusterctrs.sum(axis=1)[:,np.newaxis]   

  if kwargs['doVizBirth'] == 3:
    viz_docwordfreq_sidebyside(DocWordFreq_missing, 
                               DocWordFreq_empirical,
                               block=True)
  return DocWordFreq_clusterctrs
Returns
dataset/ETHPy150Open daeilkim/refinery/refinery/bnpy/bnpy-dev/bnpy/learnalg/BirthMoveTopicModel.py/create_critical_need_topics