def run_experiment(dataset, algorithm, explainer):
  evaluator = ExplanationEvaluator(classifier_names=[algorithm])
  evaluator.load_datasets([dataset])
  evaluator.vectorize_and_train()
  explain_fn = None


  print 'Explainer:', explainer
  if explainer == 'lime':
    rho = 25
    kernel = lambda d: np.sqrt(np.exp(-(d**2) / rho ** 2))
    explainer = explainers.GeneralizedLocalExplainer(kernel, explainers.data_labels_distances_mapping_text, num_samples=15000, return_mean=False, verbose=False, return_mapped=True)
    explain_fn = explainer.explain_instance
  elif explainer == 'parzen':
    sigmas = {'multi_polarity_electronics': {'tree': 0.5,
    'l1logreg': 1},
    'multi_polarity_kitchen': {'tree': 0.75, 'l1logreg': 2.0},
    'multi_polarity_dvd': {'tree': 8.0, 'l1logreg': 1},
    'multi_polarity_books': {'tree': 2.0, 'l1logreg': 2.0}}

    explainer = parzen_windows.ParzenWindowClassifier()
    cv_preds = cross_val_predict(evaluator.classifiers[dataset][algorithm], evaluator.train_vectors[dataset], evaluator.train_labels[dataset])
    explainer.fit(evaluator.train_vectors[dataset], cv_preds)
    explainer.sigma = sigmas[dataset][algorithm]
    explain_fn = explainer.explain_instance
  elif explainer == 'greedy':
    explain_fn = explainers.explain_greedy
  elif explainer == 'random':
    explainer = explainers.RandomExplainer()
    explain_fn = explainer.explain_instance
  train_results, test_results = evaluator.measure_explanation_hability(explain_fn)
  out = {'train': train_results[dataset][algorithm], 'test' : test_results[dataset][algorithm]}
  # Return mean of recalls and invidivual train and test recalls
  recall = np.mean(test_results[dataset][algorithm])
  print 'Recall:', recall  
  return recall, out
def main():
    parser = argparse.ArgumentParser(description='Evaluate some explanations')
    parser.add_argument('--dataset',
                        '-d',
                        type=str,
                        required=True,
                        help='dataset name')
    parser.add_argument('--algorithm',
                        '-a',
                        type=str,
                        required=True,
                        help='algorithm_name')
    parser.add_argument('--explainer',
                        '-e',
                        type=str,
                        required=True,
                        help='explainer name')
    args = parser.parse_args()
    dataset = args.dataset
    algorithm = args.algorithm
    evaluator = ExplanationEvaluator(classifier_names=[algorithm])
    evaluator.load_datasets([dataset])
    evaluator.vectorize_and_train()
    explain_fn = None
    if args.explainer == 'lime':
        rho = 25
        kernel = lambda d: np.sqrt(np.exp(-(d**2) / rho**2))
        explainer = explainers.GeneralizedLocalExplainer(
            kernel,
            explainers.data_labels_distances_mapping_text,
            num_samples=15000,
            return_mean=False,
            verbose=False,
            return_mapped=True)
        explain_fn = explainer.explain_instance
    elif args.explainer == 'parzen':
        sigmas = {
            'multi_polarity_electronics': {
                'tree': 0.5,
                'l1logreg': 1
            },
            'multi_polarity_kitchen': {
                'tree': 0.75,
                'l1logreg': 2.0
            },
            'multi_polarity_dvd': {
                'tree': 8.0,
                'l1logreg': 1
            },
            'multi_polarity_books': {
                'tree': 2.0,
                'l1logreg': 2.0
            }
        }

        explainer = parzen_windows.ParzenWindowClassifier()
        cv_preds = sklearn.cross_validation.cross_val_predict(
            evaluator.classifiers[dataset][algorithm],
            evaluator.train_vectors[dataset], evaluator.train_labels[dataset])
        explainer.fit(evaluator.train_vectors[dataset], cv_preds)
        explainer.sigma = sigmas[dataset][algorithm]
        explain_fn = explainer.explain_instance
    elif args.explainer == 'greedy':
        explain_fn = explainers.explain_greedy
    elif args.explainer == 'random':
        explainer = explainers.RandomExplainer()
        explain_fn = explainer.explain_instance
    train_results, test_results = evaluator.measure_explanation_hability(
        explain_fn)
    print('Average test: ', np.mean(test_results[dataset][algorithm]))
    out = {
        'train': train_results[dataset][algorithm],
        'test': test_results[dataset][algorithm]
    }
    print(out)
