Source code for revscoring.scoring.model_info

from collections import OrderedDict

from ..errors import ModelInfoLookupError
from . import util


[docs]class ModelInfo: def __init__(self, pairs=[], default_fields=None): """ Constructs a mapping of information about a model. :class:`~revscoring.scoring.ModelInfo` objects are usually nested within each other to provide a convenient tree structure for :func:`~revscoring.scoring.ModelInfo.lookup` and :func:`~revscoring.scoring.ModelInfo.format`. """ self._data = OrderedDict(pairs) self._default_fields = set(default_fields) \ if default_fields is not None else None def __len__(self): return len(self.keys()) def __getitem__(self, key): return self._data[key] def __setitem__(self, key, value): self._data[key] = value def __contains__(self, key): try: return (key in self._data or key in ('true', 'false') and key == 'true' in self._data or int(key) in self._data) except ValueError: return False def keys(self): return self._data.keys() def get(self, key, default=None): return self._data.get(key, default) def values(self): return self._data.values() def items(self): return self._data.items() def __iter__(self): return iter(self._data) def move_to_end(self, key, last=True): return self._data.move_to_end(key, last=last)
[docs] def lookup(self, path=None): """ Looks up a specific information value based on either a string pattern or a path. For example, the pattern "stats.roc_auc.labels.true" is the same as the path ``['stats', 'roc_auc', 'labels', True]``. :Parameters: path : `str` | `list` The location of the information to lookup. """ if isinstance(path, str): path = util.parse_pattern(path) elif path is None: path = [] d = self remaining_path = list(path) # Make sure we don't overwrite the input while len(path) > 0: key = path.pop(0) d = try_key(key, d) if hasattr(d, "lookup"): return d.lookup(remaining_path) else: continue return d
[docs] def format(self, paths=None, formatting="str", **kwargs): """ Format a representation of the model information in a useful way. :Parameters: paths : `iterable` ( `str` | [`str`] ) A set of paths to use when selecting which information should formatted. Everything beneath a provided path in the tree will be formatted. E.g. `statistics.roc_auc` and `statistics` will format redundantly because `roc_auc` is already within `statistics`. Alternatively `statistics.roc_auc` and `statistics.pr_auc` will format only those two specific bits of information. formatting : "json" or "str" Which output formatting do you want? "str" returns something nice to show on the command-line. "json" returns something that will pass through :func:`json.dump` without error. """ paths = paths or [] _paths = [ util.parse_pattern(path) if isinstance(path, str) else path for path in paths] path_tree = util.treeify(_paths) if formatting == "str": return self.format_str(path_tree, **kwargs) elif formatting == "json": return self.format_json(path_tree, **kwargs) else: raise ValueError("Formatting {0} is not available for {1}." .format(formatting, self.__class__.__name__))
def format_str(self, path_tree, **kwargs): formatted = "Model Information:\n" for key in self.normalize_fields(path_tree): key_val = try_key(key, self) if hasattr(key_val, "format_str"): sub_tree = path_tree.get(key, {}) formatted += util.tab_it_in( key_val.format_str(sub_tree, **kwargs)) else: formatted += util.tab_it_in(" - {0}: {1}" .format(key, key_val)) return formatted def format_json(self, path_tree, **kwargs): d = OrderedDict() for key in self.normalize_fields(path_tree): key_val = try_key(key, self) if hasattr(key_val, "format_json"): sub_tree = path_tree.get(key, {}) d[key] = key_val.format_json(sub_tree, **kwargs) else: d[key] = key_val return d def normalize_fields(self, path_tree): if len(path_tree) > 0: yield from path_tree.keys() else: for field in self.keys(): if self._default_fields is None or \ field in self._default_fields: yield field
def try_key(key, d): try: return d[key] except KeyError: try: if key in ("true", "false"): return d[key == 'true'] else: try: return d[int(key)] except ValueError: raise ModelInfoLookupError(key) except KeyError: raise ModelInfoLookupError(key)