# The following 5 conditions vary # idf_source, stopwords_and_stemming, punctuation, words-with-hyphens import argparse import itertools import shlex import subprocess class Setting(object): def __init__(self, label, value_flag_map): self.label = label self.choice_flags = value_flag_map def get_settings(self): return self.choice_flags.keys() def get_choice(self, setting): return self.choice_flags[setting] def get_options(self): options = [] for key in self.choice_flags.keys(): options.append("{}:{}".format(self.label, key)) return options class Experiments(object): def __init__(self, qa_dataset): self.settings = {} self.combinations = [] self.qa_data = qa_dataset self.cmd_root = "python qa-data-only-idf.py {} run".format(self.qa_data) self.eval_cmd_root = "../../Anserini/eval/trec_eval.9.0/trec_eval -m map -m recip_rank -m bpref" self.rbp_cmd_root = "rbp_eval" def add_setting(self, setting): self.settings[setting.label] = setting self._setup_combinations() def _setup_combinations(self): all_settings = [] for setting in self.settings.values(): all_settings.append(setting.get_options()) self.combinations = [] for c in itertools.product(*all_settings): self.combinations.append(c) def _run_cmd(self, cmd): pargs = shlex.split(cmd) p = subprocess.Popen(pargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, \ bufsize=1, universal_newlines=True) pout, perr = p.communicate() return pout, perr def _run_eval(self): for split in ['train-all', 'raw-dev', 'raw-test']: cmd = '{} {}/{}.qrel run.{}.idfsim'.format(self.eval_cmd_root, self.qa_data, split, split) out, err = self._run_cmd(cmd) print(split, '------' ) # trec_eval scores metrics = [] scores = [] for line in str(out).split('\n'): if not line.strip().split(): continue fields = line.strip().split() metrics.append(fields[0]) scores.append(fields[-1]) # rbp_eval scores cmd = '{} {}/{}.qrel run.{}.idfsim'.format(self.rbp_cmd_root, self.qa_data, split, split) out, err = self._run_cmd(cmd) for line in str(out).split('\n'): if not line.startswith('p= 0.50'): continue metrics.append('rbp_p0.5') scores.append(' '.join(line.strip().split()[-2:])) print('\t'.join(metrics)) print('\t'.join(scores)) def run(self, indices): """ runs a particular combination of settings """ for ci in indices: combo = self.combinations[ci] print(combo) cmd_args = [] for setting_choice in combo: setting, choice = setting_choice.split(':') cmd_args.append(self.settings[setting].choice_flags[choice]) cmd = '{} {}'.format(self.cmd_root, ' '.join(cmd_args)) print(cmd) out, err = self._run_cmd(cmd) self._run_eval() def run_all(self): """ runs all experiments """ pass def list_settings(self): """ lists all settings """ for c in enumerate(self.combinations): print(c) print("--run X Y Z to run combinations number X Y Z") if __name__ == "__main__": ap = argparse.ArgumentParser(description="Lists exerimental settings and runs experiments") ap.add_argument("--list", help="lists all available experimental settings combinations", action="store_true") ap.add_argument("--run", help='runs experimenal setting combination NUMBER(s)', nargs="+", type=int) ap.add_argument("--runall", help="runs all experiments in order", action="store_true") ap.add_argument("index_path", help="required for some combination of experiments") ap.add_argument('qa_data', help="path to the QA dataset", choices=['../../Castor-data/TrecQA', '../../Castor-data/WikiQA']) args = ap.parse_args() experiments = Experiments(args.qa_data) experiments.add_setting(Setting('idf_source', { 'qa-data':'', 'corpus-index': '--index-for-corpusIDF {}'.format(args.index_path) })) experiments.add_setting(Setting('stop_stem', { 'yes':'--stop-and-stem', 'no': '' })) experiments.add_setting(Setting('punctuation', { 'keep': '', 'remove': '--stop-punct' })) experiments.add_setting(Setting('dash_words', { 'keep': '', 'split': '--dash-split' })) experiments.list_settings() if args.run: experiments.run(args.run) if args.runall: experiments.run_all()