def main():
  parser = argparse.ArgumentParser(description='Evaluate some explanations')
  parser.add_argument('--dataset', '-d', type=str, required=True,help='dataset name')
  parser.add_argument('--algorithm1', '-a1', type=str, required=True, help='algorithm_name')
  parser.add_argument('--algorithm2', '-a2', type=str, required=True, help='algorithm_name')
  parser.add_argument('--num_features', '-k', type=int, required=True, help='num features')
  parser.add_argument('--percent_untrustworthy',  '-u', type=float, required=True, help='percentage of untrustworthy features. like 0.1')
  parser.add_argument('--num_rounds', '-r', type=int, required=True, help='num rounds')
  args = parser.parse_args()
  dataset = args.dataset
  train_data, train_labels, test_data, test_labels, class_names = LoadDataset(dataset)

  vectorizer = CountVectorizer(lowercase=False, binary=True) 
  train_vectors = vectorizer.fit_transform(train_data)
  test_vectors = vectorizer.transform(test_data)
  terms = np.array(list(vectorizer.vocabulary_.keys()))
  indices = np.array(list(vectorizer.vocabulary_.values()))
  inverse_vocabulary = terms[np.argsort(indices)]

  np.random.seed(1)
  classifier_a = get_classifier(args.algorithm1, vectorizer)
  classifier_a.fit(train_vectors, train_labels)
  classifier_a_pipeline = make_pipeline(vectorizer, classifier_a)

  classifier_b = get_classifier(args.algorithm2, vectorizer)
  classifier_b.fit(train_vectors, train_labels)
  classifier_b_pipeline = make_pipeline(vectorizer, classifier_b)

  np.random.seed(1)
  untrustworthy_rounds = []
  all_features = range(train_vectors.shape[1])
  num_untrustworthy = int(train_vectors.shape[1] * args.percent_untrustworthy)
  for _ in range(args.num_rounds):
    untrustworthy_rounds.append(np.random.choice(all_features, num_untrustworthy, replace=False))
  
  rho = 25
  kernel = lambda d: np.sqrt(np.exp(-(d**2) / rho ** 2))

  # simple_LIME = explainers.GeneralizedLocalExplainer(kernel, explainers.data_labels_distances_mapping_text, num_samples=15000, return_mean=True, verbose=False, return_mapped=True)
  LIME = LimeTextExplainer(class_names=class_names, mode="classification") 

  ridge_regressor = Ridge(alpha=1, fit_intercept=True, random_state=0)
  model_regressor = Ridge(alpha=1, fit_intercept=True, random_state=0)
  regressor_requires_positive_values=False

  sigmas = {'multi_polarity_electronics': {'neighbors': 0.75, 'svm': 10.0, 'tree': 0.5,
  'logreg': 0.5, 'random_forest': 0.5, 'embforest': 0.75},
  'multi_polarity_kitchen': {'neighbors': 1.0, 'svm': 6.0, 'tree': 0.75,
  'logreg': 0.25, 'random_forest': 6.0, 'embforest': 1.0},
  'multi_polarity_dvd': {'neighbors': 0.5, 'svm': 0.75, 'tree': 8.0, 'logreg':
  0.75, 'random_forest': 0.5, 'embforest': 5.0}, 'multi_polarity_books':
  {'neighbors': 0.5, 'svm': 7.0, 'tree': 2.0, 'logreg': 1.0, 'random_forest':
  1.0, 'embforest': 3.0}, '2ng': {'neighbors': 1.0, 'svm': 6.0, 'tree': 0.75,
  'logreg': 0.25, 'random_forest': 6.0, 'embforest': 1.0}}

  random = explainers.RandomExplainer()
  exps = {}
  explainer_names = ['DiffLIME', 'ContrastLIME', 'random', 'greedy']
  for expl in explainer_names:
    exps[expl] = []

  predictions_a = classifier_a.predict(test_vectors)
  predict_probas_a = classifier_a.predict_proba(test_vectors)[:,1]
  predictions_b = classifier_b.predict(test_vectors)

  disagreements = np.array(predictions_a != predictions_b, dtype=int)

  predict_probas_b = classifier_b.predict_proba(test_vectors)[:,1]

  LARGE_NUM_OF_FEATURES=200

  for i in range(test_vectors.shape[0]):
    print(i)
    sys.stdout.flush()

    # Doesn't need to change between single-model and contrastive LIME.
    exp = random.explain_instance(test_vectors[i], 1, None, args.num_features, None)
    exps['random'].append(exp)

    # Compute Diff-LIME
    class_exp_a = LIME.explain_instance(test_data[i],
                                      classifier_a_pipeline.predict_proba,
                                      num_features=LARGE_NUM_OF_FEATURES,
                                      model_regressor=ridge_regressor)
    lime_exp_a = [(vectorizer.vocabulary_.get(w, None), weight) for w, weight in class_exp_a.as_list() if w in vectorizer.vocabulary_]
    lime_exp_a_dict = dict(lime_exp_a)
    lime_keys_a = set(lime_exp_a_dict.keys())
    lime_score_a = class_exp_a.score
    class_exp_b = LIME.explain_instance(test_data[i],
                                      classifier_b_pipeline.predict_proba,
                                      num_features=LARGE_NUM_OF_FEATURES,
                                      model_regressor=ridge_regressor)
    lime_exp_b = [(vectorizer.vocabulary_.get(w, None), weight) for w, weight in class_exp_b.as_list() if w in vectorizer.vocabulary_]
    lime_exp_b_dict = dict(lime_exp_b)
    lime_keys_b = set(lime_exp_b_dict.keys())
    lime_score_b = class_exp_b.score
    combined_lime_keys = lime_keys_a.union(lime_keys_b)
    diff_lime_exp = []
    for word_idx in combined_lime_keys:
      lime_difference = lime_exp_b_dict.get(word_idx, 0.0) - lime_exp_a_dict.get(word_idx, 0.0)
      diff_lime_exp.append((word_idx, lime_difference))
    # Sort by difference of LIMEs
    diff_lime_exp.sort(key = lambda x: np.abs(x[1]), reverse=True)
    diff_lime_exp = diff_lime_exp[:args.num_features]
    assert lime_score_a.keys() == lime_score_b.keys()
    diff_lime_score = {k: lime_score_b[k] - lime_score_a[k] for k in lime_score_a}
    exps['DiffLIME'].append((diff_lime_exp, diff_lime_score))
    
    # Compute ContrastLime

    contrastlime_class_exp = LIME.explain_instance_contrast(test_data[i],
                                      classifier_a_pipeline.predict_proba,
                                      classifier_b_pipeline.predict_proba,
                                      num_features=args.num_features,
                                      model_regressor=model_regressor,
                                      regressor_requires_positive_values=regressor_requires_positive_values)
    contrastlime_exp = [(vectorizer.vocabulary_.get(w, None), weight) for w, weight in contrastlime_class_exp.as_list() if w in vectorizer.vocabulary_]
    contrastlime_score = contrastlime_class_exp.score
    exps['ContrastLIME'].append((contrastlime_exp, contrastlime_score))

    exp = explainers.explain_contrast_greedy_martens(test_vectors[i],
                                                     disagreements[i],
                                                     classifier_a.predict_proba,
                                                     classifier_b.predict_proba,
                                                     args.num_features)
    exps['greedy'].append(exp)

  precision = {}
  recall = {}
  f1 = {}

  neg_precision = {}
  neg_recall = {}
  neg_f1 = {}

  macro_precision = {}
  macro_recall = {}
  macro_f1 = {}

  for name in explainer_names:
    precision[name] = []
    recall[name] = []
    f1[name] = []
    neg_precision[name] = []
    neg_recall[name] = []
    neg_f1[name] = []
    macro_precision[name] = []
    macro_recall[name] = []
    macro_f1[name] = []
  flipped_preds_size = []
  for untrustworthy in untrustworthy_rounds:
    t = test_vectors.copy()
    t[:, untrustworthy] = 0

    disagreement_predictions_originals = classifier_a.predict(test_vectors) != classifier_b.predict(test_vectors)
    disagreement_predictions_updated = classifier_a.predict(t) != classifier_b.predict(t)
    mistrust_idx = np.argwhere(disagreement_predictions_originals != disagreement_predictions_updated).flatten()

    print('Number of suspect predictions ', len(mistrust_idx))
    shouldnt_trust = set(mistrust_idx)
    flipped_preds_size.append(len(shouldnt_trust))
    mistrust = collections.defaultdict(lambda:set())
    trust = collections.defaultdict(lambda: set())
    trust_fn = lambda prev, curr: (prev > 0.5 and curr > 0.5) or (prev <= 0.5 and curr <= 0.5)
    trust_fn_all = lambda exp, unt: len([x[0] for x in exp if x[0] in unt]) == 0
    for i in range(test_vectors.shape[0]):
      prev_tot = predict_probas_b[i] - predict_probas_a[i]

      exp, mean = exps['DiffLIME'][i]
      assert list(mean.keys()) == [1]
      prev_tot2 = sum([np.abs(x[1]) for x in exp]) + np.abs(mean[1])
      tot = prev_tot2 - sum([np.abs(x[1]) for x in exp if x[0] in untrustworthy])
      trust['DiffLIME'].add(i) if trust_fn(tot, prev_tot) else mistrust['DiffLIME'].add(i)



      exp, mean = exps['ContrastLIME'][i]
      assert list(mean.keys()) == [1]
      prev_tot2 = sum([np.abs(x[1]) for x in exp]) + np.abs(mean[1])
      tot = prev_tot2 - sum([np.abs(x[1]) for x in exp if x[0] in untrustworthy])
      trust['ContrastLIME'].add(i) if trust_fn(tot, prev_tot) else mistrust['ContrastLIME'].add(i)


      exp = exps['random'][i]
      trust['random'].add(i) if trust_fn_all(exp, untrustworthy) else mistrust['random'].add(i)

      exp = exps['greedy'][i]
      trust['greedy'].add(i) if trust_fn_all(exp, untrustworthy) else mistrust['greedy'].add(i)

    for expl in explainer_names:
      # switching the definition
      false_positives = set(trust[expl]).intersection(shouldnt_trust)
      true_positives = set(trust[expl]).difference(shouldnt_trust)
      false_negatives = set(mistrust[expl]).difference(shouldnt_trust)
      true_negatives = set(mistrust[expl]).intersection(shouldnt_trust)

      try:
        prec= len(true_positives) / float(len(true_positives) + len(false_positives))
      except:
        prec= 0
      try:
        rec= float(len(true_positives)) / (len(true_positives) + len(false_negatives))
      except:
        rec= 0
      try:
        neg_prec= len(true_negatives) / float(len(true_negatives) + len(false_negatives))
      except:
        neg_prec= 0
      try:
        neg_rec= float(len(true_negatives)) / (len(true_negatives) + len(false_positives))
      except:
        neg_rec= 0
      precision[expl].append(prec)
      recall[expl].append(rec)
      f1z = 2 * (prec * rec) / (prec + rec) if (prec and rec) else 0
      f1[expl].append(f1z)

      neg_precision[expl].append(neg_prec)
      neg_recall[expl].append(neg_rec)
      neg_f1z = 2 * (neg_prec * neg_rec) / (neg_prec + neg_rec) if (neg_prec and neg_rec) else 0
      neg_f1[expl].append(neg_f1z)

      macro_precision[expl].append(prec)
      macro_recall[expl].append(rec)
      macro_f1[expl].append(f1z)



  print('Average number of flipped predictions:', np.mean(flipped_preds_size), '+-', np.std(flipped_preds_size))
  print('Macro Precision:')
  for expl in explainer_names:
    print(expl, np.mean(macro_precision[expl]), '+-', np.std(macro_precision[expl]), 'pvalue', sp.stats.ttest_ind(macro_precision[expl], macro_precision['ContrastLIME'])[1].round(4))
  print()
  print('Macro Recall:')
  for expl in explainer_names:
    print(expl, np.mean(macro_recall[expl]), '+-', np.std(macro_recall[expl]), 'pvalue', sp.stats.ttest_ind(macro_recall[expl], macro_recall['ContrastLIME'])[1].round(4))
  print()
  print('Macro F1:')
  for expl in explainer_names:
    print(expl, np.mean(macro_f1[expl]), '+-', np.std(macro_f1[expl]), 'pvalue', sp.stats.ttest_ind(macro_f1[expl], macro_f1['ContrastLIME'])[1].round(4))
