def test_isstring(): "test isstring" ok_(nx.isstring('1')) ok_(nx.isstring("1")) ok_(nx.isstring(u'1')) ok_(not nx.isstring(1)) ok_(not nx.isstring(1)) ok_(not nx.isstring(1.1)) ok_(not nx.isstring(True)) ok_(not nx.isstring(False)) ok_(not nx.isstring(None))
def __getitem__(self, name): "Prediction indexing is by model name(s)" if nx.isstring(name): p = Prediction(self.df[name].to_frame(name)) else: p = Prediction(self.df[name]) return p
def user_summary(self, users, round1=61, round2=None): "Summary report on user(s)" nmr_usd = nx.token_price_data(ticker='nmr')['price'] if nx.isstring(users): users = [users] df = user_summary(self.lb[round1:round2], users, nmr_usd) return df
def __getitem__(self, index): "Index by round number, list (or tuple), or slice" if isinstance(index, slice): if index.step is not None: raise ValueError("slice step size must be 1") r1, r2 = self.rounds_to_ints(index.start, index.stop) rs = list(range(r1, r2 + 1)) ts = nx.tournament_all(as_str=False) elif nx.isint(index): rs = [index] ts = nx.tournament_all(as_str=False) elif isinstance(index, list): rs, ts = zip(*index) ts = [nx.tournament_int(i) for i in ts] elif isinstance(index, tuple): if len(index) != 2: raise IndexError("tuple index must have length 2") r, t = index if not nx.isint(r): raise IndexError("first element of tuple index must be int") if not (nx.isint(t) or nx.isstring(t)): msg = "second element of tuple index must be int or str" raise IndexError(msg) rs = [r] ts = [nx.tournament_int(t)] else: raise IndexError("indexing method not supported") self.gets(rs, ts) ridx = self.df['round'].isin(rs) tidx = self.df['tournament'].isin(ts) idx = ridx & tidx df = self.df[idx] return df
def rename(self, mapper): """ Rename prediction name(s). Parameters ---------- mapper : {dict-like, str} You can rename using a dictionary with old name as key, new as value. Or, if the prediction contains a single name, then `mapper` can be a string containing the new name. Returns ------- renamed : Prediction A copy of the prediction with renames names. """ if self.df is None: raise ValueError("Cannot rename an empty prediction") names = self.names() df = self.df.copy() if nx.isstring(mapper): if len(names) != 1: msg = 'prediction contains more than one name; use dict mapper' raise ValueError(msg) pairs = self.pairs(as_str=False) pairs = [(mapper, t) for n, t in pairs] elif isinstance(mapper, dict): prs = self.pairs(as_str=False) pairs = [] for pr in prs: if pr[0] in mapper: pr = (mapper[pr[0]], pr[1]) pairs.append(pr) df.columns = pairs return Prediction(df)
def user_nmr(self, users, round1=61, round2=None): "User(s) nmr details" if nx.isstring(users): users = [users] resolution_dates = self.get_resolution_dates() df = user_nmr(self.lb[round1:round2], users, resolution_dates) return df
def rename(self, name): "Rename model in place; model is returned" if name is None: return self if not nx.isstring(name): raise ValueError('`name` must be a string') self._name = name return self
def tournament_str(tournament_int_or_str): "Convert tournament int or str to str" if nx.isstring(tournament_int_or_str): if tournament_int_or_str not in nx.tournament_names(active_only=True): raise ValueError('tournament name is unknown') return tournament_int_or_str elif nx.isint(tournament_int_or_str): return tournament_int2str(tournament_int_or_str) raise ValueError('input must be a str or int')
def tournament_str(tournament_int_or_str): """Convert tournament int or str to str""" if nx.isstring(tournament_int_or_str): if tournament_int_or_str not in nx.tournament_names(active_only=False): raise ValueError('tournament name is not recognized') return tournament_int_or_str elif nx.isint(tournament_int_or_str): return tournament_int2str(tournament_int_or_str) raise ValueError('input must be a str or int')
def tournament_str(tournament_int_or_str): "Convert tournament int or str to str" if nx.isstring(tournament_int_or_str): if tournament_int_or_str not in TOURNAMENT_NAMES: raise ValueError('tournament name is unknown') return tournament_int_or_str elif nx.isint(tournament_int_or_str): return tournament_int2str(tournament_int_or_str) raise ValueError('input must be a str or int')
def tournament_int(tournament_int_or_str): "Convert tournament int or str to int" if nx.isstring(tournament_int_or_str): return tournament_str2int(tournament_int_or_str) elif nx.isint(tournament_int_or_str): if tournament_int_or_str not in (1, 2, 3, 4, 5): raise ValueError('tournament int must be between 1 and 5') return tournament_int_or_str raise ValueError('input must be a str or int')
def tournament_int(tournament_int_or_str): "Convert tournament int or str to int" if nx.isstring(tournament_int_or_str): return tournament_str2int(tournament_int_or_str) elif nx.isint(tournament_int_or_str): numbers = nx.tournament_numbers(active_only=True) if tournament_int_or_str not in numbers: raise ValueError("`tournament_int_or_str` not recognized") return tournament_int_or_str raise ValueError('input must be a str or int')
def __getitem__(self, index): "Prediction indexing is by model pair(s)" if isinstance(index, tuple): if len(index) != 2: raise IndexError("When indexing by tuple must be length 2") if isinstance(index[0], slice): if not is_none_slice(index[0]): raise IndexError("Slces must be slice(None, None, None,)") pairs1 = self.pairs(as_str=False) elif nx.isstring(index[0]): pairs1 = self.pairs_with_name(index[0], as_str=False) else: raise IndexError("indexing method not recognized") if isinstance(index[1], slice): if not is_none_slice(index[1]): raise IndexError("Slces must be slice(None, None, None,)") pairs2 = self.pairs(as_str=False) elif nx.isint(index[1]): pairs2 = self.pairs_with_tournament(index[1], as_str=False) elif nx.isstring(index[1]): pairs2 = self.pairs_with_tournament(index[1], as_str=False) else: raise IndexError("indexing method not recognized") pairs = [] for pair in pairs1: if pair in pairs2: pairs.append(pair) p = Prediction(pd.DataFrame(data=self.df[pairs])) elif nx.isstring(index): pairs = self.pairs_with_name(index, as_str=False) p = Prediction(self.df[pairs]) else: # assume an iterable of tuple pairs idx = [] for ix in index: if len(ix) != 2: msg = "Expecting list of tuple pairs with length 2" raise IndexError(msg) idx.append((ix[0], nx.tournament_int(ix[1]))) p = Prediction(self.df[idx]) return p
def pairs_with_name(self, name, as_str=True): """List of pairs with given `name`; `name` can be str or list of str.""" if isinstance(name, list): names = name elif nx.isstring(name): names = [name] else: raise ValueError('`name` must be str or list') prs = self.pairs(as_str) pairs = [] for pr in prs: if pr[0] in names: pairs.append(pr) return pairs
def user_nmr_tax(self, users, round1=61, round2=None, price_zero_burns=True): """ User(s) nmr tax details. Price of nmr (in usd) before round 58 (i.e before nmr was traded on and exchange) is set to 0. Price of nmr for burns is optionally set to zero by default. """ if nx.isstring(users): users = [users] nmr_price = nx.nmr_resolution_price(tournament=self.tournament) resolution_dates = self.get_resolution_dates() df = user_nmr_tax(self.lb[round1:round2], users, nmr_price, resolution_dates, price_zero_burns) return df
def pairs_with_tournament(self, tournament, as_str=True): """List of pairs; `tournament` can be int, str, or list""" if isinstance(tournament, list): tournaments = [nx.tournament_int(t) for t in tournament] elif nx.isstring(tournament): tournaments = [nx.tournament_int(tournament)] elif nx.isint(tournament): tournaments = [tournament] else: raise ValueError('`tournament` must be int, str or list') prs = self.pairs(as_str=False) pairs = [] for pr in prs: if pr[1] in tournaments: if as_str: pr = (pr[0], nx.tournament_str(pr[1])) pairs.append(pr) return pairs
def whatif(lb, users, s, c): """ Profit if `users` had staked `s` and `c` in every tournament. Earnings are left in NMR instead of splitting the NMR earnings into NMR and USD. """ if isinstance(users, list): pass elif nx.isstring(users): users = [users] else: raise ValueError("`users` must be str or list (of str)") cols = ['nmr_staked', 'nmr_burn', 'nmr_earn', 'nmr_net'] df = pd.DataFrame(columns=cols) lb.insert(0, 'pass', lb['live'] < LOGLOSS_BENCHMARK) rounds = np.sort(lb['round'].unique()) for r in rounds: d = lb[lb['round'] == r] if r > 112: staked = 0 burn = 0 earn = 0 for t in nx.tournament_all(as_str=False): dt = d[d.tournament == t] if dt.shape[0] > 0: cutoff, ignore = calc_cutoff(dt) if c >= cutoff: idx = dt.user.isin(users) dti = dt[idx] idx = dti['pass'] nwin = idx.sum() nlos = (~idx & (dti['live'].notna())).sum() p = (1.0 - cutoff) / cutoff burn += nlos * s earn += nwin * s * p staked += idx.size * s net = earn - burn df.loc[r] = [staked, burn, earn, net] else: raise ValueError("`round1` must start at at least 113") df.loc['total'] = df.sum() return df
def payout_users(lb, users): "NMR and USD payouts per round for given `users`" if isinstance(users, list): pass elif nx.isstring(users): users = [users] else: raise ValueError("`users` must be str or list (of str)") cols = ['nmr_staked', 'nmr_burn', 'nmr_earn', 'usd_earn'] df = pd.DataFrame(columns=cols) rounds = np.sort(lb['round'].unique()) for r in rounds: d = lb[lb['round'] == r] idx = d.user.isin(users) d = d[idx] ds = d.sum() pay = [ds['s'], ds['nmr_burn'], ds['nmr_stake'], ds['usd_stake']] df.loc[r] = pay df.loc['total'] = df.sum() return df
def rename(self, mapper): """ Rename prediction name(s). Parameters ---------- mapper : {dict-like, str} You can rename using a dictionary with old name as key, new as value. Or, if the prediction contains a single name, then `mapper` can be a string containing the new name. Returns ------- renamed : Prediction A copy of the prediction with renames names. """ if self.df is None: raise ValueError("Cannot rename an empty prediction") if nx.isstring(mapper): if self.shape[1] != 1: raise ValueError("prediction must contain a single name") mapper = {self.names[0]: mapper} df = self.df.rename(columns=mapper, copy=True) return Prediction(df)
def run(model, splitter, tournament=None, verbosity=2): """ Run a model/tournament pair (or pairs) through a data splitter. Parameters ---------- model : nx.Model, list, tuple Prediction model to run through the splitter. Can be a list or tuple of prediction models. Model names must be unique. splitter : nx.Splitter An iterator of fit/predict data pairs. tournament : {None, int, str, list, tuple}, optional The tournament(s) to run the model through. By default (None) the model is run through all active tournaments. If a list or tuple of tournaments is given then it must must not contain duplicate tournaments. verbosity : int, optional An integer that determines verbosity. Zero is silent. Returns ------- p : nx.Prediction A prediction object containing the predictions of the specified model/tournament pairs. """ # make list of models if isinstance(model, nx.Model): models = [model] elif isinstance(model, list) or isinstance(model, tuple): models = model else: raise ValueError('`model` must be a model, list, or tuple of models') names = [m.name for m in models] if len(names) != len(set(names)): raise ValueError('`model` cannot contain duplicate names') # make list of tournaments if tournament is None: tournaments = nx.tournament_all() elif nx.isint(tournament) or nx.isstring(tournament): tournaments = [tournament] elif isinstance(tournament, list) or isinstance(tournament, tuple): tournaments = tournament else: msg = '`tournament` must be an integer, string, list, tuple, or None.' raise ValueError(msg) tournaments = [nx.tournament_str(t) for t in tournaments] if len(tournaments) != len(set(tournaments)): raise ValueError('`tournament` cannot contain duplicates') # loop over all model/tournament pairs p = nx.Prediction() for m in models: for t in tournaments: p += run_one(m, splitter, t, verbosity=verbosity) splitter.reset() splitter.reset() return p
def __getitem__(self, index): """Data indexing""" typidx = type(index) if isinstance(index, str): if index.startswith('era'): if len(index) < 4: raise IndexError('length of era string index too short') return self.era_isin([index]) else: if index in ('train', 'validation', 'test', 'live'): return self.region_isin([index]) elif index == 'tournament': return self.region_isin(TOURNAMENT_REGIONS) else: raise IndexError('string index not recognized') elif isinstance(index, slice): # step check if index.step is not None: if not nx.isint(index.step): msg = "slice step size must be None or psotive integer" raise IndexError(msg) if index.step < 1: raise IndexError('slice step must be greater than 0') step = index.step else: step = 1 ueras = self.unique_era().tolist() # start era1 = index.start idx1 = None if era1 is None: idx1 = 0 elif not nx.isstring(era1) or not era1.startswith('era'): raise IndexError("slice elements must be strings like 'era23'") if idx1 is None: idx1 = ueras.index(era1) # end era2 = index.stop idx2 = None if era2 is None: idx2 = len(ueras) - 1 elif not nx.isstring(era2) or not era2.startswith('era'): raise IndexError("slice elements must be strings like 'era23'") if idx2 is None: idx2 = ueras.index(era2) if idx1 > idx2: raise IndexError("slice cannot go from large to small era") # find eras in slice eras = [] for ix in range(idx1, idx2 + 1, step): eras.append(ueras[ix]) data = self.era_isin(eras) return data elif typidx is pd.Series or typidx is np.ndarray: return Data(self.df[index]) else: raise IndexError('indexing type not recognized')
def make_pair(self, name, tournament): """Combine `name` and `tournament` into a pair (dataframe column name)""" if not nx.isstring(name): raise ValueError("`name` must be a string") return (name, nx.tournament_int(tournament))