docs: def classify_users(X_test, model, classifier_type, meta_model, upper_cutoff):
      """
      Uses a trained model and the unlabelled features to associate users with labels.
  
      The decision is done as per scikit-learn:
      http://scikit-learn.org/stable/modules/generated/sklearn.multiclass.OneVsRestClassifier.html
      http://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC.predict
  
      Inputs:  - feature_matrix: The graph based-features in either NumPy or SciPy sparse array format.
               - model: A trained scikit-learn One-vs-All multi-label scheme of linear SVC models.
  
      Output:  - decision_weights: A NumPy array containing the distance of each user from each label discriminator.
      """
      if classifier_type == "LinearSVC":
          prediction = model.decision_function(X_test)
          # prediction = penalize_large_classes(prediction)
  
          meta_prediction = meta_model.predict(X_test)
          meta_prediction = np.rint(meta_prediction) + 1
          meta_prediction[meta_prediction > upper_cutoff] = upper_cutoff
          meta_prediction[meta_prediction < 2] = 2
  
          prediction_indices = np.argsort(prediction, axis=1)
  
          prediction_row = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_col = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_data = np.empty(int(np.sum(meta_prediction)), dtype=np.float64)
  
          nnz_counter = 0
          for i in range(X_test.shape[0]):
              jj = prediction_indices[i, -int(meta_prediction[i]):]
              dd = prediction[i, jj]
  
              prediction_row[nnz_counter:nnz_counter+int(meta_prediction[i])] = i
              prediction_col[nnz_counter:nnz_counter+int(meta_prediction[i])] = jj
              prediction_data[nnz_counter:nnz_counter+int(meta_prediction[i])] = dd
  
              nnz_counter += int(meta_prediction[i])
  
          prediction = spsp.coo_matrix((prediction_data,
                                        (prediction_row,
                                         prediction_col)),
                                       shape=prediction.shape)
  
          prediction = normalize(prediction, norm="l2", axis=0)
      elif classifier_type == "LogisticRegression":
          prediction = model.predict_proba(X_test)
          # prediction = penalize_large_classes(prediction)
  
          meta_prediction = meta_model.predict(X_test)
          meta_prediction = np.rint(meta_prediction) + 1
          meta_prediction[meta_prediction > upper_cutoff] = upper_cutoff
          meta_prediction[meta_prediction < 2] = 2
  
          prediction_indices = np.argsort(prediction, axis=1)
  
          prediction_row = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_col = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_data = np.empty(int(np.sum(meta_prediction)), dtype=np.float64)
  
          nnz_counter = 0
          for i in range(X_test.shape[0]):
              jj = prediction_indices[i, -int(meta_prediction[i]):]
              dd = prediction[i, jj]
  
              prediction_row[nnz_counter:nnz_counter+int(meta_prediction[i])] = i
              prediction_col[nnz_counter:nnz_counter+int(meta_prediction[i])] = jj
              prediction_data[nnz_counter:nnz_counter+int(meta_prediction[i])] = dd
  
              nnz_counter += int(meta_prediction[i])
  
          prediction = spsp.coo_matrix((prediction_data,
                                        (prediction_row,
                                         prediction_col)),
                                       shape=prediction.shape)
      elif classifier_type == "RandomForest":
          if issparse(X_test):
              prediction = model.predict_proba(X_test.tocsr())
          else:
              prediction = model.predict_proba(X_test)
          # prediction = penalize_large_classes(prediction)
  
          meta_prediction = meta_model.predict(X_test)
          meta_prediction = np.rint(meta_prediction) + 1
          meta_prediction[meta_prediction > upper_cutoff] = upper_cutoff
          meta_prediction[meta_prediction < 2] = 2
  
          prediction_indices = np.argsort(prediction, axis=1)
  
          prediction_row = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_col = np.empty(int(np.sum(meta_prediction)), dtype=np.int32)
          prediction_data = np.empty(int(np.sum(meta_prediction)), dtype=np.float64)
  
          nnz_counter = 0
          for i in range(X_test.shape[0]):
              jj = prediction_indices[i, -int(meta_prediction[i]):]
              dd = prediction[i, jj]
  
              prediction_row[nnz_counter:nnz_counter+int(meta_prediction[i])] = i
              prediction_col[nnz_counter:nnz_counter+int(meta_prediction[i])] = jj
              prediction_data[nnz_counter:nnz_counter+int(meta_prediction[i])] = dd
  
              nnz_counter += int(meta_prediction[i])
  
          prediction = spsp.coo_matrix((prediction_data,
                                        (prediction_row,
                                         prediction_col)),
                                       shape=prediction.shape)
      else:
          print("Invalid classifier type.")
          raise RuntimeError
  
      return prediction