Пример #4
0
def run_experiment(df, dataset, algorithm, num_features, percent_untrustworthy,
                   num_rounds):
    train_data, train_labels, test_data, test_labels, class_names = LoadDataset(
        dataset)
    vectorizer = CountVectorizer(lowercase=False, binary=True)
    train_vectors = vectorizer.fit_transform(train_data)
    test_vectors = vectorizer.transform(test_data)
    terms = np.array(list(vectorizer.vocabulary_.keys()))
    indices = np.array(list(vectorizer.vocabulary_.values()))
    inverse_vocabulary = terms[np.argsort(indices)]

    np.random.seed(1)
    classifier = get_classifier(algorithm, vectorizer)
    classifier.fit(train_vectors, train_labels)

    np.random.seed(1)
    untrustworthy_rounds = []
    all_features = range(train_vectors.shape[1])
    num_untrustworthy = int(train_vectors.shape[1] * percent_untrustworthy)
    for _ in range(num_rounds):
        untrustworthy_rounds.append(
            np.random.choice(all_features, num_untrustworthy, replace=False))

    rho = 25
    kernel = lambda d: np.sqrt(np.exp(-(d**2) / rho**2))
    LIME = explainers.GeneralizedLocalExplainer(
        kernel,
        explainers.data_labels_distances_mapping_text,
        num_samples=15000,
        return_mean=True,
        verbose=False,
        return_mapped=True)

    parzen = parzen_windows.ParzenWindowClassifier()
    cv_preds = sklearn.cross_validation.cross_val_predict(classifier,
                                                          train_vectors,
                                                          train_labels,
                                                          cv=5)
    parzen.fit(train_vectors, cv_preds)
    sigmas = {
        'multi_polarity_electronics': {
            'neighbors': 0.75,
            'svm': 10.0,
            'tree': 0.5,
            'logreg': 0.5,
            'random_forest': 0.5,
            'embforest': 0.75
        },
        'multi_polarity_kitchen': {
            'neighbors': 1.0,
            'svm': 6.0,
            'tree': 0.75,
            'logreg': 0.25,
            'random_forest': 6.0,
            'embforest': 1.0
        },
        'multi_polarity_dvd': {
            'neighbors': 0.5,
            'svm': 0.75,
            'tree': 8.0,
            'logreg': 0.75,
            'random_forest': 0.5,
            'embforest': 5.0
        },
        'multi_polarity_books': {
            'neighbors': 0.5,
            'svm': 7.0,
            'tree': 2.0,
            'logreg': 1.0,
            'random_forest': 1.0,
            'embforest': 3.0
        }
    }
    parzen.sigma = sigmas[dataset][algorithm]

    explainer_names = ['LIME', 'random', 'greedy', 'parzen']

    # This will store the partial results so later it can be saved in "df"
    res = {k: '' for k in ['classifier'] + explainer_names}
    res['classifier'] = algorithm

    random = explainers.RandomExplainer()
    exps = {}
    for expl in explainer_names:
        exps[expl] = []

    predictions = classifier.predict(test_vectors)
    predict_probas = classifier.predict_proba(test_vectors)[:, 1]
    for i in range(test_vectors.shape[0]):
        print i
        sys.stdout.flush()
        exp, mean = LIME.explain_instance(test_vectors[i], 1,
                                          classifier.predict_proba,
                                          num_features)
        exps['LIME'].append((exp, mean))
        exp = parzen.explain_instance(test_vectors[i], 1,
                                      classifier.predict_proba, num_features,
                                      None)
        mean = parzen.predict_proba(test_vectors[i])[1]
        exps['parzen'].append((exp, mean))

        exp = random.explain_instance(test_vectors[i], 1, None, num_features,
                                      None)
        exps['random'].append(exp)

        exp = explainers.explain_greedy_martens(test_vectors[i],
                                                predictions[i],
                                                classifier.predict_proba,
                                                num_features)
        exps['greedy'].append(exp)

    precision = {}
    recall = {}
    f1 = {}
    for name in explainer_names:
        precision[name] = []
        recall[name] = []
        f1[name] = []
    flipped_preds_size = []
    for untrustworthy in untrustworthy_rounds:
        t = test_vectors.copy()
        t[:, untrustworthy] = 0
        mistrust_idx = np.argwhere(
            classifier.predict(t) != classifier.predict(test_vectors)).flatten(
            )
        print 'Number of suspect predictions', len(mistrust_idx)
        shouldnt_trust = set(mistrust_idx)
        flipped_preds_size.append(len(shouldnt_trust))
        mistrust = collections.defaultdict(lambda: set())
        trust = collections.defaultdict(lambda: set())
        trust_fn = lambda prev, curr: (prev > 0.5 and curr > 0.5) or (
            prev <= 0.5 and curr <= 0.5)
        trust_fn_all = lambda exp, unt: len([x[0] for x in exp
                                             if x[0] in unt]) == 0
        for i in range(test_vectors.shape[0]):
            exp, mean = exps['LIME'][i]
            prev_tot = predict_probas[i]
            prev_tot2 = sum([x[1] for x in exp]) + mean
            tot = prev_tot2 - sum([x[1] for x in exp if x[0] in untrustworthy])
            trust['LIME'].add(i) if trust_fn(
                tot, prev_tot) else mistrust['LIME'].add(i)

            exp, mean = exps['parzen'][i]
            prev_tot = mean
            tot = mean - sum([x[1] for x in exp if x[0] in untrustworthy])
            trust['parzen'].add(i) if trust_fn(
                tot, prev_tot) else mistrust['parzen'].add(i)
            exp = exps['random'][i]
            trust['random'].add(i) if trust_fn_all(
                exp, untrustworthy) else mistrust['random'].add(i)

            exp = exps['greedy'][i]
            trust['greedy'].add(i) if trust_fn_all(
                exp, untrustworthy) else mistrust['greedy'].add(i)

        for expl in explainer_names:
            # switching the definition
            false_positives = set(trust[expl]).intersection(shouldnt_trust)
            true_positives = set(trust[expl]).difference(shouldnt_trust)
            false_negatives = set(mistrust[expl]).difference(shouldnt_trust)
            true_negatives = set(mistrust[expl]).intersection(shouldnt_trust)

            try:
                prec = len(true_positives) / float(
                    len(true_positives) + len(false_positives))
            except:
                prec = 0
            try:
                rec = float(len(true_positives)) / (len(true_positives) +
                                                    len(false_negatives))
            except:
                rec = 0
            precision[expl].append(prec)
            recall[expl].append(rec)
            f1z = 2 * (prec * rec) / (prec + rec) if (prec and rec) else 0
            f1[expl].append(f1z)

    print 'Average number of flipped predictions:', np.mean(
        flipped_preds_size), '+-', np.std(flipped_preds_size)
    print 'Precision:'
    for expl in explainer_names:
        print expl, np.mean(precision[expl]), '+-', np.std(
            precision[expl]), 'pvalue', sp.stats.ttest_ind(
                precision[expl], precision['LIME'])[1].round(4)
    print
    print 'Recall:'
    for expl in explainer_names:
        print expl, np.mean(recall[expl]), '+-', np.std(
            recall[expl]), 'pvalue', sp.stats.ttest_ind(
                recall[expl], recall['LIME'])[1].round(4)
    print
    print 'F1:'
    for expl in explainer_names:
        print expl, np.mean(f1[expl]), '+-', np.std(
            f1[expl]), 'pvalue', sp.stats.ttest_ind(f1[expl],
                                                    f1['LIME'])[1].round(4)
        res[expl] = str('%.2f' % np.mean(f1[expl])) + '+-' + str(
            '%.2f' % np.std(f1[expl]))

    df = df.append(res, ignore_index=True)
    return df
def main():
    parser = argparse.ArgumentParser(description='Evaluate some explanations')
    parser.add_argument('--dataset',
                        '-d',
                        type=str,
                        required=True,
                        help='dataset name')
    parser.add_argument('--output_folder',
                        '-o',
                        type=str,
                        required=True,
                        help='output folder')
    parser.add_argument('--num_features',
                        '-k',
                        type=int,
                        required=True,
                        help='num features')
    parser.add_argument('--num_rounds',
                        '-r',
                        type=int,
                        required=True,
                        help='num rounds')
    parser.add_argument('--start_id',
                        '-i',
                        type=int,
                        default=0,
                        required=False,
                        help='output start id')
    args = parser.parse_args()
    dataset = args.dataset
    train_data, train_labels, test_data, test_labels, class_names = LoadDataset(
        dataset)
    rho = 25
    kernel = lambda d: np.sqrt(np.exp(-(d**2) / rho**2))
    local = explainers.GeneralizedLocalExplainer(
        kernel,
        explainers.data_labels_distances_mapping_text,
        num_samples=15000,
        return_mean=True,
        verbose=False,
        return_mapped=True)
    # Found through cross validation
    sigmas = {
        'multi_polarity_electronics': {
            'neighbors': 0.75,
            'svm': 10.0,
            'tree': 0.5,
            'logreg': 0.5,
            'random_forest': 0.5,
            'embforest': 0.75
        },
        'multi_polarity_kitchen': {
            'neighbors': 1.0,
            'svm': 6.0,
            'tree': 0.75,
            'logreg': 0.25,
            'random_forest': 6.0,
            'embforest': 1.0
        },
        'multi_polarity_dvd': {
            'neighbors': 0.5,
            'svm': 0.75,
            'tree': 8.0,
            'logreg': 0.75,
            'random_forest': 0.5,
            'embforest': 5.0
        },
        'multi_polarity_books': {
            'neighbors': 0.5,
            'svm': 7.0,
            'tree': 2.0,
            'logreg': 1.0,
            'random_forest': 1.0,
            'embforest': 3.0
        }
    }
    parzen1 = parzen_windows.ParzenWindowClassifier()
    parzen1.sigma = sigmas[dataset]['random_forest']
    parzen2 = parzen_windows.ParzenWindowClassifier()
    parzen2.sigma = sigmas[dataset]['random_forest']
    random = explainers.RandomExplainer()

    for Z in range(args.num_rounds):
        exps1 = {}
        exps2 = {}
        explainer_names = ['lime', 'parzen', 'random', 'greedy', 'mutual']
        for expl in explainer_names:
            exps1[expl] = []
            exps2[expl] = []
        print 'Round', Z
        sys.stdout.flush()
        fake_features_z = [([.1, .2], [.1,
                                       .1], 10)]  #, ([.2, .1], [.1,.1], 10)]
        clean_train, dirty_train, clean_test = corrupt_dataset(
            fake_features_z, train_data, train_labels, test_data, test_labels)
        vectorizer = CountVectorizer(lowercase=False, binary=True)
        dirty_train_vectors = vectorizer.fit_transform(dirty_train)
        clean_train_vectors = vectorizer.transform(clean_train)
        test_vectors = vectorizer.transform(clean_test)
        terms = np.array(list(vectorizer.vocabulary_.keys()))
        indices = np.array(list(vectorizer.vocabulary_.values()))
        inverse_vocabulary = terms[np.argsort(indices)]
        tokenizer = vectorizer.build_tokenizer()
        c1 = ensemble.RandomForestClassifier(n_estimators=30, max_depth=5)
        c2 = ensemble.RandomForestClassifier(n_estimators=30, max_depth=5)
        untrustworthy = [
            i for i, x in enumerate(inverse_vocabulary) if x.startswith('FAKE')
        ]
        train_idx, test_idx = tuple(
            cross_validation.ShuffleSplit(dirty_train_vectors.shape[0], 1,
                                          0.2))[0]
        train_acc1 = train_acc2 = test_acc1 = test_acc2 = 0
        print 'Trying to find trees:'
        sys.stdout.flush()
        iteration = 0
        found_tree = True
        while np.abs(train_acc1 -
                     train_acc2) > 0.001 or np.abs(test_acc1 -
                                                   test_acc2) < 0.05:
            iteration += 1
            c1.fit(dirty_train_vectors[train_idx], train_labels[train_idx])
            c2.fit(dirty_train_vectors[train_idx], train_labels[train_idx])
            train_acc1 = accuracy_score(
                train_labels[test_idx],
                c1.predict(dirty_train_vectors[test_idx]))
            train_acc2 = accuracy_score(
                train_labels[test_idx],
                c2.predict(dirty_train_vectors[test_idx]))
            test_acc1 = accuracy_score(test_labels, c1.predict(test_vectors))
            test_acc2 = accuracy_score(test_labels, c2.predict(test_vectors))
            if iteration == 3000:
                found_tree = False
                break
        if not found_tree:
            print 'skipping iteration', Z
            continue
        print 'done'
        print 'Train acc1:', train_acc1, 'Train acc2:', train_acc2
        print 'Test acc1:', test_acc1, 'Test acc2:', test_acc2
        sys.stdout.flush()
        predictions = c1.predict(dirty_train_vectors)
        predictions2 = c2.predict(dirty_train_vectors)
        predict_probas = c1.predict_proba(dirty_train_vectors)[:, 1]
        predict_probas2 = c2.predict_proba(dirty_train_vectors)[:, 1]
        cv_preds1 = cross_validation.cross_val_predict(
            c1, dirty_train_vectors[train_idx], train_labels[train_idx], cv=5)
        cv_preds2 = cross_validation.cross_val_predict(
            c2, dirty_train_vectors[train_idx], train_labels[train_idx], cv=5)
        parzen1.fit(dirty_train_vectors[train_idx], cv_preds1)
        parzen2.fit(dirty_train_vectors[train_idx], cv_preds2)
        pp = []
        pp2 = []
        true_labels = []
        iteration = 0
        for i in test_idx:
            if iteration % 50 == 0:
                print iteration
                sys.stdout.flush()
            iteration += 1
            pp.append(predict_probas[i])
            pp2.append(predict_probas2[i])
            true_labels.append(train_labels[i])
            exp, mean = local.explain_instance(dirty_train_vectors[i], 1,
                                               c1.predict_proba,
                                               args.num_features)
            exps1['lime'].append((exp, mean))

            exp = parzen1.explain_instance(dirty_train_vectors[i], 1,
                                           c1.predict_proba, args.num_features,
                                           None)
            mean = parzen1.predict_proba(dirty_train_vectors[i])[1]
            exps1['parzen'].append((exp, mean))

            exp = random.explain_instance(dirty_train_vectors[i], 1, None,
                                          args.num_features, None)
            exps1['random'].append(exp)

            exp = explainers.explain_greedy_martens(dirty_train_vectors[i],
                                                    predictions[i],
                                                    c1.predict_proba,
                                                    args.num_features)
            exps1['greedy'].append(exp)

            # Classifier 2
            exp, mean = local.explain_instance(dirty_train_vectors[i], 1,
                                               c2.predict_proba,
                                               args.num_features)
            exps2['lime'].append((exp, mean))

            exp = parzen2.explain_instance(dirty_train_vectors[i], 1,
                                           c2.predict_proba, args.num_features,
                                           None)
            mean = parzen2.predict_proba(dirty_train_vectors[i])[1]
            exps2['parzen'].append((exp, mean))

            exp = random.explain_instance(dirty_train_vectors[i], 1, None,
                                          args.num_features, None)
            exps2['random'].append(exp)

            exp = explainers.explain_greedy_martens(dirty_train_vectors[i],
                                                    predictions2[i],
                                                    c2.predict_proba,
                                                    args.num_features)
            exps2['greedy'].append(exp)

        out = {
            'true_labels': true_labels,
            'untrustworthy': untrustworthy,
            'train_acc1': train_acc1,
            'train_acc2': train_acc2,
            'test_acc1': test_acc1,
            'test_acc2': test_acc2,
            'exps1': exps1,
            'exps2': exps2,
            'predict_probas1': pp,
            'predict_probas2': pp2
        }
        pickle.dump(
            out,
            open(
                os.path.join(
                    args.output_folder, 'comparing_%s_%s_%d.pickle' %
                    (dataset, args.num_features, Z + args.start_id)), 'w'))