From b0fba5e534677a2ca61ded2f16367afe81623f36 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 10 Jan 2018 18:19:07 -0500 Subject: [PATCH 01/57] inital 2to3 run --- docs/source/conf.py | 18 +++++++++--------- sportsref/decorators.py | 10 +++++----- sportsref/nba/__init__.py | 16 ++++++++-------- sportsref/nba/boxscores.py | 20 ++++++++++---------- sportsref/nba/pbp.py | 12 ++++++------ sportsref/nba/players.py | 4 ++-- sportsref/nba/seasons.py | 6 +++--- sportsref/nfl/__init__.py | 22 +++++++++++----------- sportsref/nfl/boxscores.py | 2 +- sportsref/nfl/finders/GPF.py | 26 +++++++++++++------------- sportsref/nfl/finders/PSF.py | 28 ++++++++++++++-------------- sportsref/nfl/finders/__init__.py | 16 ++++++++-------- sportsref/nfl/pbp.py | 14 +++++++------- sportsref/nfl/players.py | 12 ++++++------ sportsref/nfl/teams.py | 16 ++++++++-------- sportsref/utils.py | 29 ++++++++++++++--------------- 16 files changed, 125 insertions(+), 126 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 5c4ae71..185dae3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,18 +48,18 @@ master_doc = 'index' # General information about the project. -project = u'sportsref' -copyright = u'2016, Matt Goldberg' -author = u'Matt Goldberg' +project = 'sportsref' +copyright = '2016, Matt Goldberg' +author = 'Matt Goldberg' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'' +version = '' # The full version, including alpha/beta/rc tags. -release = u'' +release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -129,8 +129,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'sportsref.tex', u'sportsref Documentation', - u'Matt Goldberg', 'manual'), + (master_doc, 'sportsref.tex', 'sportsref Documentation', + 'Matt Goldberg', 'manual'), ] @@ -139,7 +139,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'sportsref', u'sportsref Documentation', + (master_doc, 'sportsref', 'sportsref Documentation', [author], 1) ] @@ -150,7 +150,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'sportsref', u'sportsref Documentation', + (master_doc, 'sportsref', 'sportsref Documentation', author, 'sportsref', 'One line description of project.', 'Miscellaneous'), ] diff --git a/sportsref/decorators.py b/sportsref/decorators.py index c037d89..67d2b1d 100644 --- a/sportsref/decorators.py +++ b/sportsref/decorators.py @@ -6,7 +6,7 @@ import hashlib import os import re -import urlparse +import urllib.parse import appdirs from boltons import funcutils @@ -121,7 +121,7 @@ def cacheValidFuncs(s): def wrapper(url): # hash based on the URL file_hash = hashlib.md5() - file_hash.update(url) + file_hash.update(b + url) file_hash = file_hash.hexdigest() filename = '{}/{}'.format(CACHE_DIR, file_hash) @@ -155,7 +155,7 @@ def get_class_instance_key(cls, args, kwargs): l = [id(cls)] for arg in args: l.append(id(arg)) - l.extend((k, id(v)) for k, v in kwargs.items()) + l.extend((k, id(v)) for k, v in list(kwargs.items())) return tuple(sorted(l)) @@ -192,8 +192,8 @@ def _copy(v): ret = _copy(cache[key]) return ret except TypeError: - print('memoization type error in function {} for arguments {}' - .format(fun.__name__, key)) + print(('memoization type error in function {} for arguments {}' + .format(fun.__name__, key))) raise cache = {} diff --git a/sportsref/nba/__init__.py b/sportsref/nba/__init__.py index 251a90e..d09534b 100644 --- a/sportsref/nba/__init__.py +++ b/sportsref/nba/__init__.py @@ -1,12 +1,12 @@ -import boxscores -import pbp -import seasons -import teams +from . import boxscores +from . import pbp +from . import seasons +from . import teams -from boxscores import BoxScore -from seasons import Season -from teams import Team -from players import Player +from .boxscores import BoxScore +from .seasons import Season +from .teams import Team +from .players import Player BASE_URL = 'http://www.basketball-reference.com' diff --git a/sportsref/nba/boxscores.py b/sportsref/nba/boxscores.py index 31e0d38..20f3a8e 100644 --- a/sportsref/nba/boxscores.py +++ b/sportsref/nba/boxscores.py @@ -48,7 +48,7 @@ def date(self): :returns: A datetime.date object with year, month, and day attributes. """ match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) - year, month, day = map(int, match.groups()) + year, month, day = list(map(int, match.groups())) return datetime.date(year=year, month=month, day=day) @sportsref.decorators.memoize @@ -69,8 +69,8 @@ def linescore(self): columns[0] = 'team_id' data = [ - [sportsref.utils.flatten_links(td) for td in tr('td').items()] - for tr in table('tr.thead').next_all('tr').items() + [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] + for tr in list(table('tr.thead').next_all('tr').items()) ] return pd.DataFrame(data, index=['away', 'home'], @@ -152,7 +152,7 @@ def _get_player_stats(self, table_id_fmt): # clean data and add features for i, (tm, df) in enumerate(zip(tms, dfs)): no_time = df['mp'] == 0 - stat_cols = [col for col, dtype in df.dtypes.iteritems() + stat_cols = [col for col, dtype in df.dtypes.items() if dtype != 'object'] df.loc[no_time, stat_cols] = 0 df['team_id'] = tm @@ -192,7 +192,7 @@ def pbp(self, dense_lineups=False, sparse_lineups=False): ) table = doc('table#pbp') trs = [ - tr for tr in table('tr').items() + tr for tr in list(table('tr').items()) if (not tr.attr['class'] or # regular data rows tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds ] @@ -216,7 +216,7 @@ def pbp(self, dense_lineups=False, sparse_lineups=False): # add time of play to entry t_str = row.eq(0).text() t_regex = r'(\d+):(\d+)\.(\d+)' - mins, secs, tenths = map(int, re.match(t_regex, t_str).groups()) + mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) endQ = (12 * 60 * min(cur_qtr, 4) + 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) @@ -244,11 +244,11 @@ def pbp(self, dense_lineups=False, sparse_lineups=False): # if another case, log and continue else: if not desc.text().lower().startswith('end of '): - print( + print(( '{}, Q{}, {} other case: {}' .format(self.boxscore_id, cur_qtr, t_str, desc.text()) - ) + )) continue # handle team play description @@ -274,8 +274,8 @@ def pbp(self, dense_lineups=False, sparse_lineups=False): p = orig_p new_p = new_p[1] elif new_p.get('is_error'): - print("can't parse: {}, boxscore: {}" - .format(desc, self.boxscore_id)) + print(("can't parse: {}, boxscore: {}" + .format(desc, self.boxscore_id))) # import pdb; pdb.set_trace() p.update(new_p) diff --git a/sportsref/nba/pbp.py b/sportsref/nba/pbp.py index d4ff2f2..a67eebd 100644 --- a/sportsref/nba/pbp.py +++ b/sportsref/nba/pbp.py @@ -34,7 +34,7 @@ def parse_play(boxscore_id, details, is_hm): :rtype: dictionary or None """ # if input isn't a string, return None - if not details or not isinstance(details, basestring): + if not details or not isinstance(details, str): return None bs = sportsref.nba.BoxScore(boxscore_id) @@ -495,8 +495,8 @@ def players_from_play(play): break if len(hm_starters) != 5 or len(aw_starters) != 5: - print('WARNING: wrong number of starters for a team in Q{} of {}' - .format(qtr, df.boxscore_id.iloc[0])) + print(('WARNING: wrong number of starters for a team in Q{} of {}' + .format(qtr, df.boxscore_id.iloc[0]))) return period_starters @@ -585,9 +585,9 @@ def handle_sub(row, aw_lineup, hm_lineup): ): return aw_lineup, hm_lineup # otherwise, let's print and pretend this never happened - print('ERROR IN SUB IN {}, Q{}, {}: {}' + print(('ERROR IN SUB IN {}, Q{}, {}: {}' .format(row['boxscore_id'], row['quarter'], - row['clock_time'], row['detail'])) + row['clock_time'], row['detail']))) raise return aw_lineup, hm_lineup @@ -608,7 +608,7 @@ def handle_sub(row, aw_lineup, hm_lineup): lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) # then, move on to the quarter, and enter the starting lineups cur_qtr += 1 - aw_lineup, hm_lineup = map(list, per_starters[cur_qtr-1]) + aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) lineups[i] = lineup_dict(aw_lineup, hm_lineup) # if the first play in the quarter is a sub, handle that if row['is_sub']: diff --git a/sportsref/nba/players.py b/sportsref/nba/players.py index a0cea49..122dd6c 100644 --- a/sportsref/nba/players.py +++ b/sportsref/nba/players.py @@ -65,7 +65,7 @@ def age(self, year, month=2, day=1): doc = self.get_main_doc() date_string = doc('span[itemprop="birthDate"]').attr('data-birth') regex = r'(\d{4})\-(\d{2})\-(\d{2})' - date_args = map(int, re.match(regex, date_string).groups()) + date_args = list(map(int, re.match(regex, date_string).groups())) birth_date = datetime.date(*date_args) age_date = datetime.date(year=year, month=month, day=day) delta = age_date - birth_date @@ -87,7 +87,7 @@ def height(self): doc = self.get_main_doc() raw = doc('span[itemprop="height"]').text() try: - feet, inches = map(int, raw.split('-')) + feet, inches = list(map(int, raw.split('-'))) return feet * 12 + inches except ValueError: return None diff --git a/sportsref/nba/seasons.py b/sportsref/nba/seasons.py index 93f6b79..5be3575 100644 --- a/sportsref/nba/seasons.py +++ b/sportsref/nba/seasons.py @@ -58,7 +58,7 @@ def get_team_ids(self): if not df.empty: return df.index.tolist() else: - print 'ERROR: no teams found' + print('ERROR: no teams found') return [] @sportsref.decorators.memoize @@ -75,7 +75,7 @@ def team_ids_to_names(self): team_names = unflattened['team_name'] if len(team_names) != len(team_ids): raise Exception("team names and team IDs don't align") - return dict(zip(team_ids, team_names)) + return dict(list(zip(team_ids, team_names))) @sportsref.decorators.memoize def team_names_to_ids(self): @@ -83,7 +83,7 @@ def team_names_to_ids(self): :returns: Dictionary with tean names as keys and team IDs as values. """ d = self.team_ids_to_names() - return {v: k for k, v in d.items()} + return {v: k for k, v in list(d.items())} @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) diff --git a/sportsref/nfl/__init__.py b/sportsref/nfl/__init__.py index 90f045c..16d59b3 100644 --- a/sportsref/nfl/__init__.py +++ b/sportsref/nfl/__init__.py @@ -1,15 +1,15 @@ -import finders -import teams -import players -import boxscores -import winProb -import pbp +from . import finders +from . import teams +from . import players +from . import boxscores +from . import winProb +from . import pbp -from players import Player -from seasons import Season -from teams import Team -from boxscores import BoxScore -from finders import GamePlayFinder, PlayerSeasonFinder +from .players import Player +from .seasons import Season +from .teams import Team +from .boxscores import BoxScore +from .finders import GamePlayFinder, PlayerSeasonFinder BASE_URL = 'http://www.pro-football-reference.com' diff --git a/sportsref/nfl/boxscores.py b/sportsref/nfl/boxscores.py index ef461ca..b8a33b4 100644 --- a/sportsref/nfl/boxscores.py +++ b/sportsref/nfl/boxscores.py @@ -53,7 +53,7 @@ def date(self): :returns: A datetime.date object with year, month, and day attributes. """ match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) - year, month, day = map(int, match.groups()) + year, month, day = list(map(int, match.groups())) return datetime.date(year=year, month=month, day=day) @sportsref.decorators.memoize diff --git a/sportsref/nfl/finders/GPF.py b/sportsref/nfl/finders/GPF.py index d11b037..3c6e695 100644 --- a/sportsref/nfl/finders/GPF.py +++ b/sportsref/nfl/finders/GPF.py @@ -21,7 +21,7 @@ def GamePlayFinder(**kwargs): url = '{}?{}'.format(GPF_URL, querystring) # if verbose, print url if kwargs.get('verbose', False): - print url + print(url) html = utils.get_html(url) doc = pq(html) @@ -31,7 +31,7 @@ def GamePlayFinder(**kwargs): # parse score column if 'score' in plays.columns: - oScore, dScore = zip(*plays.score.apply(lambda s: s.split('-'))) + oScore, dScore = list(zip(*plays.score.apply(lambda s: s.split('-')))) plays['teamScore'] = oScore plays['oppScore'] = dScore # add parsed pbp info @@ -50,11 +50,11 @@ def _kwargs_to_qs(**kwargs): inpOptDef = inputs_options_defaults() opts = { name: dct['value'] - for name, dct in inpOptDef.iteritems() + for name, dct in inpOptDef.items() } # clean up keys and values - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): # pID, playerID => player_id if k.lower() in ('pid', 'playerid'): del kwargs[k] @@ -91,8 +91,8 @@ def _kwargs_to_qs(**kwargs): lst = list(v) kwargs['year_min'] = min(lst) kwargs['year_max'] = max(lst) - elif isinstance(v, basestring): - v = map(int, v.split(',')) + elif isinstance(v, str): + v = list(map(int, v.split(','))) kwargs['year_min'] = min(v) kwargs['year_max'] = max(v) else: @@ -105,8 +105,8 @@ def _kwargs_to_qs(**kwargs): lst = list(v) kwargs['week_num_min'] = min(lst) kwargs['week_num_max'] = max(lst) - elif isinstance(v, basestring): - v = map(int, v.split(',')) + elif isinstance(v, str): + v = list(map(int, v.split(','))) kwargs['week_num_min'] = min(v) kwargs['week_num_max'] = max(v) else: @@ -115,7 +115,7 @@ def _kwargs_to_qs(**kwargs): # if playoff_round defined, then turn on playoff flag if k == 'playoff_round': kwargs['game_type'] = 'P' - if isinstance(v, basestring): + if isinstance(v, str): v = v.split(',') if not isinstance(v, collections.Iterable): v = [v] @@ -126,11 +126,11 @@ def _kwargs_to_qs(**kwargs): opts[k] = [] # update based on kwargs - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): # if overwriting a default, overwrite it if k in opts: # if multiple values separated by commas, split em - if isinstance(v, basestring): + if isinstance(v, str): v = v.split(',') elif not isinstance(v, collections.Iterable): v = [v] @@ -140,7 +140,7 @@ def _kwargs_to_qs(**kwargs): opts['request'] = [1] qs = '&'.join('{}={}'.format(name, val) - for name, vals in sorted(opts.iteritems()) for val in vals) + for name, vals in sorted(opts.items()) for val in vals) return qs @@ -167,7 +167,7 @@ def inputs_options_defaults(): # otherwise, we must regenerate the dict and rewrite it else: - print 'Regenerating GPFConstants file' + print('Regenerating GPFConstants file') html = utils.get_html(GPF_URL) doc = pq(html) diff --git a/sportsref/nfl/finders/PSF.py b/sportsref/nfl/finders/PSF.py index 5b77ce6..66e71b8 100644 --- a/sportsref/nfl/finders/PSF.py +++ b/sportsref/nfl/finders/PSF.py @@ -2,7 +2,7 @@ import json import os import time -import urllib +import urllib.request, urllib.parse, urllib.error from pyquery import PyQuery as pq @@ -25,7 +25,7 @@ def PlayerSeasonFinder(**kwargs): querystring = _kwargs_to_qs(**kwargs) url = '{}?{}'.format(PSF_URL, querystring) if kwargs.get('verbose', False): - print url + print(url) html = utils.get_html(url) doc = pq(html) table = doc('table#results') @@ -33,7 +33,7 @@ def PlayerSeasonFinder(**kwargs): if df.empty: break - thisSeason = zip(df.player_id, df.year) + thisSeason = list(zip(df.player_id, df.year)) playerSeasons.extend(thisSeason) if doc('*:contains("Next Page")'): @@ -53,11 +53,11 @@ def _kwargs_to_qs(**kwargs): inpOptDef = inputs_options_defaults() opts = { name: dct['value'] - for name, dct in inpOptDef.iteritems() + for name, dct in inpOptDef.items() } # clean up keys and values - for k, v in kwargs.items(): + for k, v in list(kwargs.items()): del kwargs[k] # bool => 'Y'|'N' if isinstance(v, bool): @@ -71,8 +71,8 @@ def _kwargs_to_qs(**kwargs): lst = list(v) kwargs['year_min'] = min(lst) kwargs['year_max'] = max(lst) - elif isinstance(v, basestring): - v = map(int, v.split(',')) + elif isinstance(v, str): + v = list(map(int, v.split(','))) kwargs['year_min'] = min(v) kwargs['year_max'] = max(v) else: @@ -80,7 +80,7 @@ def _kwargs_to_qs(**kwargs): kwargs['year_max'] = v # pos, position, positions => pos[] elif k.lower() in ('pos', 'position', 'positions'): - if isinstance(v, basestring): + if isinstance(v, str): v = v.split(',') elif not isinstance(v, collections.Iterable): v = [v] @@ -90,7 +90,7 @@ def _kwargs_to_qs(**kwargs): 'draft_pos', 'draftpos', 'draftposition', 'draftpositions', 'draft_position', 'draft_positions' ): - if isinstance(v, basestring): + if isinstance(v, str): v = v.split(',') elif not isinstance(v, collections.Iterable): v = [v] @@ -100,12 +100,12 @@ def _kwargs_to_qs(**kwargs): kwargs[k] = v # update based on kwargs - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): # if overwriting a default, overwrite it (with a list so the # opts -> querystring list comp works) if k in opts or k in ('pos[]', 'draft_pos[]'): # if multiple values separated by commas, split em - if isinstance(v, basestring): + if isinstance(v, str): v = v.split(',') # otherwise, make sure it's a list elif not isinstance(v, collections.Iterable): @@ -119,8 +119,8 @@ def _kwargs_to_qs(**kwargs): opts['offset'] = [kwargs.get('offset', 0)] qs = '&'.join( - '{}={}'.format(urllib.quote_plus(name), val) - for name, vals in sorted(opts.iteritems()) for val in vals + '{}={}'.format(urllib.parse.quote_plus(name), val) + for name, vals in sorted(opts.items()) for val in vals ) return qs @@ -147,7 +147,7 @@ def inputs_options_defaults(): # otherwise, we must regenerate the dict and rewrite it else: - print 'Regenerating PSFConstants file' + print('Regenerating PSFConstants file') html = utils.get_html(PSF_URL) doc = pq(html) diff --git a/sportsref/nfl/finders/__init__.py b/sportsref/nfl/finders/__init__.py index 027570c..8c758df 100644 --- a/sportsref/nfl/finders/__init__.py +++ b/sportsref/nfl/finders/__init__.py @@ -1,8 +1,8 @@ -import GPF -import PSF +from . import GPF +from . import PSF -from PSF import PlayerSeasonFinder -from GPF import GamePlayFinder +from .PSF import PlayerSeasonFinder +from .GPF import GamePlayFinder # modules/variables to expose __all__ = [ @@ -19,7 +19,7 @@ name, ','.join(dct['value']) ) - for name, dct in sorted(IOD.iteritems())) + for name, dct in sorted(IOD.items())) optsStr = '\n'.join( '{}: {}'.format( name, @@ -31,7 +31,7 @@ ','.join('"{}"'.format(opt) for opt in dct['options'][:10]), ','.join('"{}"'.format(opt) for opt in dct['options'][-2:]) ) - for name, dct in sorted(IOD.iteritems())) + for name, dct in sorted(IOD.items())) PSF.PlayerSeasonFinder.__doc__ = """ @@ -64,7 +64,7 @@ name, ','.join(dct['value']) ) - for name, dct in sorted(IOD.iteritems()) + for name, dct in sorted(IOD.items()) ) optsStr = '\n'.join( @@ -78,7 +78,7 @@ ','.join('"{}"'.format(opt) for opt in dct['options'][:10]), ','.join('"{}"'.format(opt) for opt in dct['options'][-2:]) ) - for name, dct in sorted(IOD.iteritems()) + for name, dct in sorted(IOD.items()) ) GPF.GamePlayFinder.__doc__ = """ diff --git a/sportsref/nfl/pbp.py b/sportsref/nfl/pbp.py index e7a03b9..2e3099d 100644 --- a/sportsref/nfl/pbp.py +++ b/sportsref/nfl/pbp.py @@ -27,9 +27,9 @@ def expand_details(df, detailCol='detail'): """ df = copy.deepcopy(df) df['detail'] = df[detailCol] - dicts = map(sportsref.nfl.pbp.parse_play_details, df['detail'].values) + dicts = list(map(sportsref.nfl.pbp.parse_play_details, df['detail'].values)) # clean up unmatched details - cols = {c for d in dicts if d for c in d.iterkeys()} + cols = {c for d in dicts if d for c in d.keys()} blankEntry = {c: np.nan for c in cols} newDicts = [d if d else blankEntry for d in dicts] # get details DataFrame and merge it with original to create main DataFrame @@ -60,14 +60,14 @@ def parse_play_details(details): """ # if input isn't a string, return None - if not isinstance(details, basestring): + if not isinstance(details, str): return None rushOptRE = r'(?P{})'.format( - r'|'.join(RUSH_OPTS.iterkeys()) + r'|'.join(iter(RUSH_OPTS.keys())) ) passOptRE = r'(?P{})'.format( - r'|'.join(PASS_OPTS.iterkeys()) + r'|'.join(iter(PASS_OPTS.keys())) ) playerRE = r"\S{6,8}\d{2}" @@ -465,7 +465,7 @@ def _clean_features(struct): # creating secsElapsed (in entire game) from qtr_time_remain and quarter if pd.notnull(struct.get('qtr_time_remain')): qtr = struct['quarter'] - mins, secs = map(int, struct['qtr_time_remain'].split(':')) + mins, secs = list(map(int, struct['qtr_time_remain'].split(':'))) struct['secsElapsed'] = qtr * 900 - mins * 60 - secs # creating columns for turnovers struct['isInt'] = pd.notnull(struct.get('interceptor')) @@ -488,7 +488,7 @@ def _loc_to_features(l): """ if l: - if isinstance(l, basestring): + if isinstance(l, str): l = l.strip() if ' ' in l: r = l.split() diff --git a/sportsref/nfl/players.py b/sportsref/nfl/players.py index 4190e87..23a4fcd 100644 --- a/sportsref/nfl/players.py +++ b/sportsref/nfl/players.py @@ -3,7 +3,7 @@ import datetime import re -import urlparse +import urllib.parse import numpy as np from pyquery import PyQuery as pq @@ -40,12 +40,12 @@ def __reduce__(self): def _subpage_url(self, page, year=None): # if no year, return career version if year is None: - return urlparse.urljoin( + return urllib.parse.urljoin( self.mainURL, '{}/{}/'.format(self.player_id, page) ) # otherwise, return URL for a given year else: - return urlparse.urljoin( + return urllib.parse.urljoin( self.mainURL, '{}/{}/{}/'.format(self.player_id, page, year) ) @@ -68,7 +68,7 @@ def age(self, year, month=9, day=1): try: dateargs = re.match(r'(\d{4})\-(\d{2})\-(\d{2})', birthstring).groups() - dateargs = map(int, dateargs) + dateargs = list(map(int, dateargs)) birthDate = datetime.date(*dateargs) delta = datetime.date(year=year, month=month, day=day) - birthDate age = delta.days / 365. @@ -93,7 +93,7 @@ def height(self): doc = self.get_doc() rawText = doc('div#meta p span[itemprop="height"]').text() try: - feet, inches = map(int, rawText.split('-')) + feet, inches = list(map(int, rawText.split('-'))) return feet * 12 + inches except ValueError: return None @@ -355,7 +355,7 @@ def _simple_year_award(self, award_id): """ doc = self.get_doc() table = doc('div#leaderboard_{} table'.format(award_id)) - return map(int, sportsref.utils.parse_awards_table(table)) + return list(map(int, sportsref.utils.parse_awards_table(table))) diff --git a/sportsref/nfl/teams.py b/sportsref/nfl/teams.py index 018feda..cc3882e 100644 --- a/sportsref/nfl/teams.py +++ b/sportsref/nfl/teams.py @@ -33,9 +33,9 @@ def team_names(year): df = pd.concat((active_df, inactive_df)) df = df.loc[~df['has_class_partial_table']] ids = df.team_id.str[:3].values - names = [tr('th a') for tr in active_table('tr').items()] - names.extend(tr('th a') for tr in inactive_table('tr').items()) - names = filter(None, names) + names = [tr('th a') for tr in list(active_table('tr').items())] + names.extend(tr('th a') for tr in list(inactive_table('tr').items())) + names = [_f for _f in names if _f] names = [lst[0].text_content() for lst in names] # combine IDs and team names into pandas series series = pd.Series(names, index=ids) @@ -54,7 +54,7 @@ def team_ids(year): :returns: A dictionary with full team name keys and teamID values. """ names = team_names(year) - return {v: k for k, v in names.iteritems()} + return {v: k for k, v in names.items()} @sportsref.decorators.memoize @@ -64,7 +64,7 @@ def list_teams(year): :year: The year of the season in question (as an int). :returns: A list of team IDs. """ - return team_names(year).keys() + return list(team_names(year).keys()) class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): @@ -206,7 +206,7 @@ def head_coaches_by_game(self, year): coachAndTenure.append((coachID, tenure)) coachIDs = [ - cID for cID, games in coachAndTenure for _ in xrange(games) + cID for cID, games in coachAndTenure for _ in range(games) ] return np.array(coachIDs[::-1]) @@ -398,7 +398,7 @@ def off_splits(self, year): """ doc = self.get_year_doc('{}_splits'.format(year)) tables = doc('table.stats_table') - dfs = [sportsref.utils.parse_table(table) for table in tables.items()] + dfs = [sportsref.utils.parse_table(table) for table in list(tables.items())] dfs = [ df.assign(split=df.columns[0]) .rename(columns={df.columns[0]: 'split_value'}) @@ -418,7 +418,7 @@ def def_splits(self, year): """ doc = self.get_year_doc('{}_opp_splits'.format(year)) tables = doc('table.stats_table') - dfs = [sportsref.utils.parse_table(table) for table in tables.items()] + dfs = [sportsref.utils.parse_table(table) for table in list(tables.items())] dfs = [ df.assign(split=df.columns[0]) .rename(columns={df.columns[0]: 'split_value'}) diff --git a/sportsref/utils.py b/sportsref/utils.py index ff31cf4..e900dd4 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -70,8 +70,7 @@ def parse_table(table, flatten=True, footer=False): # get data rows = list(table('tbody tr' if not footer else 'tfoot tr') - .not_('.thead, .stat_total, .stat_average') - .items()) + .not_('.thead, .stat_total, .stat_average').items()) data = [ [flatten_links(td) if flatten else td.text() for td in row.items('th,td')] @@ -118,7 +117,7 @@ def parse_table(table, flatten=True, footer=False): break # ignore *, +, and other characters used to note things - df.replace(re.compile(ur'[\*\+\u2605]', re.U), '', inplace=True) + df.replace(re.compile(r'[\*\+\u2605]', re.U), '', inplace=True) for col in df.columns: if hasattr(df[col], 'str'): df[col] = df[col].str.strip() @@ -172,8 +171,8 @@ def parse_table(table, flatten=True, footer=False): # converts number-y things to floats def convert_to_float(val): # percentages: (number%) -> float(number * 0.01) - m = re.search(ur'([-\.\d]+)\%', - val if isinstance(val, basestring) else str(val), re.U) + m = re.search(r'([-\.\d]+)\%', + val if isinstance(val, str) else str(val), re.U) try: if m: return float(m.group(1)) / 100. if m else val @@ -182,11 +181,11 @@ def convert_to_float(val): except ValueError: return val # salaries: $ABC,DEF,GHI -> float(ABCDEFGHI) - m = re.search(ur'\$[\d,]+', - val if isinstance(val, basestring) else str(val), re.U) + m = re.search(r'\$[\d,]+', + val if isinstance(val, str) else str(val), re.U) try: if m: - return float(re.sub(ur'\$|,', '', val)) + return float(re.sub(r'\$|,', '', val)) except Exception: return val # generally try to coerce to float, unless it's an int or bool @@ -215,8 +214,8 @@ def parse_info_table(table): :returns: A dictionary representing the information. """ ret = {} - for tr in table('tr').not_('.thead').items(): - th, td = tr('th, td').items() + for tr in list(table('tr').not_('.thead').items()): + th, td = list(tr('th, td').items()) key = th.text().lower() key = re.sub(r'\W', '_', key) val = sportsref.utils.flatten_links(td) @@ -230,7 +229,7 @@ def parse_awards_table(table): :table: PyQuery object representing the HTML table. :returns: A list of the entries in the table, with flattened links. """ - return [flatten_links(tr) for tr in table('tr').items()] + return [flatten_links(tr) for tr in list(table('tr').items())] def flatten_links(td, _recurse=False): @@ -243,7 +242,7 @@ def flatten_links(td, _recurse=False): # helper function to flatten individual strings/links def _flattenC(c): - if isinstance(c, basestring): + if isinstance(c, str): return c.strip('\t\n') elif 'href' in c.attrib: cID = rel_url_to_id(c.attrib['href']) @@ -312,7 +311,7 @@ def rel_url_to_id(url): for regex in regexes: match = re.match(regex, url, re.I) if match: - return filter(None, match.groups())[0] + return [_f for _f in match.groups() if _f][0] # things we don't want to match but don't want to print a WARNING if any( @@ -323,7 +322,7 @@ def rel_url_to_id(url): ): return url - print 'WARNING. NO MATCH WAS FOUND FOR "{}"'.format(url) + print('WARNING. NO MATCH WAS FOUND FOR "{}"'.format(url)) return url @@ -334,4 +333,4 @@ def __init__(self, ee): __, __, self.tb = sys.exc_info() def re_raise(self): - raise self.ee, None, self.tb + raise self.ee.with_traceback(self.tb) From da0b1ace9e97c5d94c87c4b4adcbbd8dab04cb86 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 10 Jan 2018 18:27:43 -0500 Subject: [PATCH 02/57] hashing encoding fix --- sportsref/decorators.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sportsref/decorators.py b/sportsref/decorators.py index 67d2b1d..c2c6f00 100644 --- a/sportsref/decorators.py +++ b/sportsref/decorators.py @@ -121,7 +121,11 @@ def cacheValidFuncs(s): def wrapper(url): # hash based on the URL file_hash = hashlib.md5() - file_hash.update(b + url) + + #was throwing error that url wasn't encoded after 2to3 + url_encoded = url.encode('utf-8') + + file_hash.update(url_encoded) file_hash = file_hash.hexdigest() filename = '{}/{}'.format(CACHE_DIR, file_hash) From 706c1ac69407af17576d28e66574d0e0fe3bc5f5 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 15 Jan 2018 16:41:20 -0500 Subject: [PATCH 03/57] new cbb folder --- sportsref/cbb/__init__.py | 20 ++ sportsref/cbb/boxscores.py | 458 +++++++++++++++++++++++++ sportsref/cbb/pbp.py | 671 +++++++++++++++++++++++++++++++++++++ sportsref/cbb/players.py | 220 ++++++++++++ sportsref/cbb/seasons.py | 222 ++++++++++++ sportsref/cbb/teams.py | 75 +++++ 6 files changed, 1666 insertions(+) create mode 100644 sportsref/cbb/__init__.py create mode 100644 sportsref/cbb/boxscores.py create mode 100644 sportsref/cbb/pbp.py create mode 100644 sportsref/cbb/players.py create mode 100644 sportsref/cbb/seasons.py create mode 100644 sportsref/cbb/teams.py diff --git a/sportsref/cbb/__init__.py b/sportsref/cbb/__init__.py new file mode 100644 index 0000000..d09534b --- /dev/null +++ b/sportsref/cbb/__init__.py @@ -0,0 +1,20 @@ +from . import boxscores +from . import pbp +from . import seasons +from . import teams + +from .boxscores import BoxScore +from .seasons import Season +from .teams import Team +from .players import Player + +BASE_URL = 'http://www.basketball-reference.com' + +__all__ = [ + 'BASE_URL', + 'boxscores', 'BoxScore', + 'pbp', + 'seasons', 'Season', + 'teams', 'Team', + 'players', 'Player', +] diff --git a/sportsref/cbb/boxscores.py b/sportsref/cbb/boxscores.py new file mode 100644 index 0000000..20f3a8e --- /dev/null +++ b/sportsref/cbb/boxscores.py @@ -0,0 +1,458 @@ +import future +import future.utils + +import datetime +import re + +import numpy as np +import pandas as pd +from pyquery import PyQuery as pq + +import sportsref + + +class BoxScore( + future.utils.with_metaclass(sportsref.decorators.Cached, object) +): + + def __init__(self, boxscore_id): + self.boxscore_id = boxscore_id + + def __eq__(self, other): + return self.boxscore_id == other.boxscore_id + + def __hash__(self): + return hash(self.boxscore_id) + + def __repr__(self): + return 'BoxScore({})'.format(self.boxscore_id) + + @sportsref.decorators.memoize + def get_main_doc(self): + url = ('{}/boxscores/{}.html' + .format(sportsref.nba.BASE_URL, self.boxscore_id)) + doc = pq(sportsref.utils.get_html(url)) + return doc + + @sportsref.decorators.memoize + def get_subpage_doc(self, page): + url = (sportsref.nba.BASE_URL + + '/boxscores/{}/{}.html'.format(page, self.boxscore_id)) + doc = pq(sportsref.utils.get_html(url)) + return doc + + @sportsref.decorators.memoize + def date(self): + """Returns the date of the game. See Python datetime.date documentation + for more. + :returns: A datetime.date object with year, month, and day attributes. + """ + match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) + year, month, day = list(map(int, match.groups())) + return datetime.date(year=year, month=month, day=day) + + @sportsref.decorators.memoize + def weekday(self): + days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', + 'Saturday', 'Sunday'] + date = self.date() + wd = date.weekday() + return days[wd] + + @sportsref.decorators.memoize + def linescore(self): + """Returns the linescore for the game as a DataFrame.""" + doc = self.get_main_doc() + table = doc('table#line_score') + + columns = [th.text() for th in table('tr.thead').items('th')] + columns[0] = 'team_id' + + data = [ + [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] + for tr in list(table('tr.thead').next_all('tr').items()) + ] + + return pd.DataFrame(data, index=['away', 'home'], + columns=columns, dtype='float') + + @sportsref.decorators.memoize + def home(self): + """Returns home team ID. + :returns: 3-character string representing home team's ID. + """ + linescore = self.linescore() + return linescore.loc['home', 'team_id'] + + @sportsref.decorators.memoize + def away(self): + """Returns away team ID. + :returns: 3-character string representing away team's ID. + """ + linescore = self.linescore() + return linescore.loc['away', 'team_id'] + + @sportsref.decorators.memoize + def home_score(self): + """Returns score of the home team. + :returns: int of the home score. + """ + linescore = self.linescore() + return linescore.loc['home', 'T'] + + @sportsref.decorators.memoize + def away_score(self): + """Returns score of the away team. + :returns: int of the away score. + """ + linescore = self.linescore() + return linescore.loc['away', 'T'] + + @sportsref.decorators.memoize + def winner(self): + """Returns the team ID of the winning team. Returns NaN if a tie.""" + hmScore = self.home_score() + awScore = self.away_score() + if hmScore > awScore: + return self.home() + elif hmScore < awScore: + return self.away() + else: + return None + + @sportsref.decorators.memoize + def season(self): + """ + Returns the year ID of the season in which this game took place. + + :returns: An int representing the year of the season. + """ + d = self.date() + if d.month >= 9: + return d.year + 1 + else: + return d.year + + def _get_player_stats(self, table_id_fmt): + """Returns a DataFrame of player stats from the game (either basic or + advanced, depending on the argument. + + :param table_id_fmt: Format string for str.format with a placeholder + for the team ID (e.g. 'box_{}_basic') + :returns: DataFrame of player stats + """ + + # get data + doc = self.get_main_doc() + tms = self.away(), self.home() + tm_ids = [table_id_fmt.format(tm) for tm in tms] + tables = [doc('table#{}'.format(tm_id).lower()) for tm_id in tm_ids] + dfs = [sportsref.utils.parse_table(table) for table in tables] + + # clean data and add features + for i, (tm, df) in enumerate(zip(tms, dfs)): + no_time = df['mp'] == 0 + stat_cols = [col for col, dtype in df.dtypes.items() + if dtype != 'object'] + df.loc[no_time, stat_cols] = 0 + df['team_id'] = tm + df['is_home'] = i == 1 + df['is_starter'] = [p < 5 for p in range(df.shape[0])] + df.drop_duplicates(subset='player_id', keep='first', inplace=True) + + return pd.concat(dfs) + + @sportsref.decorators.memoize + def basic_stats(self): + """Returns a DataFrame of basic player stats from the game.""" + return self._get_player_stats('box_{}_basic') + + @sportsref.decorators.memoize + def advanced_stats(self): + """Returns a DataFrame of advanced player stats from the game.""" + return self._get_player_stats('box_{}_advanced') + + @sportsref.decorators.memoize + def pbp(self, dense_lineups=False, sparse_lineups=False): + """Returns a dataframe of the play-by-play data from the game. + + :param dense_lineups: If True, adds 10 columns containing the names of + the players on the court. Defaults to False. + :param sparse_lineups: If True, adds binary columns denoting whether a + given player is in the game at the time of a pass. Defaults to + False. + :returns: pandas DataFrame of play-by-play. Similar to GPF. + """ + try: + doc = self.get_subpage_doc('pbp') + except: + raise ValueError( + 'Error fetching PBP subpage for boxscore {}' + .format(self.boxscore_id) + ) + table = doc('table#pbp') + trs = [ + tr for tr in list(table('tr').items()) + if (not tr.attr['class'] or # regular data rows + tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds + ] + rows = [tr.children('td') for tr in trs] + n_rows = len(trs) + data = [] + cur_qtr = 0 + bsid = self.boxscore_id + + for i in range(n_rows): + tr = trs[i] + row = rows[i] + p = {} + + # increment cur_qtr when we hit a new quarter + if tr.attr['id'] and tr.attr['id'].startswith('q'): + assert int(tr.attr['id'][1:]) == cur_qtr + 1 + cur_qtr += 1 + continue + + # add time of play to entry + t_str = row.eq(0).text() + t_regex = r'(\d+):(\d+)\.(\d+)' + mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) + endQ = (12 * 60 * min(cur_qtr, 4) + + 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) + secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) + p['secs_elapsed'] = secsElapsed + p['clock_time'] = t_str + p['quarter'] = cur_qtr + + # handle single play description + # ex: beginning/end of quarter, jump ball + if row.length == 2: + desc = row.eq(1) + # handle jump balls + if desc.text().lower().startswith('jump ball: '): + p['is_jump_ball'] = True + jb_str = sportsref.utils.flatten_links(desc) + p.update( + sportsref.nba.pbp.parse_play(bsid, jb_str, None) + ) + # ignore rows marking beginning/end of quarters + elif ( + desc.text().lower().startswith('start of ') or + desc.text().lower().startswith('end of ') + ): + continue + # if another case, log and continue + else: + if not desc.text().lower().startswith('end of '): + print(( + '{}, Q{}, {} other case: {}' + .format(self.boxscore_id, cur_qtr, + t_str, desc.text()) + )) + continue + + # handle team play description + # ex: shot, turnover, rebound, foul, sub, etc. + elif row.length == 6: + aw_desc, hm_desc = row.eq(1), row.eq(5) + is_hm_play = bool(hm_desc.text()) + desc = hm_desc if is_hm_play else aw_desc + desc = sportsref.utils.flatten_links(desc) + # parse the play + new_p = sportsref.nba.pbp.parse_play(bsid, desc, is_hm_play) + if not new_p: + continue + elif isinstance(new_p, list): + # this happens when a row needs to be expanded to 2 rows; + # ex: double personal foul -> two PF rows + + # first, update and append the first row + orig_p = dict(p) + p.update(new_p[0]) + data.append(p) + # second, set up the second row to be appended below + p = orig_p + new_p = new_p[1] + elif new_p.get('is_error'): + print(("can't parse: {}, boxscore: {}" + .format(desc, self.boxscore_id))) + # import pdb; pdb.set_trace() + p.update(new_p) + + # otherwise, I don't know what this was + else: + raise Exception(("don't know how to handle row of length {}" + .format(row.length))) + + data.append(p) + + # convert to DataFrame and clean columns + df = pd.DataFrame.from_records(data) + df.sort_values('secs_elapsed', inplace=True, kind='mergesort') + df = sportsref.nba.pbp.clean_features(df) + + # add columns for home team, away team, boxscore_id, date + away, home = self.away(), self.home() + df['home'] = home + df['away'] = away + df['boxscore_id'] = self.boxscore_id + df['season'] = self.season() + date = self.date() + df['year'] = date.year + df['month'] = date.month + df['day'] = date.day + + def _clean_rebs(df): + df.reset_index(drop=True, inplace=True) + no_reb_after = ( + (df.fta_num < df.tot_fta) | df.is_ftm | + df.get('is_tech_fta', False) + ).shift(1).fillna(False) + no_reb_before = ( + (df.fta_num == df.tot_fta) + ).shift(-1).fillna(False) + se_end_qtr = df.loc[ + df.clock_time == '0:00.0', 'secs_elapsed' + ].unique() + no_reb_when = df.secs_elapsed.isin(se_end_qtr) + drop_mask = ( + (df.rebounder == 'Team') & + (no_reb_after | no_reb_before | no_reb_when) + ).nonzero()[0] + df.drop(drop_mask, axis=0, inplace=True) + df.reset_index(drop=True, inplace=True) + return df + + # get rid of 'rebounds' after FTM, non-final FTA, or tech FTA + df = _clean_rebs(df) + + # track possession number for each possession + # TODO: see 201604130PHO, secs_elapsed == 2756 + # things that end a poss: + # FGM, dreb, TO, end of Q, made last FT, lost jump ball, + # def goaltending, shot clock violation + new_poss = (df.off_team == df.home).diff().fillna(False) + # def rebound considered part of the new possession + df['poss_id'] = np.cumsum(new_poss) + df.is_dreb + # create poss_id with rebs -> new possessions for granular groupbys + poss_id_reb = np.cumsum(new_poss | df.is_reb) + + # make sure plays with the same clock time are in the right order + # TODO: make sort_cols depend on what cols are in the play? + # or combine related plays, like and-1 shot and foul + # issues come up with FGA after timeout in 201604130LAL + # issues come up with PF between FGA and DREB in 201604120SAS + sort_cols = [col for col in + ['is_reb', 'is_fga', 'is_pf', 'is_tech_foul', + 'is_ejection', 'is_tech_fta', 'is_timeout', 'is_pf_fta', + 'fta_num', 'is_viol', 'is_to', 'is_jump_ball', 'is_sub'] + if col in df.columns] + asc_true = ['fta_num'] + ascend = [(col in asc_true) for col in sort_cols] + for label, group in df.groupby([df.secs_elapsed, poss_id_reb]): + if len(group) > 1: + df.loc[group.index, :] = group.sort_values( + sort_cols, ascending=ascend, kind='mergesort' + ).values + + # 2nd pass: get rid of 'rebounds' after FTM, non-final FTA, etc. + df = _clean_rebs(df) + + # makes sure off/def and poss_id are correct for subs after rearranging + # some possessions above + df.loc[df['is_sub'], ['off_team', 'def_team', 'poss_id']] = np.nan + df.off_team.fillna(method='bfill', inplace=True) + df.def_team.fillna(method='bfill', inplace=True) + df.poss_id.fillna(method='bfill', inplace=True) + # make off_team and def_team NaN for jump balls + if 'is_jump_ball' in df.columns: + df.loc[df['is_jump_ball'], ['off_team', 'def_team']] = np.nan + + # make sure 'off_team' is always the team shooting FTs, even on techs + # (impt for keeping track of the score) + if 'is_tech_fta' in df.columns: + tech_fta = df['is_tech_fta'] + df.loc[tech_fta, 'off_team'] = df.loc[tech_fta, 'fta_team'] + df.loc[tech_fta, 'def_team'] = np.where( + df.loc[tech_fta, 'off_team'] == home, away, home + ) + df.drop('fta_team', axis=1, inplace=True) + # redefine poss_id_reb + new_poss = (df.off_team == df.home).diff().fillna(False) + poss_id_reb = np.cumsum(new_poss | df.is_reb) + + # get rid of redundant subs + for (se, tm, pnum), group in df[df.is_sub].groupby( + [df.secs_elapsed, df.sub_team, poss_id_reb] + ): + if len(group) > 1: + sub_in = set() + sub_out = set() + # first, figure out who's in and who's out after subs + for i, row in group.iterrows(): + if row['sub_in'] in sub_out: + sub_out.remove(row['sub_in']) + else: + sub_in.add(row['sub_in']) + if row['sub_out'] in sub_in: + sub_in.remove(row['sub_out']) + else: + sub_out.add(row['sub_out']) + assert len(sub_in) == len(sub_out) + # second, add those subs + n_subs = len(sub_in) + for idx, p_in, p_out in zip( + group.index[:n_subs], sub_in, sub_out + ): + assert df.loc[idx, 'is_sub'] + df.loc[idx, 'sub_in'] = p_in + df.loc[idx, 'sub_out'] = p_out + df.loc[idx, 'sub_team'] = tm + df.loc[idx, 'detail'] = ( + '{} enters the game for {}'.format(p_in, p_out) + ) + # third, if applicable, remove old sub entries when there are + # redundant subs + n_extra = len(group) - len(sub_in) + if n_extra: + extra_idxs = group.index[-n_extra:] + df.drop(extra_idxs, axis=0, inplace=True) + + df.reset_index(drop=True, inplace=True) + + # add column for pts and score + df['pts'] = (df['is_ftm'] + 2 * df['is_fgm'] + + (df['is_fgm'] & df['is_three'])) + df['hm_pts'] = np.where(df.off_team == df.home, df.pts, 0) + df['aw_pts'] = np.where(df.off_team == df.away, df.pts, 0) + df['hm_score'] = np.cumsum(df['hm_pts']) + df['aw_score'] = np.cumsum(df['aw_pts']) + + # more helpful columns + # "play" is differentiated from "poss" by counting OReb as new play + # "plays" end with non-and1 FGA, TO, last non-tech FTA, or end of qtr + # (or double lane viol) + new_qtr = df.quarter.diff().shift(-1).fillna(False).astype(bool) + and1 = (df.is_fgm & df.is_pf.shift(-1).fillna(False) & + df.is_fta.shift(-2).fillna(False) & + ~df.secs_elapsed.diff().shift(-1).fillna(False).astype(bool)) + double_lane = (df.get('viol_type') == 'double lane') + new_play = df.eval('(is_fga & ~(@and1)) | is_to | @new_qtr |' + '(is_fta & ~is_tech_fta & fta_num == tot_fta) |' + '@double_lane') + df['play_id'] = np.cumsum(new_play).shift(1).fillna(0) + df['hm_off'] = df.off_team == df.home + + # get lineup data + if dense_lineups: + df = pd.concat( + (df, sportsref.nba.pbp.get_dense_lineups(df)), axis=1 + ) + if sparse_lineups: + df = pd.concat( + (df, sportsref.nba.pbp.get_sparse_lineups(df)), axis=1 + ) + + # TODO: add shot clock as a feature + + return df diff --git a/sportsref/cbb/pbp.py b/sportsref/cbb/pbp.py new file mode 100644 index 0000000..a67eebd --- /dev/null +++ b/sportsref/cbb/pbp.py @@ -0,0 +1,671 @@ +from builtins import enumerate, int, list, range, zip + +import operator +import re + +import numpy as np +import pandas as pd + +import sportsref + +PLAYER_RE = r'\w{0,7}\d{2}' + +HM_LINEUP_COLS = ['hm_player{}'.format(i) for i in range(1, 6)] +AW_LINEUP_COLS = ['aw_player{}'.format(i) for i in range(1, 6)] +ALL_LINEUP_COLS = AW_LINEUP_COLS + HM_LINEUP_COLS + + +def sparse_lineup_cols(df): + regex = '{}_in'.format(PLAYER_RE) + return [c for c in df.columns if re.match(regex, c)] + + +def parse_play(boxscore_id, details, is_hm): + """Parse play details from a play-by-play string describing a play. + + Assuming valid input, this function returns structured data in a dictionary + describing the play. If the play detail string was invalid, this function + returns None. + + :param boxscore_id: the boxscore ID of the play + :param details: detail string for the play + :param is_hm: bool indicating whether the offense is at home + :param returns: dictionary of play attributes or None if invalid + :rtype: dictionary or None + """ + # if input isn't a string, return None + if not details or not isinstance(details, str): + return None + + bs = sportsref.nba.BoxScore(boxscore_id) + aw, hm = bs.away(), bs.home() + season = sportsref.nba.Season(bs.season()) + hm_roster = set(bs.basic_stats().query('is_home == True').player_id.values) + + p = {} + p['detail'] = details + p['home'] = hm + p['away'] = aw + p['is_home_play'] = is_hm + + # parsing field goal attempts + shotRE = (r'(?P{0}) (?Pmakes|misses) ' + '(?P2|3)\-pt shot').format(PLAYER_RE) + distRE = r' (?:from (?P\d+) ft|at rim)' + assistRE = r' \(assist by (?P{0})\)'.format(PLAYER_RE) + blockRE = r' \(block by (?P{0})\)'.format(PLAYER_RE) + shotRE = r'{0}{1}(?:{2}|{3})?'.format(shotRE, distRE, assistRE, blockRE) + m = re.match(shotRE, details, re.IGNORECASE) + if m: + p['is_fga'] = True + p.update(m.groupdict()) + p['shot_dist'] = p['shot_dist'] if p['shot_dist'] is not None else 0 + p['shot_dist'] = int(p['shot_dist']) + p['is_fgm'] = p['is_fgm'] == 'makes' + p['is_three'] = p['is_three'] == '3' + p['is_assist'] = pd.notnull(p.get('assister')) + p['is_block'] = pd.notnull(p.get('blocker')) + shooter_home = p['shooter'] in hm_roster + p['off_team'] = hm if shooter_home else aw + p['def_team'] = aw if shooter_home else hm + return p + + # parsing jump balls + jumpRE = ((r'Jump ball: (?P{0}) vs\. (?P{0})' + r'(?: \((?P{0}) gains possession\))?') + .format(PLAYER_RE)) + m = re.match(jumpRE, details, re.IGNORECASE) + if m: + p['is_jump_ball'] = True + p.update(m.groupdict()) + return p + + # parsing rebounds + rebRE = (r'(?POffensive|Defensive) rebound' + r' by (?P{0}|Team)').format(PLAYER_RE) + m = re.match(rebRE, details, re.I) + if m: + p['is_reb'] = True + p.update(m.groupdict()) + p['is_oreb'] = p['is_oreb'].lower() == 'offensive' + p['is_dreb'] = not p['is_oreb'] + if p['rebounder'] == 'Team': + p['reb_team'], other = (hm, aw) if is_hm else (aw, hm) + else: + reb_home = p['rebounder'] in hm_roster + p['reb_team'], other = (hm, aw) if reb_home else (aw, hm) + p['off_team'] = p['reb_team'] if p['is_oreb'] else other + p['def_team'] = p['reb_team'] if p['is_dreb'] else other + return p + + # parsing free throws + ftRE = (r'(?P{}) (?Pmakes|misses) ' + r'(?Ptechnical )?(?Pflagrant )?' + r'(?Pclear path )?free throw' + r'(?: (?P\d+) of (?P\d+))?').format(PLAYER_RE) + m = re.match(ftRE, details, re.I) + if m: + p['is_fta'] = True + p.update(m.groupdict()) + p['is_ftm'] = p['is_ftm'] == 'makes' + p['is_tech_fta'] = bool(p['is_tech_fta']) + p['is_flag_fta'] = bool(p['is_flag_fta']) + p['is_clearpath_fta'] = bool(p['is_clearpath_fta']) + p['is_pf_fta'] = not p['is_tech_fta'] + if p['tot_fta']: + p['tot_fta'] = int(p['tot_fta']) + if p['fta_num']: + p['fta_num'] = int(p['fta_num']) + ft_home = p['ft_shooter'] in hm_roster + p['fta_team'] = hm if ft_home else aw + if not p['is_tech_fta']: + p['off_team'] = hm if ft_home else aw + p['def_team'] = aw if ft_home else hm + return p + + # parsing substitutions + subRE = (r'(?P{0}) enters the game for ' + r'(?P{0})').format(PLAYER_RE) + m = re.match(subRE, details, re.I) + if m: + p['is_sub'] = True + p.update(m.groupdict()) + sub_home = p['sub_in'] in hm_roster or p['sub_out'] in hm_roster + p['sub_team'] = hm if sub_home else aw + return p + + # parsing turnovers + toReasons = (r'(?P[^;]+)(?:; steal by ' + r'(?P{0}))?').format(PLAYER_RE) + toRE = (r'Turnover by (?P{}|Team) ' + r'\((?:{})\)').format(PLAYER_RE, toReasons) + m = re.match(toRE, details, re.I) + if m: + p['is_to'] = True + p.update(m.groupdict()) + p['to_type'] = p['to_type'].lower() + if p['to_type'] == 'offensive foul': + return None + p['is_steal'] = pd.notnull(p['stealer']) + p['is_travel'] = p['to_type'] == 'traveling' + p['is_shot_clock_viol'] = p['to_type'] == 'shot clock' + p['is_oob'] = p['to_type'] == 'step out of bounds' + p['is_three_sec_viol'] = p['to_type'] == '3 sec' + p['is_backcourt_viol'] = p['to_type'] == 'back court' + p['is_off_goaltend'] = p['to_type'] == 'offensive goaltending' + p['is_double_dribble'] = p['to_type'] == 'dbl dribble' + p['is_discont_dribble'] = p['to_type'] == 'discontinued dribble' + p['is_carry'] = p['to_type'] == 'palming' + if p['to_by'] == 'Team': + p['off_team'] = hm if is_hm else aw + p['def_team'] = aw if is_hm else hm + else: + to_home = p['to_by'] in hm_roster + p['off_team'] = hm if to_home else aw + p['def_team'] = aw if to_home else hm + return p + + # parsing shooting fouls + shotFoulRE = (r'Shooting(?P block)? foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(shotFoulRE, details, re.I) + if m: + p['is_pf'] = True + p['is_shot_foul'] = True + p.update(m.groupdict()) + p['is_block_foul'] = bool(p['is_block_foul']) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing offensive fouls + offFoulRE = (r'Offensive(?P charge)? foul ' + r'by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(offFoulRE, details, re.I) + if m: + p['is_pf'] = True + p['is_off_foul'] = True + p['is_to'] = True + p['to_type'] = 'offensive foul' + p.update(m.groupdict()) + p['is_charge'] = bool(p['is_charge']) + p['fouler'] = p['to_by'] + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = hm if foul_on_home else aw + p['def_team'] = aw if foul_on_home else hm + p['foul_team'] = p['off_team'] + return p + + # parsing personal fouls + foulRE = (r'Personal (?Ptake )?(?Pblock )?' + r'foul by (?P{0})(?: \(drawn by ' + r'(?P{0})\))?').format(PLAYER_RE) + m = re.match(foulRE, details, re.I) + if m: + p['is_pf'] = True + p.update(m.groupdict()) + p['is_take_foul'] = bool(p['is_take_foul']) + p['is_block_foul'] = bool(p['is_block_foul']) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # TODO: parsing double personal fouls + # double_foul_re = (r'Double personal foul by (?P{0}) and ' + # r'(?P{0})').format(PLAYER_RE) + # m = re.match(double_Foul_re, details, re.I) + # if m: + # p['is_pf'] = True + # p.update(m.groupdict()) + # p['off_team'] = + + # parsing loose ball fouls + looseBallRE = (r'Loose ball foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(looseBallRE, details, re.I) + if m: + p['is_pf'] = True + p['is_loose_ball_foul'] = True + p.update(m.groupdict()) + foul_home = p['fouler'] in hm_roster + p['foul_team'] = hm if foul_home else aw + return p + + # parsing punching fouls + # TODO + + # parsing away from play fouls + awayFromBallRE = ((r'Away from play foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?') + .format(PLAYER_RE)) + m = re.match(awayFromBallRE, details, re.I) + if m: + p['is_pf'] = True + p['is_away_from_play_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + # TODO: figure out who had the ball based on previous play + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing inbound fouls + inboundRE = (r'Inbound foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(inboundRE, details, re.I) + if m: + p['is_pf'] = True + p['is_inbound_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing flagrant fouls + flagrantRE = (r'Flagrant foul type (?P1|2) by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(flagrantRE, details, re.I) + if m: + p['is_pf'] = True + p['is_flagrant'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing clear path fouls + clearPathRE = (r'Clear path foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(clearPathRE, details, re.I) + if m: + p['is_pf'] = True + p['is_clear_path_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing timeouts + timeoutRE = r'(?P.*?) (?:full )?timeout' + m = re.match(timeoutRE, details, re.I) + if m: + p['is_timeout'] = True + p.update(m.groupdict()) + isOfficialTO = p['timeout_team'].lower() == 'official' + name_to_id = season.team_names_to_ids() + p['timeout_team'] = ( + 'Official' if isOfficialTO else + name_to_id.get(hm, name_to_id.get(aw, p['timeout_team'])) + ) + return p + + # parsing technical fouls + techRE = (r'(?PHanging )?' + r'(?PTaunting )?' + r'(?PIll def )?' + r'(?PDelay )?' + r'(?PNon unsport )?' + r'tech(?:nical)? foul by ' + r'(?P{0}|Team)').format(PLAYER_RE) + m = re.match(techRE, details, re.I) + if m: + p['is_tech_foul'] = True + p.update(m.groupdict()) + p['is_hanging'] = bool(p['is_hanging']) + p['is_taunting'] = bool(p['is_taunting']) + p['is_ill_def'] = bool(p['is_ill_def']) + p['is_delay'] = bool(p['is_delay']) + p['is_unsport'] = bool(p['is_unsport']) + foul_on_home = p['tech_fouler'] in hm_roster + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing ejections + ejectRE = r'(?P{0}|Team) ejected from game'.format(PLAYER_RE) + m = re.match(ejectRE, details, re.I) + if m: + p['is_ejection'] = True + p.update(m.groupdict()) + if p['ejectee'] == 'Team': + p['ejectee_team'] = hm if is_hm else aw + else: + eject_home = p['ejectee'] in hm_roster + p['ejectee_team'] = hm if eject_home else aw + return p + + # parsing defensive 3 seconds techs + def3TechRE = (r'(?:Def 3 sec tech foul|Defensive three seconds)' + r' by (?P{})').format(PLAYER_RE) + m = re.match(def3TechRE, details, re.I) + if m: + p['is_tech_foul'] = True + p['is_def_three_secs'] = True + p.update(m.groupdict()) + foul_on_home = p['tech_fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing violations + violRE = (r'Violation by (?P{0}|Team) ' + r'\((?P.*)\)').format(PLAYER_RE) + m = re.match(violRE, details, re.I) + if m: + p['is_viol'] = True + p.update(m.groupdict()) + if p['viol_type'] == 'kicked_ball': + p['is_to'] = True + p['to_by'] = p['violator'] + if p['violator'] == 'Team': + p['viol_team'] = hm if is_hm else aw + else: + viol_home = p['violator'] in hm_roster + p['viol_team'] = hm if viol_home else aw + return p + + p['is_error'] = True + return p + + +def clean_features(df): + """Fixes up columns of the passed DataFrame, such as casting T/F columns to + boolean and filling in NaNs for team and opp. + + :param df: DataFrame of play-by-play data. + :returns: Dataframe with cleaned columns. + """ + df = pd.DataFrame(df) + + bool_vals = set([True, False, None, np.nan]) + sparse_cols = sparse_lineup_cols(df) + for col in df: + + # make indicator columns boolean type (and fill in NaNs) + if set(df[col].unique()[:5]) <= bool_vals: + df[col] = (df[col] == True) + + # fill NaN's in sparse lineup columns to 0 + elif col in sparse_cols: + df[col] = df[col].fillna(0) + + # fix free throw columns on technicals + df.loc[df.is_tech_fta, ['fta_num', 'tot_fta']] = 1 + + # fill in NaN's/fix off_team and def_team columns + df.off_team.fillna(method='bfill', inplace=True) + df.def_team.fillna(method='bfill', inplace=True) + df.off_team.fillna(method='ffill', inplace=True) + df.def_team.fillna(method='ffill', inplace=True) + + return df + + +def clean_multigame_features(df): + """TODO: Docstring for clean_multigame_features. + + :df: TODO + :returns: TODO + """ + df = pd.DataFrame(df) + if df.index.value_counts().max() > 1: + df.reset_index(drop=True, inplace=True) + + df = clean_features(df) + + # if it's many games in one DataFrame, make poss_id and play_id unique + for col in ('play_id', 'poss_id'): + diffs = df[col].diff().fillna(0) + if (diffs < 0).any(): + new_col = np.cumsum(diffs.astype(bool)) + df.eval('{} = @new_col'.format(col), inplace=True) + + return df + + +def get_period_starters(df): + """TODO + """ + + def players_from_play(play): + """Figures out what players are in the game based on the players + mentioned in a play. Returns away and home players as two sets. + + :param play: A dictionary representing a parsed play. + :returns: (aw_players, hm_players) + :rtype: tuple of lists + """ + # if it's a tech FT from between periods, don't count this play + if ( + play['clock_time'] == '12:00.0' and + (play.get('is_tech_foul') or play.get('is_tech_fta')) + ): + return [], [] + + stats = sportsref.nba.BoxScore(play['boxscore_id']).basic_stats() + home_grouped = stats.groupby('is_home') + hm_roster = set(home_grouped.player_id.get_group(True).values) + aw_roster = set(home_grouped.player_id.get_group(False).values) + player_keys = [ + 'assister', 'away_jumper', 'blocker', 'drew_foul', 'fouler', + 'ft_shooter', 'gains_poss', 'home_jumper', 'rebounder', 'shooter', + 'stealer', 'sub_in', 'sub_out', 'to_by' + ] + players = [p for p in play[player_keys] if pd.notnull(p)] + + aw_players = [p for p in players if p in aw_roster] + hm_players = [p for p in players if p in hm_roster] + return aw_players, hm_players + + # create a mapping { quarter => (away_starters, home_starters) } + n_periods = df.quarter.nunique() + period_starters = [(set(), set()) for _ in range(n_periods)] + + # fill out this mapping quarter by quarter + for qtr, qtr_grp in df.groupby(df.quarter): + aw_starters, hm_starters = period_starters[qtr-1] + exclude = set() + # loop through sets of plays that happen at the "same time" + for label, time_grp in qtr_grp.groupby(qtr_grp.secs_elapsed): + # first, if they sub in and weren't already starters, exclude them + sub_ins = set(time_grp.sub_in.dropna().values) + exclude.update(sub_ins - aw_starters - hm_starters) + # second, figure out new starters from each play at this time + for i, row in time_grp.iterrows(): + aw_players, hm_players = players_from_play(row) + # update overall sets for the quarter + aw_starters.update(aw_players) + hm_starters.update(hm_players) + # remove excluded (subbed-in) players + hm_starters -= exclude + aw_starters -= exclude + # check whether we have found all starters + if len(hm_starters) > 5 or len(aw_starters) > 5: + import ipdb + ipdb.set_trace() + if len(hm_starters) >= 5 and len(aw_starters) >= 5: + break + + if len(hm_starters) != 5 or len(aw_starters) != 5: + print(('WARNING: wrong number of starters for a team in Q{} of {}' + .format(qtr, df.boxscore_id.iloc[0]))) + + return period_starters + + +def get_sparse_lineups(df): + """TODO: Docstring for get_sparse_lineups. + + :param df: TODO + :returns: TODO + """ + + # get the lineup data using get_dense_lineups if necessary + if (set(ALL_LINEUP_COLS) - set(df.columns)): + lineup_df = get_dense_lineups(df) + else: + lineup_df = df[ALL_LINEUP_COLS] + + # create the sparse representation + hm_lineups = lineup_df[HM_LINEUP_COLS].values + aw_lineups = lineup_df[AW_LINEUP_COLS].values + # +1 for home, -1 for away + hm_df = pd.DataFrame([ + {'{}_in'.format(player_id): 1 for player_id in lineup} + for lineup in hm_lineups + ], dtype=int) + aw_df = pd.DataFrame([ + {'{}_in'.format(player_id): -1 for player_id in lineup} + for lineup in aw_lineups + ], dtype=int) + sparse_df = pd.concat((hm_df, aw_df), axis=1).fillna(0) + return sparse_df + + +def get_dense_lineups(df): + """Returns a new DataFrame based on the one it is passed. Specifically, it + adds five columns for each team (ten total), where each column has the ID + of a player on the court during the play. + + This information is figured out sequentially from the game's substitution + data in the passed DataFrame, so the DataFrame passed as an argument must + be from a specific BoxScore (rather than a DataFrame of non-consecutive + plays). That is, the DataFrame must be of the form returned by + :func:`nba.BoxScore.pbp `. + + .. note:: Note that the lineups reflect the teams in the game when the play + happened, not after the play. For example, if a play is a substitution, + the lineups for that play will be the lineups before the substituion + occurs. + + :param df: A DataFrame of a game's play-by-play data. + :returns: A DataFrame with additional lineup columns. + + """ + # TODO: add this precondition to documentation + assert df['boxscore_id'].nunique() == 1 + + def lineup_dict(aw_lineup, hm_lineup): + """Returns a dictionary of lineups to be converted to columns. + Specifically, the columns are 'aw_player1' through 'aw_player5' and + 'hm_player1' through 'hm_player5'. + + :param aw_lineup: The away team's current lineup. + :param hm_lineup: The home team's current lineup. + :returns: A dictionary of lineups. + """ + return { + '{}_player{}'.format(tm, i+1): player + for tm, lineup in zip(['aw', 'hm'], [aw_lineup, hm_lineup]) + for i, player in enumerate(lineup) + } + + def handle_sub(row, aw_lineup, hm_lineup): + """Modifies the aw_lineup and hm_lineup lists based on the substitution + that takes place in the given row.""" + assert row['is_sub'] + sub_lineup = hm_lineup if row['sub_team'] == row['home'] else aw_lineup + try: + # make the sub + idx = sub_lineup.index(row['sub_out']) + sub_lineup[idx] = row['sub_in'] + except ValueError: + # if the sub was double-entered and it's already been executed... + if ( + row['sub_in'] in sub_lineup + and row['sub_out'] not in sub_lineup + ): + return aw_lineup, hm_lineup + # otherwise, let's print and pretend this never happened + print(('ERROR IN SUB IN {}, Q{}, {}: {}' + .format(row['boxscore_id'], row['quarter'], + row['clock_time'], row['detail']))) + raise + return aw_lineup, hm_lineup + + per_starters = get_period_starters(df) + cur_qtr = 0 + aw_lineup, hm_lineup = [], [] + df = df.reset_index(drop=True) + lineups = [{} for _ in range(df.shape[0])] + + # loop through select plays to determine lineups + sub_or_per_start = df.is_sub | df.quarter.diff().astype(bool) + for i, row in df.loc[sub_or_per_start].iterrows(): + if row['quarter'] > cur_qtr: + # first row in a quarter + assert row['quarter'] == cur_qtr + 1 + # first, finish up the last quarter's lineups + if cur_qtr > 0 and not df.loc[i-1, 'is_sub']: + lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) + # then, move on to the quarter, and enter the starting lineups + cur_qtr += 1 + aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) + lineups[i] = lineup_dict(aw_lineup, hm_lineup) + # if the first play in the quarter is a sub, handle that + if row['is_sub']: + aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) + else: + # during the quarter + # update lineups first then change lineups based on subs + lineups[i] = lineup_dict(aw_lineup, hm_lineup) + if row['is_sub']: + aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) + + # create and clean DataFrame + lineup_df = pd.DataFrame(lineups) + if lineup_df.iloc[-1].isnull().all(): + lineup_df.iloc[-1] = lineup_dict(aw_lineup, hm_lineup) + lineup_df = lineup_df.groupby(df.quarter).fillna(method='bfill') + + # fill in NaN's based on minutes played + bool_mat = lineup_df.isnull() + mask = bool_mat.any(axis=1) + if mask.any(): + bs = sportsref.nba.BoxScore(df.boxscore_id[0]) + # first, get the true minutes played from the box score + stats = sportsref.nba.BoxScore(df.boxscore_id.iloc[0]).basic_stats() + true_mp = pd.Series( + stats.query('mp > 0')[['player_id', 'mp']] + .set_index('player_id').to_dict()['mp'] + ) * 60 + # next, calculate minutes played based on the lineup data + calc_mp = pd.Series( + {p: (df.secs_elapsed.diff() * + [p in row for row in lineup_df.values]).sum() + for p in stats.query('mp > 0').player_id.values}) + # finally, figure which players are missing minutes + diff = true_mp - calc_mp + players_missing = diff.loc[diff.abs() >= 150] + hm_roster = bs.basic_stats().query('is_home == True').player_id.values + missing_df = pd.DataFrame( + {'secs': players_missing.values, + 'is_home': players_missing.index.isin(hm_roster)}, + index=players_missing.index + ) + + if missing_df.empty: + # TODO: log this as a warning (or error?) + print('There are NaNs in the lineup data, but no players were ' + 'found to be missing significant minutes') + else: + # import ipdb + # ipdb.set_trace() + for is_home, group in missing_df.groupby('is_home'): + player_id = group.index.item() + tm_cols = (sportsref.nba.pbp.HM_LINEUP_COLS if is_home else + sportsref.nba.pbp.AW_LINEUP_COLS) + row_mask = lineup_df[tm_cols].isnull().any(axis=1) + lineup_df.loc[row_mask, tm_cols] = ( + lineup_df.loc[row_mask, tm_cols].fillna(player_id).values + ) + + return lineup_df diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py new file mode 100644 index 0000000..122dd6c --- /dev/null +++ b/sportsref/cbb/players.py @@ -0,0 +1,220 @@ +import future +import future.utils + +import datetime +import re + +import numpy as np +from pyquery import PyQuery as pq + +import sportsref + +__all__ = [ + 'Player', +] + + +class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + """Each instance of this class represents an NBA player, uniquely + identified by a player ID. The instance methods give various data available + from the player's Basketball Reference player page.""" + + def __init__(self, player_id): + self.player_id = player_id + self.url_base = (sportsref.nba.BASE_URL + + '/players/{0[0]}/{0}').format(self.player_id) + self.main_url = self.url_base + '.htm' + + def __eq__(self, other): + return self.player_id == other.player_id + + def __hash__(self): + return hash(self.player_id) + + def __repr__(self): + return 'Player({})'.format(self.player_id) + + def __str__(self): + return self.name() + + @sportsref.decorators.memoize + def get_main_doc(self): + return pq(sportsref.utils.get_html(self.main_url)) + + @sportsref.decorators.memoize + def get_sub_doc(self, rel_url): + url = '{}/{}'.format(self.url_base, rel_url) + return pq(sportsref.utils.get_html(url)) + + @sportsref.decorators.memoize + def name(self): + """Returns the name of the player as a string.""" + doc = self.get_main_doc() + return doc('h1[itemprop="name"]').text() + + @sportsref.decorators.memoize + def age(self, year, month=2, day=1): + """Returns the age of the player on a given date. + + :year: int representing the year. + :month: int representing the month (1-12). + :day: int representing the day within the month (1-31). + :returns: Age in years as a float. + """ + doc = self.get_main_doc() + date_string = doc('span[itemprop="birthDate"]').attr('data-birth') + regex = r'(\d{4})\-(\d{2})\-(\d{2})' + date_args = list(map(int, re.match(regex, date_string).groups())) + birth_date = datetime.date(*date_args) + age_date = datetime.date(year=year, month=month, day=day) + delta = age_date - birth_date + age = delta.days / 365. + return age + + @sportsref.decorators.memoize + def position(self): + """TODO: Docstring for position. + :returns: TODO + """ + raise Exception('not yet implemented - nba.Player.position') + + @sportsref.decorators.memoize + def height(self): + """Returns the player's height (in inches). + :returns: An int representing a player's height in inches. + """ + doc = self.get_main_doc() + raw = doc('span[itemprop="height"]').text() + try: + feet, inches = list(map(int, raw.split('-'))) + return feet * 12 + inches + except ValueError: + return None + + @sportsref.decorators.memoize + def weight(self): + """Returns the player's weight (in pounds). + :returns: An int representing a player's weight in pounds. + """ + doc = self.get_main_doc() + raw = doc('span[itemprop="weight"]').text() + try: + weight = re.match(r'(\d+)lb', raw).group(1) + return int(weight) + except ValueError: + return None + + @sportsref.decorators.memoize + def hand(self): + """Returns the player's handedness. + :returns: 'L' for left-handed, 'R' for right-handed. + """ + doc = self.get_main_doc() + hand = re.search(r'Shoots:\s*(L|R)', doc.text()).group(1) + return hand + + @sportsref.decorators.memoize + def draft_pick(self): + """Returns when in the draft the player was picked. + :returns: TODO + """ + raise Exception('not yet implemented - nba.Player.draft_pick') + + @sportsref.decorators.memoize + def draft_year(self): + """Returns the year the player was selected (or undrafted). + :returns: TODO + """ + raise Exception('not yet implemented - nba.Player.draft_year') + + @sportsref.decorators.kind_rpb(include_type=True) + def _get_stats_table(self, table_id, kind='R', summary=False): + """Gets a stats table from the player page; helper function that does + the work for per-game, per-100-poss, etc. stats. + + :table_id: the ID of the HTML table. + :kind: specifies regular season, playoffs, or both. One of 'R', 'P', + 'B'. Defaults to 'R'. + :returns: A DataFrame of stats. + """ + doc = self.get_main_doc() + table_id = 'table#{}{}'.format( + 'playoffs_' if kind == 'P' else '', table_id) + table = doc(table_id) + df = sportsref.utils.parse_table(table, flatten=(not summary), + footer=summary) + return df + + @sportsref.decorators.memoize + def stats_per_game(self, kind='R', summary=False): + """Returns a DataFrame of per-game box score stats.""" + return self._get_stats_table('per_game', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_totals(self, kind='R', summary=False): + """Returns a DataFrame of total box score statistics by season.""" + return self._get_stats_table('totals', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_per36(self, kind='R', summary=False): + """Returns a DataFrame of per-36-minutes stats.""" + return self._get_stats_table('per_minute', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_per100(self, kind='R', summary=False): + """Returns a DataFrame of per-100-possession stats.""" + return self._get_stats_table('per_poss', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_advanced(self, kind='R', summary=False): + """Returns a DataFrame of advanced stats.""" + return self._get_stats_table('advanced', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_shooting(self, kind='R', summary=False): + """Returns a DataFrame of shooting stats.""" + return self._get_stats_table('shooting', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_pbp(self, kind='R', summary=False): + """Returns a DataFrame of play-by-play stats.""" + return self._get_stats_table('advanced_pbp', kind=kind, + summary=summary) + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def gamelog_basic(self, year, kind='R'): + """Returns a table of a player's basic game-by-game stats for a season. + + :param year: The year representing the desired season. + :param kind: specifies regular season, playoffs, or both. One of 'R', + 'P', 'B'. Defaults to 'R'. + :returns: A DataFrame of the player's standard boxscore stats from each + game of the season. + :rtype: pd.DataFrame + """ + doc = self.get_sub_doc('gamelog/{}'.format(year)) + table = (doc('table#pgl_basic_playoffs') + if kind == 'P' else doc('table#pgl_basic')) + df = sportsref.utils.parse_table(table) + return df + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def gamelog_advanced(self, year, kind='R'): + """Returns a table of a player's advanced game-by-game stats for a + season. + + :param year: The year representing the desired season. + :param kind: specifies regular season, playoffs, or both. One of 'R', + 'P', 'B'. Defaults to 'R'. + :returns: A DataFrame of the player's advanced stats from each game of + the season. + :rtype: pd.DataFrame + """ + doc = self.get_sub_doc('gamelog-advanced/{}'.format(year)) + table = (doc('table#pgl_advanced_playoffs') + if kind == 'P' else doc('table#pgl_advanced')) + df = sportsref.utils.parse_table(table) + return df diff --git a/sportsref/cbb/seasons.py b/sportsref/cbb/seasons.py new file mode 100644 index 0000000..5be3575 --- /dev/null +++ b/sportsref/cbb/seasons.py @@ -0,0 +1,222 @@ +import future +import future.utils + +import pandas as pd +from pyquery import PyQuery as pq + +import sportsref + + +class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + """Object representing a given NBA season.""" + + def __init__(self, year): + """Initializes a Season object for an NBA season. + + :year: The year of the season we want. + """ + self.yr = int(year) + + def __eq__(self, other): + return (self.yr == other.yr) + + def __hash__(self): + return hash(self.yr) + + def __repr__(self): + return 'Season({})'.format(self.yr) + + def _subpage_url(self, page): + return (sportsref.nba.BASE_URL + + '/leagues/NBA_{}_{}.html'.format(self.yr, page)) + + @sportsref.decorators.memoize + def get_main_doc(self): + """Returns PyQuery object for the main season URL. + :returns: PyQuery object. + """ + url = (sportsref.nba.BASE_URL + + '/leagues/NBA_{}.html'.format(self.yr)) + return pq(sportsref.utils.get_html(url)) + + @sportsref.decorators.memoize + def get_sub_doc(self, subpage): + """Returns PyQuery object for a given subpage URL. + :subpage: The subpage of the season, e.g. 'per_game'. + :returns: PyQuery object. + """ + html = sportsref.utils.get_html(self._subpage_url(subpage)) + return pq(html) + + @sportsref.decorators.memoize + def get_team_ids(self): + """Returns a list of the team IDs for the given year. + :returns: List of team IDs. + """ + df = self.team_stats_per_game() + if not df.empty: + return df.index.tolist() + else: + print('ERROR: no teams found') + return [] + + @sportsref.decorators.memoize + def team_ids_to_names(self): + """Mapping from 3-letter team IDs to full team names. + :returns: Dictionary with team IDs as keys and full team strings as + values. + """ + doc = self.get_main_doc() + table = doc('table#team-stats-per_game') + flattened = sportsref.utils.parse_table(table, flatten=True) + unflattened = sportsref.utils.parse_table(table, flatten=False) + team_ids = flattened['team_id'] + team_names = unflattened['team_name'] + if len(team_names) != len(team_ids): + raise Exception("team names and team IDs don't align") + return dict(list(zip(team_ids, team_names))) + + @sportsref.decorators.memoize + def team_names_to_ids(self): + """Mapping from full team names to 3-letter team IDs. + :returns: Dictionary with tean names as keys and team IDs as values. + """ + d = self.team_ids_to_names() + return {v: k for k, v in list(d.items())} + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def schedule(self, kind='R'): + """Returns a list of BoxScore IDs for every game in the season. + Only needs to handle 'R' or 'P' options because decorator handles 'B'. + + :param kind: 'R' for regular season, 'P' for playoffs, 'B' for both. + Defaults to 'R'. + :returns: DataFrame of schedule information. + :rtype: pd.DataFrame + """ + kind = kind.upper()[0] + dfs = [] + + # get games from each month + for month in ('october', 'november', 'december', 'january', 'february', + 'march', 'april', 'may', 'june'): + try: + doc = self.get_sub_doc('games-{}'.format(month)) + except ValueError: + continue + table = doc('table#schedule') + df = sportsref.utils.parse_table(table) + dfs.append(df) + df = pd.concat(dfs).reset_index(drop=True) + + # figure out how many regular season games + try: + sportsref.utils.get_html('{}/playoffs/NBA_{}.html'.format( + sportsref.nba.BASE_URL, self.yr) + ) + is_past_season = True + except ValueError: + is_past_season = False + + if is_past_season: + team_per_game = self.team_stats_per_game() + n_reg_games = int(team_per_game.g.sum() / 2) + else: + n_reg_games = len(df) + + # subset appropriately based on `kind` + if kind == 'P': + return df.iloc[n_reg_games:] + else: + return df.iloc[:n_reg_games] + + def finals_winner(self): + """Returns the team ID for the winner of that year's NBA Finals. + :returns: 3-letter team ID for champ. + """ + raise NotImplementedError('nba.Season.finals_winner') + + def finals_loser(self): + """Returns the team ID for the loser of that year's NBA Finals. + :returns: 3-letter team ID for runner-up. + """ + raise NotImplementedError('nba.Season.finals_loser') + + @sportsref.decorators.memoize + def _get_team_stats_table(self, selector): + """Helper function for stats tables on season pages. Returns a + DataFrame.""" + doc = self.get_main_doc() + table = doc(selector) + df = sportsref.utils.parse_table(table) + df.set_index('team_id', inplace=True) + return df + + def team_stats_per_game(self): + """Returns a Pandas DataFrame of each team's basic per-game stats for + the season.""" + return self._get_team_stats_table('table#team-stats-per_game') + + def opp_stats_per_game(self): + """Returns a Pandas DataFrame of each team's opponent's basic per-game + stats for the season.""" + return self._get_team_stats_table('table#opponent-stats-per_game') + + def team_stats_totals(self): + """Returns a Pandas DataFrame of each team's basic stat totals for the + season.""" + return self._get_team_stats_table('table#team-stats-base') + + def opp_stats_totals(self): + """Returns a Pandas DataFrame of each team's opponent's basic stat + totals for the season.""" + return self._get_team_stats_table('table#opponent-stats-base') + + def misc_stats(self): + """Returns a Pandas DataFrame of miscellaneous stats about each team's + season.""" + return self._get_team_stats_table('table#misc_stats') + + def team_stats_shooting(self): + """Returns a Pandas DataFrame of each team's shooting stats for the + season.""" + return self._get_team_stats_table('table#team_shooting') + + def opp_stats_shooting(self): + """Returns a Pandas DataFrame of each team's opponent's shooting stats + for the season.""" + return self._get_team_stats_table('table#opponent_shooting') + + @sportsref.decorators.memoize + def _get_player_stats_table(self, identifier): + """Helper function for player season stats. + + :identifier: string identifying the type of stat, e.g. 'per_game'. + :returns: A DataFrame of stats. + """ + doc = self.get_sub_doc(identifier) + table = doc('table#{}_stats'.format(identifier)) + df = sportsref.utils.parse_table(table) + return df + + def player_stats_per_game(self): + """Returns a DataFrame of per-game player stats for a season.""" + return self._get_player_stats_table('per_game') + + def player_stats_totals(self): + """Returns a DataFrame of player stat totals for a season.""" + return self._get_player_stats_table('totals') + + def player_stats_per36(self): + """Returns a DataFrame of player per-36 min stats for a season.""" + return self._get_player_stats_table('per_minute') + + def player_stats_per100(self): + """Returns a DataFrame of player per-100 poss stats for a season.""" + return self._get_player_stats_table('per_poss') + + def player_stats_advanced(self): + """Returns a DataFrame of player per-100 poss stats for a season.""" + return self._get_player_stats_table('advanced') diff --git a/sportsref/cbb/teams.py b/sportsref/cbb/teams.py new file mode 100644 index 0000000..86d56f9 --- /dev/null +++ b/sportsref/cbb/teams.py @@ -0,0 +1,75 @@ +import future +import future.utils + +import numpy as np +from pyquery import PyQuery as pq + +import sportsref + + +class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + def __init__(self, team_id): + self.team_id = team_id.upper() + + def __eq__(self, other): + return (self.team_id == other.team_id) + + def __hash__(self): + return hash(self.team_id) + + @sportsref.decorators.memoize + def team_year_url(self, yr_str): + return (sportsref.nba.BASE_URL + + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) + + @sportsref.decorators.memoize + def get_main_doc(self): + relURL = '/teams/{}'.format(self.team_id) + teamURL = sportsref.nba.BASE_URL + relURL + mainDoc = pq(sportsref.utils.get_html(teamURL)) + return mainDoc + + @sportsref.decorators.memoize + def get_year_doc(self, yr_str): + return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) + + @sportsref.decorators.memoize + def name(self): + """Returns the real name of the franchise given the team ID. + + Examples: + 'BOS' -> 'Boston Celtics' + 'NJN' -> 'Brooklyn Nets' + + :returns: A string corresponding to the team's full name. + """ + doc = self.get_main_doc() + name = doc('div#info h1[itemprop="name"]').text() + return name + + @sportsref.decorators.memoize + def roster(self, year): + """Returns the roster table for the given year. + + :year: The year for which we want the roster; defaults to current year. + :returns: A DataFrame containing roster information for that year. + """ + doc = self.get_year_doc(year) + table = doc('table#roster') + df = sportsref.utils.parse_table(table) + df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) + return df + + # TODO: kind_rpb + @sportsref.decorators.memoize + def schedule(self, year): + """Gets schedule information for a team-season. + + :year: The year for which we want the schedule. + :returns: DataFrame of schedule information. + """ + doc = self.get_year_doc('{}_games'.format(year)) + table = doc('table#games') + df = sportsref.utils.parse_table(table) + return df From 950c0dbfce21d5f5fb8405d94aac4d47c9e1881f Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 15 Jan 2018 16:50:29 -0500 Subject: [PATCH 04/57] base_url format update --- sportsref/cbb/__init__.py | 2 +- sportsref/cbb/players.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sportsref/cbb/__init__.py b/sportsref/cbb/__init__.py index d09534b..841cff0 100644 --- a/sportsref/cbb/__init__.py +++ b/sportsref/cbb/__init__.py @@ -8,7 +8,7 @@ from .teams import Team from .players import Player -BASE_URL = 'http://www.basketball-reference.com' +BASE_URL = 'http://www.sports-reference.com' __all__ = [ 'BASE_URL', diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py index 122dd6c..8ad913e 100644 --- a/sportsref/cbb/players.py +++ b/sportsref/cbb/players.py @@ -16,14 +16,14 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - """Each instance of this class represents an NBA player, uniquely + """Each instance of this class represents an CBB player, uniquely identified by a player ID. The instance methods give various data available - from the player's Basketball Reference player page.""" + from the player's Sports Reference player page.""" def __init__(self, player_id): self.player_id = player_id - self.url_base = (sportsref.nba.BASE_URL + - '/players/{0[0]}/{0}').format(self.player_id) + self.url_base = (sportsref.cbb.BASE_URL + + '/players/{0}').format(self.player_id) self.main_url = self.url_base + '.htm' def __eq__(self, other): From 5487e46fc46ff5a5bddd926273e5245ddfa287f9 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 15 Jan 2018 16:51:39 -0500 Subject: [PATCH 05/57] fix --- sportsref/cbb/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py index 8ad913e..cb6943d 100644 --- a/sportsref/cbb/players.py +++ b/sportsref/cbb/players.py @@ -23,7 +23,7 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): def __init__(self, player_id): self.player_id = player_id self.url_base = (sportsref.cbb.BASE_URL + - '/players/{0}').format(self.player_id) + '/cbb/players/{0}').format(self.player_id) self.main_url = self.url_base + '.htm' def __eq__(self, other): From f32f4c74df6b49a3d6de22cca473ecfb6085ed49 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 18 Jan 2018 13:05:36 -0500 Subject: [PATCH 06/57] added euro --- sportsref/cbb/__init__.py | 2 +- sportsref/cbb/players.py | 36 ++++++++---------------------------- sportsref/nba/players.py | 2 ++ sportsref/utils.py | 3 ++- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/sportsref/cbb/__init__.py b/sportsref/cbb/__init__.py index 841cff0..6879d90 100644 --- a/sportsref/cbb/__init__.py +++ b/sportsref/cbb/__init__.py @@ -8,7 +8,7 @@ from .teams import Team from .players import Player -BASE_URL = 'http://www.sports-reference.com' +BASE_URL = 'http://www.sports-reference.com/cbb' __all__ = [ 'BASE_URL', diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py index cb6943d..661043b 100644 --- a/sportsref/cbb/players.py +++ b/sportsref/cbb/players.py @@ -23,8 +23,8 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): def __init__(self, player_id): self.player_id = player_id self.url_base = (sportsref.cbb.BASE_URL + - '/cbb/players/{0}').format(self.player_id) - self.main_url = self.url_base + '.htm' + '/players/{0}').format(self.player_id) + self.main_url = self.url_base + '.html' def __eq__(self, other): return self.player_id == other.player_id @@ -105,29 +105,6 @@ def weight(self): except ValueError: return None - @sportsref.decorators.memoize - def hand(self): - """Returns the player's handedness. - :returns: 'L' for left-handed, 'R' for right-handed. - """ - doc = self.get_main_doc() - hand = re.search(r'Shoots:\s*(L|R)', doc.text()).group(1) - return hand - - @sportsref.decorators.memoize - def draft_pick(self): - """Returns when in the draft the player was picked. - :returns: TODO - """ - raise Exception('not yet implemented - nba.Player.draft_pick') - - @sportsref.decorators.memoize - def draft_year(self): - """Returns the year the player was selected (or undrafted). - :returns: TODO - """ - raise Exception('not yet implemented - nba.Player.draft_year') - @sportsref.decorators.kind_rpb(include_type=True) def _get_stats_table(self, table_id, kind='R', summary=False): """Gets a stats table from the player page; helper function that does @@ -139,17 +116,20 @@ def _get_stats_table(self, table_id, kind='R', summary=False): :returns: A DataFrame of stats. """ doc = self.get_main_doc() + #print(doc) table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) + + print(table_id) table = doc(table_id) - df = sportsref.utils.parse_table(table, flatten=(not summary), - footer=summary) + print(doc(table_id)) + df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df @sportsref.decorators.memoize def stats_per_game(self, kind='R', summary=False): """Returns a DataFrame of per-game box score stats.""" - return self._get_stats_table('per_game', kind=kind, summary=summary) + return self._get_stats_table('players_per_game', kind=kind, summary=summary) @sportsref.decorators.memoize def stats_totals(self, kind='R', summary=False): diff --git a/sportsref/nba/players.py b/sportsref/nba/players.py index 122dd6c..f0794e5 100644 --- a/sportsref/nba/players.py +++ b/sportsref/nba/players.py @@ -141,7 +141,9 @@ def _get_stats_table(self, table_id, kind='R', summary=False): doc = self.get_main_doc() table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) + print(table_id) table = doc(table_id) + print(table) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df diff --git a/sportsref/utils.py b/sportsref/utils.py index e900dd4..c0d4e94 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -54,7 +54,8 @@ def get_html(url): def parse_table(table, flatten=True, footer=False): """Parses a table from SR into a pandas dataframe. - :param table: the PyQuery object representing the HTML table + :param table: the PyQuery +object representing the HTML table :param flatten: if True, flattens relative URLs to IDs. otherwise, leaves all fields as text without cleaning. :param footer: If True, returns the summary/footer of the page. Recommended From c3553d0bdd0310b5cb04ea8a91695242bfa5dd5c Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 18 Jan 2018 13:06:06 -0500 Subject: [PATCH 07/57] added euro folder --- sportsref/euro/__init__.py | 20 ++ sportsref/euro/boxscores.py | 458 ++++++++++++++++++++++++ sportsref/euro/pbp.py | 671 ++++++++++++++++++++++++++++++++++++ sportsref/euro/players.py | 200 +++++++++++ sportsref/euro/seasons.py | 222 ++++++++++++ sportsref/euro/teams.py | 75 ++++ 6 files changed, 1646 insertions(+) create mode 100644 sportsref/euro/__init__.py create mode 100644 sportsref/euro/boxscores.py create mode 100644 sportsref/euro/pbp.py create mode 100644 sportsref/euro/players.py create mode 100644 sportsref/euro/seasons.py create mode 100644 sportsref/euro/teams.py diff --git a/sportsref/euro/__init__.py b/sportsref/euro/__init__.py new file mode 100644 index 0000000..1e3c5e8 --- /dev/null +++ b/sportsref/euro/__init__.py @@ -0,0 +1,20 @@ +from . import boxscores +from . import pbp +from . import seasons +from . import teams + +from .boxscores import BoxScore +from .seasons import Season +from .teams import Team +from .players import Player + +BASE_URL = 'http://www.sports-reference.com/euro' + +__all__ = [ + 'BASE_URL', + 'boxscores', 'BoxScore', + 'pbp', + 'seasons', 'Season', + 'teams', 'Team', + 'players', 'Player', +] diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py new file mode 100644 index 0000000..20f3a8e --- /dev/null +++ b/sportsref/euro/boxscores.py @@ -0,0 +1,458 @@ +import future +import future.utils + +import datetime +import re + +import numpy as np +import pandas as pd +from pyquery import PyQuery as pq + +import sportsref + + +class BoxScore( + future.utils.with_metaclass(sportsref.decorators.Cached, object) +): + + def __init__(self, boxscore_id): + self.boxscore_id = boxscore_id + + def __eq__(self, other): + return self.boxscore_id == other.boxscore_id + + def __hash__(self): + return hash(self.boxscore_id) + + def __repr__(self): + return 'BoxScore({})'.format(self.boxscore_id) + + @sportsref.decorators.memoize + def get_main_doc(self): + url = ('{}/boxscores/{}.html' + .format(sportsref.nba.BASE_URL, self.boxscore_id)) + doc = pq(sportsref.utils.get_html(url)) + return doc + + @sportsref.decorators.memoize + def get_subpage_doc(self, page): + url = (sportsref.nba.BASE_URL + + '/boxscores/{}/{}.html'.format(page, self.boxscore_id)) + doc = pq(sportsref.utils.get_html(url)) + return doc + + @sportsref.decorators.memoize + def date(self): + """Returns the date of the game. See Python datetime.date documentation + for more. + :returns: A datetime.date object with year, month, and day attributes. + """ + match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) + year, month, day = list(map(int, match.groups())) + return datetime.date(year=year, month=month, day=day) + + @sportsref.decorators.memoize + def weekday(self): + days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', + 'Saturday', 'Sunday'] + date = self.date() + wd = date.weekday() + return days[wd] + + @sportsref.decorators.memoize + def linescore(self): + """Returns the linescore for the game as a DataFrame.""" + doc = self.get_main_doc() + table = doc('table#line_score') + + columns = [th.text() for th in table('tr.thead').items('th')] + columns[0] = 'team_id' + + data = [ + [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] + for tr in list(table('tr.thead').next_all('tr').items()) + ] + + return pd.DataFrame(data, index=['away', 'home'], + columns=columns, dtype='float') + + @sportsref.decorators.memoize + def home(self): + """Returns home team ID. + :returns: 3-character string representing home team's ID. + """ + linescore = self.linescore() + return linescore.loc['home', 'team_id'] + + @sportsref.decorators.memoize + def away(self): + """Returns away team ID. + :returns: 3-character string representing away team's ID. + """ + linescore = self.linescore() + return linescore.loc['away', 'team_id'] + + @sportsref.decorators.memoize + def home_score(self): + """Returns score of the home team. + :returns: int of the home score. + """ + linescore = self.linescore() + return linescore.loc['home', 'T'] + + @sportsref.decorators.memoize + def away_score(self): + """Returns score of the away team. + :returns: int of the away score. + """ + linescore = self.linescore() + return linescore.loc['away', 'T'] + + @sportsref.decorators.memoize + def winner(self): + """Returns the team ID of the winning team. Returns NaN if a tie.""" + hmScore = self.home_score() + awScore = self.away_score() + if hmScore > awScore: + return self.home() + elif hmScore < awScore: + return self.away() + else: + return None + + @sportsref.decorators.memoize + def season(self): + """ + Returns the year ID of the season in which this game took place. + + :returns: An int representing the year of the season. + """ + d = self.date() + if d.month >= 9: + return d.year + 1 + else: + return d.year + + def _get_player_stats(self, table_id_fmt): + """Returns a DataFrame of player stats from the game (either basic or + advanced, depending on the argument. + + :param table_id_fmt: Format string for str.format with a placeholder + for the team ID (e.g. 'box_{}_basic') + :returns: DataFrame of player stats + """ + + # get data + doc = self.get_main_doc() + tms = self.away(), self.home() + tm_ids = [table_id_fmt.format(tm) for tm in tms] + tables = [doc('table#{}'.format(tm_id).lower()) for tm_id in tm_ids] + dfs = [sportsref.utils.parse_table(table) for table in tables] + + # clean data and add features + for i, (tm, df) in enumerate(zip(tms, dfs)): + no_time = df['mp'] == 0 + stat_cols = [col for col, dtype in df.dtypes.items() + if dtype != 'object'] + df.loc[no_time, stat_cols] = 0 + df['team_id'] = tm + df['is_home'] = i == 1 + df['is_starter'] = [p < 5 for p in range(df.shape[0])] + df.drop_duplicates(subset='player_id', keep='first', inplace=True) + + return pd.concat(dfs) + + @sportsref.decorators.memoize + def basic_stats(self): + """Returns a DataFrame of basic player stats from the game.""" + return self._get_player_stats('box_{}_basic') + + @sportsref.decorators.memoize + def advanced_stats(self): + """Returns a DataFrame of advanced player stats from the game.""" + return self._get_player_stats('box_{}_advanced') + + @sportsref.decorators.memoize + def pbp(self, dense_lineups=False, sparse_lineups=False): + """Returns a dataframe of the play-by-play data from the game. + + :param dense_lineups: If True, adds 10 columns containing the names of + the players on the court. Defaults to False. + :param sparse_lineups: If True, adds binary columns denoting whether a + given player is in the game at the time of a pass. Defaults to + False. + :returns: pandas DataFrame of play-by-play. Similar to GPF. + """ + try: + doc = self.get_subpage_doc('pbp') + except: + raise ValueError( + 'Error fetching PBP subpage for boxscore {}' + .format(self.boxscore_id) + ) + table = doc('table#pbp') + trs = [ + tr for tr in list(table('tr').items()) + if (not tr.attr['class'] or # regular data rows + tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds + ] + rows = [tr.children('td') for tr in trs] + n_rows = len(trs) + data = [] + cur_qtr = 0 + bsid = self.boxscore_id + + for i in range(n_rows): + tr = trs[i] + row = rows[i] + p = {} + + # increment cur_qtr when we hit a new quarter + if tr.attr['id'] and tr.attr['id'].startswith('q'): + assert int(tr.attr['id'][1:]) == cur_qtr + 1 + cur_qtr += 1 + continue + + # add time of play to entry + t_str = row.eq(0).text() + t_regex = r'(\d+):(\d+)\.(\d+)' + mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) + endQ = (12 * 60 * min(cur_qtr, 4) + + 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) + secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) + p['secs_elapsed'] = secsElapsed + p['clock_time'] = t_str + p['quarter'] = cur_qtr + + # handle single play description + # ex: beginning/end of quarter, jump ball + if row.length == 2: + desc = row.eq(1) + # handle jump balls + if desc.text().lower().startswith('jump ball: '): + p['is_jump_ball'] = True + jb_str = sportsref.utils.flatten_links(desc) + p.update( + sportsref.nba.pbp.parse_play(bsid, jb_str, None) + ) + # ignore rows marking beginning/end of quarters + elif ( + desc.text().lower().startswith('start of ') or + desc.text().lower().startswith('end of ') + ): + continue + # if another case, log and continue + else: + if not desc.text().lower().startswith('end of '): + print(( + '{}, Q{}, {} other case: {}' + .format(self.boxscore_id, cur_qtr, + t_str, desc.text()) + )) + continue + + # handle team play description + # ex: shot, turnover, rebound, foul, sub, etc. + elif row.length == 6: + aw_desc, hm_desc = row.eq(1), row.eq(5) + is_hm_play = bool(hm_desc.text()) + desc = hm_desc if is_hm_play else aw_desc + desc = sportsref.utils.flatten_links(desc) + # parse the play + new_p = sportsref.nba.pbp.parse_play(bsid, desc, is_hm_play) + if not new_p: + continue + elif isinstance(new_p, list): + # this happens when a row needs to be expanded to 2 rows; + # ex: double personal foul -> two PF rows + + # first, update and append the first row + orig_p = dict(p) + p.update(new_p[0]) + data.append(p) + # second, set up the second row to be appended below + p = orig_p + new_p = new_p[1] + elif new_p.get('is_error'): + print(("can't parse: {}, boxscore: {}" + .format(desc, self.boxscore_id))) + # import pdb; pdb.set_trace() + p.update(new_p) + + # otherwise, I don't know what this was + else: + raise Exception(("don't know how to handle row of length {}" + .format(row.length))) + + data.append(p) + + # convert to DataFrame and clean columns + df = pd.DataFrame.from_records(data) + df.sort_values('secs_elapsed', inplace=True, kind='mergesort') + df = sportsref.nba.pbp.clean_features(df) + + # add columns for home team, away team, boxscore_id, date + away, home = self.away(), self.home() + df['home'] = home + df['away'] = away + df['boxscore_id'] = self.boxscore_id + df['season'] = self.season() + date = self.date() + df['year'] = date.year + df['month'] = date.month + df['day'] = date.day + + def _clean_rebs(df): + df.reset_index(drop=True, inplace=True) + no_reb_after = ( + (df.fta_num < df.tot_fta) | df.is_ftm | + df.get('is_tech_fta', False) + ).shift(1).fillna(False) + no_reb_before = ( + (df.fta_num == df.tot_fta) + ).shift(-1).fillna(False) + se_end_qtr = df.loc[ + df.clock_time == '0:00.0', 'secs_elapsed' + ].unique() + no_reb_when = df.secs_elapsed.isin(se_end_qtr) + drop_mask = ( + (df.rebounder == 'Team') & + (no_reb_after | no_reb_before | no_reb_when) + ).nonzero()[0] + df.drop(drop_mask, axis=0, inplace=True) + df.reset_index(drop=True, inplace=True) + return df + + # get rid of 'rebounds' after FTM, non-final FTA, or tech FTA + df = _clean_rebs(df) + + # track possession number for each possession + # TODO: see 201604130PHO, secs_elapsed == 2756 + # things that end a poss: + # FGM, dreb, TO, end of Q, made last FT, lost jump ball, + # def goaltending, shot clock violation + new_poss = (df.off_team == df.home).diff().fillna(False) + # def rebound considered part of the new possession + df['poss_id'] = np.cumsum(new_poss) + df.is_dreb + # create poss_id with rebs -> new possessions for granular groupbys + poss_id_reb = np.cumsum(new_poss | df.is_reb) + + # make sure plays with the same clock time are in the right order + # TODO: make sort_cols depend on what cols are in the play? + # or combine related plays, like and-1 shot and foul + # issues come up with FGA after timeout in 201604130LAL + # issues come up with PF between FGA and DREB in 201604120SAS + sort_cols = [col for col in + ['is_reb', 'is_fga', 'is_pf', 'is_tech_foul', + 'is_ejection', 'is_tech_fta', 'is_timeout', 'is_pf_fta', + 'fta_num', 'is_viol', 'is_to', 'is_jump_ball', 'is_sub'] + if col in df.columns] + asc_true = ['fta_num'] + ascend = [(col in asc_true) for col in sort_cols] + for label, group in df.groupby([df.secs_elapsed, poss_id_reb]): + if len(group) > 1: + df.loc[group.index, :] = group.sort_values( + sort_cols, ascending=ascend, kind='mergesort' + ).values + + # 2nd pass: get rid of 'rebounds' after FTM, non-final FTA, etc. + df = _clean_rebs(df) + + # makes sure off/def and poss_id are correct for subs after rearranging + # some possessions above + df.loc[df['is_sub'], ['off_team', 'def_team', 'poss_id']] = np.nan + df.off_team.fillna(method='bfill', inplace=True) + df.def_team.fillna(method='bfill', inplace=True) + df.poss_id.fillna(method='bfill', inplace=True) + # make off_team and def_team NaN for jump balls + if 'is_jump_ball' in df.columns: + df.loc[df['is_jump_ball'], ['off_team', 'def_team']] = np.nan + + # make sure 'off_team' is always the team shooting FTs, even on techs + # (impt for keeping track of the score) + if 'is_tech_fta' in df.columns: + tech_fta = df['is_tech_fta'] + df.loc[tech_fta, 'off_team'] = df.loc[tech_fta, 'fta_team'] + df.loc[tech_fta, 'def_team'] = np.where( + df.loc[tech_fta, 'off_team'] == home, away, home + ) + df.drop('fta_team', axis=1, inplace=True) + # redefine poss_id_reb + new_poss = (df.off_team == df.home).diff().fillna(False) + poss_id_reb = np.cumsum(new_poss | df.is_reb) + + # get rid of redundant subs + for (se, tm, pnum), group in df[df.is_sub].groupby( + [df.secs_elapsed, df.sub_team, poss_id_reb] + ): + if len(group) > 1: + sub_in = set() + sub_out = set() + # first, figure out who's in and who's out after subs + for i, row in group.iterrows(): + if row['sub_in'] in sub_out: + sub_out.remove(row['sub_in']) + else: + sub_in.add(row['sub_in']) + if row['sub_out'] in sub_in: + sub_in.remove(row['sub_out']) + else: + sub_out.add(row['sub_out']) + assert len(sub_in) == len(sub_out) + # second, add those subs + n_subs = len(sub_in) + for idx, p_in, p_out in zip( + group.index[:n_subs], sub_in, sub_out + ): + assert df.loc[idx, 'is_sub'] + df.loc[idx, 'sub_in'] = p_in + df.loc[idx, 'sub_out'] = p_out + df.loc[idx, 'sub_team'] = tm + df.loc[idx, 'detail'] = ( + '{} enters the game for {}'.format(p_in, p_out) + ) + # third, if applicable, remove old sub entries when there are + # redundant subs + n_extra = len(group) - len(sub_in) + if n_extra: + extra_idxs = group.index[-n_extra:] + df.drop(extra_idxs, axis=0, inplace=True) + + df.reset_index(drop=True, inplace=True) + + # add column for pts and score + df['pts'] = (df['is_ftm'] + 2 * df['is_fgm'] + + (df['is_fgm'] & df['is_three'])) + df['hm_pts'] = np.where(df.off_team == df.home, df.pts, 0) + df['aw_pts'] = np.where(df.off_team == df.away, df.pts, 0) + df['hm_score'] = np.cumsum(df['hm_pts']) + df['aw_score'] = np.cumsum(df['aw_pts']) + + # more helpful columns + # "play" is differentiated from "poss" by counting OReb as new play + # "plays" end with non-and1 FGA, TO, last non-tech FTA, or end of qtr + # (or double lane viol) + new_qtr = df.quarter.diff().shift(-1).fillna(False).astype(bool) + and1 = (df.is_fgm & df.is_pf.shift(-1).fillna(False) & + df.is_fta.shift(-2).fillna(False) & + ~df.secs_elapsed.diff().shift(-1).fillna(False).astype(bool)) + double_lane = (df.get('viol_type') == 'double lane') + new_play = df.eval('(is_fga & ~(@and1)) | is_to | @new_qtr |' + '(is_fta & ~is_tech_fta & fta_num == tot_fta) |' + '@double_lane') + df['play_id'] = np.cumsum(new_play).shift(1).fillna(0) + df['hm_off'] = df.off_team == df.home + + # get lineup data + if dense_lineups: + df = pd.concat( + (df, sportsref.nba.pbp.get_dense_lineups(df)), axis=1 + ) + if sparse_lineups: + df = pd.concat( + (df, sportsref.nba.pbp.get_sparse_lineups(df)), axis=1 + ) + + # TODO: add shot clock as a feature + + return df diff --git a/sportsref/euro/pbp.py b/sportsref/euro/pbp.py new file mode 100644 index 0000000..a67eebd --- /dev/null +++ b/sportsref/euro/pbp.py @@ -0,0 +1,671 @@ +from builtins import enumerate, int, list, range, zip + +import operator +import re + +import numpy as np +import pandas as pd + +import sportsref + +PLAYER_RE = r'\w{0,7}\d{2}' + +HM_LINEUP_COLS = ['hm_player{}'.format(i) for i in range(1, 6)] +AW_LINEUP_COLS = ['aw_player{}'.format(i) for i in range(1, 6)] +ALL_LINEUP_COLS = AW_LINEUP_COLS + HM_LINEUP_COLS + + +def sparse_lineup_cols(df): + regex = '{}_in'.format(PLAYER_RE) + return [c for c in df.columns if re.match(regex, c)] + + +def parse_play(boxscore_id, details, is_hm): + """Parse play details from a play-by-play string describing a play. + + Assuming valid input, this function returns structured data in a dictionary + describing the play. If the play detail string was invalid, this function + returns None. + + :param boxscore_id: the boxscore ID of the play + :param details: detail string for the play + :param is_hm: bool indicating whether the offense is at home + :param returns: dictionary of play attributes or None if invalid + :rtype: dictionary or None + """ + # if input isn't a string, return None + if not details or not isinstance(details, str): + return None + + bs = sportsref.nba.BoxScore(boxscore_id) + aw, hm = bs.away(), bs.home() + season = sportsref.nba.Season(bs.season()) + hm_roster = set(bs.basic_stats().query('is_home == True').player_id.values) + + p = {} + p['detail'] = details + p['home'] = hm + p['away'] = aw + p['is_home_play'] = is_hm + + # parsing field goal attempts + shotRE = (r'(?P{0}) (?Pmakes|misses) ' + '(?P2|3)\-pt shot').format(PLAYER_RE) + distRE = r' (?:from (?P\d+) ft|at rim)' + assistRE = r' \(assist by (?P{0})\)'.format(PLAYER_RE) + blockRE = r' \(block by (?P{0})\)'.format(PLAYER_RE) + shotRE = r'{0}{1}(?:{2}|{3})?'.format(shotRE, distRE, assistRE, blockRE) + m = re.match(shotRE, details, re.IGNORECASE) + if m: + p['is_fga'] = True + p.update(m.groupdict()) + p['shot_dist'] = p['shot_dist'] if p['shot_dist'] is not None else 0 + p['shot_dist'] = int(p['shot_dist']) + p['is_fgm'] = p['is_fgm'] == 'makes' + p['is_three'] = p['is_three'] == '3' + p['is_assist'] = pd.notnull(p.get('assister')) + p['is_block'] = pd.notnull(p.get('blocker')) + shooter_home = p['shooter'] in hm_roster + p['off_team'] = hm if shooter_home else aw + p['def_team'] = aw if shooter_home else hm + return p + + # parsing jump balls + jumpRE = ((r'Jump ball: (?P{0}) vs\. (?P{0})' + r'(?: \((?P{0}) gains possession\))?') + .format(PLAYER_RE)) + m = re.match(jumpRE, details, re.IGNORECASE) + if m: + p['is_jump_ball'] = True + p.update(m.groupdict()) + return p + + # parsing rebounds + rebRE = (r'(?POffensive|Defensive) rebound' + r' by (?P{0}|Team)').format(PLAYER_RE) + m = re.match(rebRE, details, re.I) + if m: + p['is_reb'] = True + p.update(m.groupdict()) + p['is_oreb'] = p['is_oreb'].lower() == 'offensive' + p['is_dreb'] = not p['is_oreb'] + if p['rebounder'] == 'Team': + p['reb_team'], other = (hm, aw) if is_hm else (aw, hm) + else: + reb_home = p['rebounder'] in hm_roster + p['reb_team'], other = (hm, aw) if reb_home else (aw, hm) + p['off_team'] = p['reb_team'] if p['is_oreb'] else other + p['def_team'] = p['reb_team'] if p['is_dreb'] else other + return p + + # parsing free throws + ftRE = (r'(?P{}) (?Pmakes|misses) ' + r'(?Ptechnical )?(?Pflagrant )?' + r'(?Pclear path )?free throw' + r'(?: (?P\d+) of (?P\d+))?').format(PLAYER_RE) + m = re.match(ftRE, details, re.I) + if m: + p['is_fta'] = True + p.update(m.groupdict()) + p['is_ftm'] = p['is_ftm'] == 'makes' + p['is_tech_fta'] = bool(p['is_tech_fta']) + p['is_flag_fta'] = bool(p['is_flag_fta']) + p['is_clearpath_fta'] = bool(p['is_clearpath_fta']) + p['is_pf_fta'] = not p['is_tech_fta'] + if p['tot_fta']: + p['tot_fta'] = int(p['tot_fta']) + if p['fta_num']: + p['fta_num'] = int(p['fta_num']) + ft_home = p['ft_shooter'] in hm_roster + p['fta_team'] = hm if ft_home else aw + if not p['is_tech_fta']: + p['off_team'] = hm if ft_home else aw + p['def_team'] = aw if ft_home else hm + return p + + # parsing substitutions + subRE = (r'(?P{0}) enters the game for ' + r'(?P{0})').format(PLAYER_RE) + m = re.match(subRE, details, re.I) + if m: + p['is_sub'] = True + p.update(m.groupdict()) + sub_home = p['sub_in'] in hm_roster or p['sub_out'] in hm_roster + p['sub_team'] = hm if sub_home else aw + return p + + # parsing turnovers + toReasons = (r'(?P[^;]+)(?:; steal by ' + r'(?P{0}))?').format(PLAYER_RE) + toRE = (r'Turnover by (?P{}|Team) ' + r'\((?:{})\)').format(PLAYER_RE, toReasons) + m = re.match(toRE, details, re.I) + if m: + p['is_to'] = True + p.update(m.groupdict()) + p['to_type'] = p['to_type'].lower() + if p['to_type'] == 'offensive foul': + return None + p['is_steal'] = pd.notnull(p['stealer']) + p['is_travel'] = p['to_type'] == 'traveling' + p['is_shot_clock_viol'] = p['to_type'] == 'shot clock' + p['is_oob'] = p['to_type'] == 'step out of bounds' + p['is_three_sec_viol'] = p['to_type'] == '3 sec' + p['is_backcourt_viol'] = p['to_type'] == 'back court' + p['is_off_goaltend'] = p['to_type'] == 'offensive goaltending' + p['is_double_dribble'] = p['to_type'] == 'dbl dribble' + p['is_discont_dribble'] = p['to_type'] == 'discontinued dribble' + p['is_carry'] = p['to_type'] == 'palming' + if p['to_by'] == 'Team': + p['off_team'] = hm if is_hm else aw + p['def_team'] = aw if is_hm else hm + else: + to_home = p['to_by'] in hm_roster + p['off_team'] = hm if to_home else aw + p['def_team'] = aw if to_home else hm + return p + + # parsing shooting fouls + shotFoulRE = (r'Shooting(?P block)? foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(shotFoulRE, details, re.I) + if m: + p['is_pf'] = True + p['is_shot_foul'] = True + p.update(m.groupdict()) + p['is_block_foul'] = bool(p['is_block_foul']) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing offensive fouls + offFoulRE = (r'Offensive(?P charge)? foul ' + r'by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(offFoulRE, details, re.I) + if m: + p['is_pf'] = True + p['is_off_foul'] = True + p['is_to'] = True + p['to_type'] = 'offensive foul' + p.update(m.groupdict()) + p['is_charge'] = bool(p['is_charge']) + p['fouler'] = p['to_by'] + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = hm if foul_on_home else aw + p['def_team'] = aw if foul_on_home else hm + p['foul_team'] = p['off_team'] + return p + + # parsing personal fouls + foulRE = (r'Personal (?Ptake )?(?Pblock )?' + r'foul by (?P{0})(?: \(drawn by ' + r'(?P{0})\))?').format(PLAYER_RE) + m = re.match(foulRE, details, re.I) + if m: + p['is_pf'] = True + p.update(m.groupdict()) + p['is_take_foul'] = bool(p['is_take_foul']) + p['is_block_foul'] = bool(p['is_block_foul']) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # TODO: parsing double personal fouls + # double_foul_re = (r'Double personal foul by (?P{0}) and ' + # r'(?P{0})').format(PLAYER_RE) + # m = re.match(double_Foul_re, details, re.I) + # if m: + # p['is_pf'] = True + # p.update(m.groupdict()) + # p['off_team'] = + + # parsing loose ball fouls + looseBallRE = (r'Loose ball foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(looseBallRE, details, re.I) + if m: + p['is_pf'] = True + p['is_loose_ball_foul'] = True + p.update(m.groupdict()) + foul_home = p['fouler'] in hm_roster + p['foul_team'] = hm if foul_home else aw + return p + + # parsing punching fouls + # TODO + + # parsing away from play fouls + awayFromBallRE = ((r'Away from play foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?') + .format(PLAYER_RE)) + m = re.match(awayFromBallRE, details, re.I) + if m: + p['is_pf'] = True + p['is_away_from_play_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + # TODO: figure out who had the ball based on previous play + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing inbound fouls + inboundRE = (r'Inbound foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(inboundRE, details, re.I) + if m: + p['is_pf'] = True + p['is_inbound_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing flagrant fouls + flagrantRE = (r'Flagrant foul type (?P1|2) by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(flagrantRE, details, re.I) + if m: + p['is_pf'] = True + p['is_flagrant'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing clear path fouls + clearPathRE = (r'Clear path foul by (?P{0})' + r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) + m = re.match(clearPathRE, details, re.I) + if m: + p['is_pf'] = True + p['is_clear_path_foul'] = True + p.update(m.groupdict()) + foul_on_home = p['fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing timeouts + timeoutRE = r'(?P.*?) (?:full )?timeout' + m = re.match(timeoutRE, details, re.I) + if m: + p['is_timeout'] = True + p.update(m.groupdict()) + isOfficialTO = p['timeout_team'].lower() == 'official' + name_to_id = season.team_names_to_ids() + p['timeout_team'] = ( + 'Official' if isOfficialTO else + name_to_id.get(hm, name_to_id.get(aw, p['timeout_team'])) + ) + return p + + # parsing technical fouls + techRE = (r'(?PHanging )?' + r'(?PTaunting )?' + r'(?PIll def )?' + r'(?PDelay )?' + r'(?PNon unsport )?' + r'tech(?:nical)? foul by ' + r'(?P{0}|Team)').format(PLAYER_RE) + m = re.match(techRE, details, re.I) + if m: + p['is_tech_foul'] = True + p.update(m.groupdict()) + p['is_hanging'] = bool(p['is_hanging']) + p['is_taunting'] = bool(p['is_taunting']) + p['is_ill_def'] = bool(p['is_ill_def']) + p['is_delay'] = bool(p['is_delay']) + p['is_unsport'] = bool(p['is_unsport']) + foul_on_home = p['tech_fouler'] in hm_roster + p['foul_team'] = hm if foul_on_home else aw + return p + + # parsing ejections + ejectRE = r'(?P{0}|Team) ejected from game'.format(PLAYER_RE) + m = re.match(ejectRE, details, re.I) + if m: + p['is_ejection'] = True + p.update(m.groupdict()) + if p['ejectee'] == 'Team': + p['ejectee_team'] = hm if is_hm else aw + else: + eject_home = p['ejectee'] in hm_roster + p['ejectee_team'] = hm if eject_home else aw + return p + + # parsing defensive 3 seconds techs + def3TechRE = (r'(?:Def 3 sec tech foul|Defensive three seconds)' + r' by (?P{})').format(PLAYER_RE) + m = re.match(def3TechRE, details, re.I) + if m: + p['is_tech_foul'] = True + p['is_def_three_secs'] = True + p.update(m.groupdict()) + foul_on_home = p['tech_fouler'] in hm_roster + p['off_team'] = aw if foul_on_home else hm + p['def_team'] = hm if foul_on_home else aw + p['foul_team'] = p['def_team'] + return p + + # parsing violations + violRE = (r'Violation by (?P{0}|Team) ' + r'\((?P.*)\)').format(PLAYER_RE) + m = re.match(violRE, details, re.I) + if m: + p['is_viol'] = True + p.update(m.groupdict()) + if p['viol_type'] == 'kicked_ball': + p['is_to'] = True + p['to_by'] = p['violator'] + if p['violator'] == 'Team': + p['viol_team'] = hm if is_hm else aw + else: + viol_home = p['violator'] in hm_roster + p['viol_team'] = hm if viol_home else aw + return p + + p['is_error'] = True + return p + + +def clean_features(df): + """Fixes up columns of the passed DataFrame, such as casting T/F columns to + boolean and filling in NaNs for team and opp. + + :param df: DataFrame of play-by-play data. + :returns: Dataframe with cleaned columns. + """ + df = pd.DataFrame(df) + + bool_vals = set([True, False, None, np.nan]) + sparse_cols = sparse_lineup_cols(df) + for col in df: + + # make indicator columns boolean type (and fill in NaNs) + if set(df[col].unique()[:5]) <= bool_vals: + df[col] = (df[col] == True) + + # fill NaN's in sparse lineup columns to 0 + elif col in sparse_cols: + df[col] = df[col].fillna(0) + + # fix free throw columns on technicals + df.loc[df.is_tech_fta, ['fta_num', 'tot_fta']] = 1 + + # fill in NaN's/fix off_team and def_team columns + df.off_team.fillna(method='bfill', inplace=True) + df.def_team.fillna(method='bfill', inplace=True) + df.off_team.fillna(method='ffill', inplace=True) + df.def_team.fillna(method='ffill', inplace=True) + + return df + + +def clean_multigame_features(df): + """TODO: Docstring for clean_multigame_features. + + :df: TODO + :returns: TODO + """ + df = pd.DataFrame(df) + if df.index.value_counts().max() > 1: + df.reset_index(drop=True, inplace=True) + + df = clean_features(df) + + # if it's many games in one DataFrame, make poss_id and play_id unique + for col in ('play_id', 'poss_id'): + diffs = df[col].diff().fillna(0) + if (diffs < 0).any(): + new_col = np.cumsum(diffs.astype(bool)) + df.eval('{} = @new_col'.format(col), inplace=True) + + return df + + +def get_period_starters(df): + """TODO + """ + + def players_from_play(play): + """Figures out what players are in the game based on the players + mentioned in a play. Returns away and home players as two sets. + + :param play: A dictionary representing a parsed play. + :returns: (aw_players, hm_players) + :rtype: tuple of lists + """ + # if it's a tech FT from between periods, don't count this play + if ( + play['clock_time'] == '12:00.0' and + (play.get('is_tech_foul') or play.get('is_tech_fta')) + ): + return [], [] + + stats = sportsref.nba.BoxScore(play['boxscore_id']).basic_stats() + home_grouped = stats.groupby('is_home') + hm_roster = set(home_grouped.player_id.get_group(True).values) + aw_roster = set(home_grouped.player_id.get_group(False).values) + player_keys = [ + 'assister', 'away_jumper', 'blocker', 'drew_foul', 'fouler', + 'ft_shooter', 'gains_poss', 'home_jumper', 'rebounder', 'shooter', + 'stealer', 'sub_in', 'sub_out', 'to_by' + ] + players = [p for p in play[player_keys] if pd.notnull(p)] + + aw_players = [p for p in players if p in aw_roster] + hm_players = [p for p in players if p in hm_roster] + return aw_players, hm_players + + # create a mapping { quarter => (away_starters, home_starters) } + n_periods = df.quarter.nunique() + period_starters = [(set(), set()) for _ in range(n_periods)] + + # fill out this mapping quarter by quarter + for qtr, qtr_grp in df.groupby(df.quarter): + aw_starters, hm_starters = period_starters[qtr-1] + exclude = set() + # loop through sets of plays that happen at the "same time" + for label, time_grp in qtr_grp.groupby(qtr_grp.secs_elapsed): + # first, if they sub in and weren't already starters, exclude them + sub_ins = set(time_grp.sub_in.dropna().values) + exclude.update(sub_ins - aw_starters - hm_starters) + # second, figure out new starters from each play at this time + for i, row in time_grp.iterrows(): + aw_players, hm_players = players_from_play(row) + # update overall sets for the quarter + aw_starters.update(aw_players) + hm_starters.update(hm_players) + # remove excluded (subbed-in) players + hm_starters -= exclude + aw_starters -= exclude + # check whether we have found all starters + if len(hm_starters) > 5 or len(aw_starters) > 5: + import ipdb + ipdb.set_trace() + if len(hm_starters) >= 5 and len(aw_starters) >= 5: + break + + if len(hm_starters) != 5 or len(aw_starters) != 5: + print(('WARNING: wrong number of starters for a team in Q{} of {}' + .format(qtr, df.boxscore_id.iloc[0]))) + + return period_starters + + +def get_sparse_lineups(df): + """TODO: Docstring for get_sparse_lineups. + + :param df: TODO + :returns: TODO + """ + + # get the lineup data using get_dense_lineups if necessary + if (set(ALL_LINEUP_COLS) - set(df.columns)): + lineup_df = get_dense_lineups(df) + else: + lineup_df = df[ALL_LINEUP_COLS] + + # create the sparse representation + hm_lineups = lineup_df[HM_LINEUP_COLS].values + aw_lineups = lineup_df[AW_LINEUP_COLS].values + # +1 for home, -1 for away + hm_df = pd.DataFrame([ + {'{}_in'.format(player_id): 1 for player_id in lineup} + for lineup in hm_lineups + ], dtype=int) + aw_df = pd.DataFrame([ + {'{}_in'.format(player_id): -1 for player_id in lineup} + for lineup in aw_lineups + ], dtype=int) + sparse_df = pd.concat((hm_df, aw_df), axis=1).fillna(0) + return sparse_df + + +def get_dense_lineups(df): + """Returns a new DataFrame based on the one it is passed. Specifically, it + adds five columns for each team (ten total), where each column has the ID + of a player on the court during the play. + + This information is figured out sequentially from the game's substitution + data in the passed DataFrame, so the DataFrame passed as an argument must + be from a specific BoxScore (rather than a DataFrame of non-consecutive + plays). That is, the DataFrame must be of the form returned by + :func:`nba.BoxScore.pbp `. + + .. note:: Note that the lineups reflect the teams in the game when the play + happened, not after the play. For example, if a play is a substitution, + the lineups for that play will be the lineups before the substituion + occurs. + + :param df: A DataFrame of a game's play-by-play data. + :returns: A DataFrame with additional lineup columns. + + """ + # TODO: add this precondition to documentation + assert df['boxscore_id'].nunique() == 1 + + def lineup_dict(aw_lineup, hm_lineup): + """Returns a dictionary of lineups to be converted to columns. + Specifically, the columns are 'aw_player1' through 'aw_player5' and + 'hm_player1' through 'hm_player5'. + + :param aw_lineup: The away team's current lineup. + :param hm_lineup: The home team's current lineup. + :returns: A dictionary of lineups. + """ + return { + '{}_player{}'.format(tm, i+1): player + for tm, lineup in zip(['aw', 'hm'], [aw_lineup, hm_lineup]) + for i, player in enumerate(lineup) + } + + def handle_sub(row, aw_lineup, hm_lineup): + """Modifies the aw_lineup and hm_lineup lists based on the substitution + that takes place in the given row.""" + assert row['is_sub'] + sub_lineup = hm_lineup if row['sub_team'] == row['home'] else aw_lineup + try: + # make the sub + idx = sub_lineup.index(row['sub_out']) + sub_lineup[idx] = row['sub_in'] + except ValueError: + # if the sub was double-entered and it's already been executed... + if ( + row['sub_in'] in sub_lineup + and row['sub_out'] not in sub_lineup + ): + return aw_lineup, hm_lineup + # otherwise, let's print and pretend this never happened + print(('ERROR IN SUB IN {}, Q{}, {}: {}' + .format(row['boxscore_id'], row['quarter'], + row['clock_time'], row['detail']))) + raise + return aw_lineup, hm_lineup + + per_starters = get_period_starters(df) + cur_qtr = 0 + aw_lineup, hm_lineup = [], [] + df = df.reset_index(drop=True) + lineups = [{} for _ in range(df.shape[0])] + + # loop through select plays to determine lineups + sub_or_per_start = df.is_sub | df.quarter.diff().astype(bool) + for i, row in df.loc[sub_or_per_start].iterrows(): + if row['quarter'] > cur_qtr: + # first row in a quarter + assert row['quarter'] == cur_qtr + 1 + # first, finish up the last quarter's lineups + if cur_qtr > 0 and not df.loc[i-1, 'is_sub']: + lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) + # then, move on to the quarter, and enter the starting lineups + cur_qtr += 1 + aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) + lineups[i] = lineup_dict(aw_lineup, hm_lineup) + # if the first play in the quarter is a sub, handle that + if row['is_sub']: + aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) + else: + # during the quarter + # update lineups first then change lineups based on subs + lineups[i] = lineup_dict(aw_lineup, hm_lineup) + if row['is_sub']: + aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) + + # create and clean DataFrame + lineup_df = pd.DataFrame(lineups) + if lineup_df.iloc[-1].isnull().all(): + lineup_df.iloc[-1] = lineup_dict(aw_lineup, hm_lineup) + lineup_df = lineup_df.groupby(df.quarter).fillna(method='bfill') + + # fill in NaN's based on minutes played + bool_mat = lineup_df.isnull() + mask = bool_mat.any(axis=1) + if mask.any(): + bs = sportsref.nba.BoxScore(df.boxscore_id[0]) + # first, get the true minutes played from the box score + stats = sportsref.nba.BoxScore(df.boxscore_id.iloc[0]).basic_stats() + true_mp = pd.Series( + stats.query('mp > 0')[['player_id', 'mp']] + .set_index('player_id').to_dict()['mp'] + ) * 60 + # next, calculate minutes played based on the lineup data + calc_mp = pd.Series( + {p: (df.secs_elapsed.diff() * + [p in row for row in lineup_df.values]).sum() + for p in stats.query('mp > 0').player_id.values}) + # finally, figure which players are missing minutes + diff = true_mp - calc_mp + players_missing = diff.loc[diff.abs() >= 150] + hm_roster = bs.basic_stats().query('is_home == True').player_id.values + missing_df = pd.DataFrame( + {'secs': players_missing.values, + 'is_home': players_missing.index.isin(hm_roster)}, + index=players_missing.index + ) + + if missing_df.empty: + # TODO: log this as a warning (or error?) + print('There are NaNs in the lineup data, but no players were ' + 'found to be missing significant minutes') + else: + # import ipdb + # ipdb.set_trace() + for is_home, group in missing_df.groupby('is_home'): + player_id = group.index.item() + tm_cols = (sportsref.nba.pbp.HM_LINEUP_COLS if is_home else + sportsref.nba.pbp.AW_LINEUP_COLS) + row_mask = lineup_df[tm_cols].isnull().any(axis=1) + lineup_df.loc[row_mask, tm_cols] = ( + lineup_df.loc[row_mask, tm_cols].fillna(player_id).values + ) + + return lineup_df diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py new file mode 100644 index 0000000..661043b --- /dev/null +++ b/sportsref/euro/players.py @@ -0,0 +1,200 @@ +import future +import future.utils + +import datetime +import re + +import numpy as np +from pyquery import PyQuery as pq + +import sportsref + +__all__ = [ + 'Player', +] + + +class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + """Each instance of this class represents an CBB player, uniquely + identified by a player ID. The instance methods give various data available + from the player's Sports Reference player page.""" + + def __init__(self, player_id): + self.player_id = player_id + self.url_base = (sportsref.cbb.BASE_URL + + '/players/{0}').format(self.player_id) + self.main_url = self.url_base + '.html' + + def __eq__(self, other): + return self.player_id == other.player_id + + def __hash__(self): + return hash(self.player_id) + + def __repr__(self): + return 'Player({})'.format(self.player_id) + + def __str__(self): + return self.name() + + @sportsref.decorators.memoize + def get_main_doc(self): + return pq(sportsref.utils.get_html(self.main_url)) + + @sportsref.decorators.memoize + def get_sub_doc(self, rel_url): + url = '{}/{}'.format(self.url_base, rel_url) + return pq(sportsref.utils.get_html(url)) + + @sportsref.decorators.memoize + def name(self): + """Returns the name of the player as a string.""" + doc = self.get_main_doc() + return doc('h1[itemprop="name"]').text() + + @sportsref.decorators.memoize + def age(self, year, month=2, day=1): + """Returns the age of the player on a given date. + + :year: int representing the year. + :month: int representing the month (1-12). + :day: int representing the day within the month (1-31). + :returns: Age in years as a float. + """ + doc = self.get_main_doc() + date_string = doc('span[itemprop="birthDate"]').attr('data-birth') + regex = r'(\d{4})\-(\d{2})\-(\d{2})' + date_args = list(map(int, re.match(regex, date_string).groups())) + birth_date = datetime.date(*date_args) + age_date = datetime.date(year=year, month=month, day=day) + delta = age_date - birth_date + age = delta.days / 365. + return age + + @sportsref.decorators.memoize + def position(self): + """TODO: Docstring for position. + :returns: TODO + """ + raise Exception('not yet implemented - nba.Player.position') + + @sportsref.decorators.memoize + def height(self): + """Returns the player's height (in inches). + :returns: An int representing a player's height in inches. + """ + doc = self.get_main_doc() + raw = doc('span[itemprop="height"]').text() + try: + feet, inches = list(map(int, raw.split('-'))) + return feet * 12 + inches + except ValueError: + return None + + @sportsref.decorators.memoize + def weight(self): + """Returns the player's weight (in pounds). + :returns: An int representing a player's weight in pounds. + """ + doc = self.get_main_doc() + raw = doc('span[itemprop="weight"]').text() + try: + weight = re.match(r'(\d+)lb', raw).group(1) + return int(weight) + except ValueError: + return None + + @sportsref.decorators.kind_rpb(include_type=True) + def _get_stats_table(self, table_id, kind='R', summary=False): + """Gets a stats table from the player page; helper function that does + the work for per-game, per-100-poss, etc. stats. + + :table_id: the ID of the HTML table. + :kind: specifies regular season, playoffs, or both. One of 'R', 'P', + 'B'. Defaults to 'R'. + :returns: A DataFrame of stats. + """ + doc = self.get_main_doc() + #print(doc) + table_id = 'table#{}{}'.format( + 'playoffs_' if kind == 'P' else '', table_id) + + print(table_id) + table = doc(table_id) + print(doc(table_id)) + df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) + return df + + @sportsref.decorators.memoize + def stats_per_game(self, kind='R', summary=False): + """Returns a DataFrame of per-game box score stats.""" + return self._get_stats_table('players_per_game', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_totals(self, kind='R', summary=False): + """Returns a DataFrame of total box score statistics by season.""" + return self._get_stats_table('totals', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_per36(self, kind='R', summary=False): + """Returns a DataFrame of per-36-minutes stats.""" + return self._get_stats_table('per_minute', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_per100(self, kind='R', summary=False): + """Returns a DataFrame of per-100-possession stats.""" + return self._get_stats_table('per_poss', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_advanced(self, kind='R', summary=False): + """Returns a DataFrame of advanced stats.""" + return self._get_stats_table('advanced', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_shooting(self, kind='R', summary=False): + """Returns a DataFrame of shooting stats.""" + return self._get_stats_table('shooting', kind=kind, summary=summary) + + @sportsref.decorators.memoize + def stats_pbp(self, kind='R', summary=False): + """Returns a DataFrame of play-by-play stats.""" + return self._get_stats_table('advanced_pbp', kind=kind, + summary=summary) + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def gamelog_basic(self, year, kind='R'): + """Returns a table of a player's basic game-by-game stats for a season. + + :param year: The year representing the desired season. + :param kind: specifies regular season, playoffs, or both. One of 'R', + 'P', 'B'. Defaults to 'R'. + :returns: A DataFrame of the player's standard boxscore stats from each + game of the season. + :rtype: pd.DataFrame + """ + doc = self.get_sub_doc('gamelog/{}'.format(year)) + table = (doc('table#pgl_basic_playoffs') + if kind == 'P' else doc('table#pgl_basic')) + df = sportsref.utils.parse_table(table) + return df + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def gamelog_advanced(self, year, kind='R'): + """Returns a table of a player's advanced game-by-game stats for a + season. + + :param year: The year representing the desired season. + :param kind: specifies regular season, playoffs, or both. One of 'R', + 'P', 'B'. Defaults to 'R'. + :returns: A DataFrame of the player's advanced stats from each game of + the season. + :rtype: pd.DataFrame + """ + doc = self.get_sub_doc('gamelog-advanced/{}'.format(year)) + table = (doc('table#pgl_advanced_playoffs') + if kind == 'P' else doc('table#pgl_advanced')) + df = sportsref.utils.parse_table(table) + return df diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py new file mode 100644 index 0000000..5be3575 --- /dev/null +++ b/sportsref/euro/seasons.py @@ -0,0 +1,222 @@ +import future +import future.utils + +import pandas as pd +from pyquery import PyQuery as pq + +import sportsref + + +class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + """Object representing a given NBA season.""" + + def __init__(self, year): + """Initializes a Season object for an NBA season. + + :year: The year of the season we want. + """ + self.yr = int(year) + + def __eq__(self, other): + return (self.yr == other.yr) + + def __hash__(self): + return hash(self.yr) + + def __repr__(self): + return 'Season({})'.format(self.yr) + + def _subpage_url(self, page): + return (sportsref.nba.BASE_URL + + '/leagues/NBA_{}_{}.html'.format(self.yr, page)) + + @sportsref.decorators.memoize + def get_main_doc(self): + """Returns PyQuery object for the main season URL. + :returns: PyQuery object. + """ + url = (sportsref.nba.BASE_URL + + '/leagues/NBA_{}.html'.format(self.yr)) + return pq(sportsref.utils.get_html(url)) + + @sportsref.decorators.memoize + def get_sub_doc(self, subpage): + """Returns PyQuery object for a given subpage URL. + :subpage: The subpage of the season, e.g. 'per_game'. + :returns: PyQuery object. + """ + html = sportsref.utils.get_html(self._subpage_url(subpage)) + return pq(html) + + @sportsref.decorators.memoize + def get_team_ids(self): + """Returns a list of the team IDs for the given year. + :returns: List of team IDs. + """ + df = self.team_stats_per_game() + if not df.empty: + return df.index.tolist() + else: + print('ERROR: no teams found') + return [] + + @sportsref.decorators.memoize + def team_ids_to_names(self): + """Mapping from 3-letter team IDs to full team names. + :returns: Dictionary with team IDs as keys and full team strings as + values. + """ + doc = self.get_main_doc() + table = doc('table#team-stats-per_game') + flattened = sportsref.utils.parse_table(table, flatten=True) + unflattened = sportsref.utils.parse_table(table, flatten=False) + team_ids = flattened['team_id'] + team_names = unflattened['team_name'] + if len(team_names) != len(team_ids): + raise Exception("team names and team IDs don't align") + return dict(list(zip(team_ids, team_names))) + + @sportsref.decorators.memoize + def team_names_to_ids(self): + """Mapping from full team names to 3-letter team IDs. + :returns: Dictionary with tean names as keys and team IDs as values. + """ + d = self.team_ids_to_names() + return {v: k for k, v in list(d.items())} + + @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) + def schedule(self, kind='R'): + """Returns a list of BoxScore IDs for every game in the season. + Only needs to handle 'R' or 'P' options because decorator handles 'B'. + + :param kind: 'R' for regular season, 'P' for playoffs, 'B' for both. + Defaults to 'R'. + :returns: DataFrame of schedule information. + :rtype: pd.DataFrame + """ + kind = kind.upper()[0] + dfs = [] + + # get games from each month + for month in ('october', 'november', 'december', 'january', 'february', + 'march', 'april', 'may', 'june'): + try: + doc = self.get_sub_doc('games-{}'.format(month)) + except ValueError: + continue + table = doc('table#schedule') + df = sportsref.utils.parse_table(table) + dfs.append(df) + df = pd.concat(dfs).reset_index(drop=True) + + # figure out how many regular season games + try: + sportsref.utils.get_html('{}/playoffs/NBA_{}.html'.format( + sportsref.nba.BASE_URL, self.yr) + ) + is_past_season = True + except ValueError: + is_past_season = False + + if is_past_season: + team_per_game = self.team_stats_per_game() + n_reg_games = int(team_per_game.g.sum() / 2) + else: + n_reg_games = len(df) + + # subset appropriately based on `kind` + if kind == 'P': + return df.iloc[n_reg_games:] + else: + return df.iloc[:n_reg_games] + + def finals_winner(self): + """Returns the team ID for the winner of that year's NBA Finals. + :returns: 3-letter team ID for champ. + """ + raise NotImplementedError('nba.Season.finals_winner') + + def finals_loser(self): + """Returns the team ID for the loser of that year's NBA Finals. + :returns: 3-letter team ID for runner-up. + """ + raise NotImplementedError('nba.Season.finals_loser') + + @sportsref.decorators.memoize + def _get_team_stats_table(self, selector): + """Helper function for stats tables on season pages. Returns a + DataFrame.""" + doc = self.get_main_doc() + table = doc(selector) + df = sportsref.utils.parse_table(table) + df.set_index('team_id', inplace=True) + return df + + def team_stats_per_game(self): + """Returns a Pandas DataFrame of each team's basic per-game stats for + the season.""" + return self._get_team_stats_table('table#team-stats-per_game') + + def opp_stats_per_game(self): + """Returns a Pandas DataFrame of each team's opponent's basic per-game + stats for the season.""" + return self._get_team_stats_table('table#opponent-stats-per_game') + + def team_stats_totals(self): + """Returns a Pandas DataFrame of each team's basic stat totals for the + season.""" + return self._get_team_stats_table('table#team-stats-base') + + def opp_stats_totals(self): + """Returns a Pandas DataFrame of each team's opponent's basic stat + totals for the season.""" + return self._get_team_stats_table('table#opponent-stats-base') + + def misc_stats(self): + """Returns a Pandas DataFrame of miscellaneous stats about each team's + season.""" + return self._get_team_stats_table('table#misc_stats') + + def team_stats_shooting(self): + """Returns a Pandas DataFrame of each team's shooting stats for the + season.""" + return self._get_team_stats_table('table#team_shooting') + + def opp_stats_shooting(self): + """Returns a Pandas DataFrame of each team's opponent's shooting stats + for the season.""" + return self._get_team_stats_table('table#opponent_shooting') + + @sportsref.decorators.memoize + def _get_player_stats_table(self, identifier): + """Helper function for player season stats. + + :identifier: string identifying the type of stat, e.g. 'per_game'. + :returns: A DataFrame of stats. + """ + doc = self.get_sub_doc(identifier) + table = doc('table#{}_stats'.format(identifier)) + df = sportsref.utils.parse_table(table) + return df + + def player_stats_per_game(self): + """Returns a DataFrame of per-game player stats for a season.""" + return self._get_player_stats_table('per_game') + + def player_stats_totals(self): + """Returns a DataFrame of player stat totals for a season.""" + return self._get_player_stats_table('totals') + + def player_stats_per36(self): + """Returns a DataFrame of player per-36 min stats for a season.""" + return self._get_player_stats_table('per_minute') + + def player_stats_per100(self): + """Returns a DataFrame of player per-100 poss stats for a season.""" + return self._get_player_stats_table('per_poss') + + def player_stats_advanced(self): + """Returns a DataFrame of player per-100 poss stats for a season.""" + return self._get_player_stats_table('advanced') diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py new file mode 100644 index 0000000..86d56f9 --- /dev/null +++ b/sportsref/euro/teams.py @@ -0,0 +1,75 @@ +import future +import future.utils + +import numpy as np +from pyquery import PyQuery as pq + +import sportsref + + +class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): + + def __init__(self, team_id): + self.team_id = team_id.upper() + + def __eq__(self, other): + return (self.team_id == other.team_id) + + def __hash__(self): + return hash(self.team_id) + + @sportsref.decorators.memoize + def team_year_url(self, yr_str): + return (sportsref.nba.BASE_URL + + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) + + @sportsref.decorators.memoize + def get_main_doc(self): + relURL = '/teams/{}'.format(self.team_id) + teamURL = sportsref.nba.BASE_URL + relURL + mainDoc = pq(sportsref.utils.get_html(teamURL)) + return mainDoc + + @sportsref.decorators.memoize + def get_year_doc(self, yr_str): + return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) + + @sportsref.decorators.memoize + def name(self): + """Returns the real name of the franchise given the team ID. + + Examples: + 'BOS' -> 'Boston Celtics' + 'NJN' -> 'Brooklyn Nets' + + :returns: A string corresponding to the team's full name. + """ + doc = self.get_main_doc() + name = doc('div#info h1[itemprop="name"]').text() + return name + + @sportsref.decorators.memoize + def roster(self, year): + """Returns the roster table for the given year. + + :year: The year for which we want the roster; defaults to current year. + :returns: A DataFrame containing roster information for that year. + """ + doc = self.get_year_doc(year) + table = doc('table#roster') + df = sportsref.utils.parse_table(table) + df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) + return df + + # TODO: kind_rpb + @sportsref.decorators.memoize + def schedule(self, year): + """Gets schedule information for a team-season. + + :year: The year for which we want the schedule. + :returns: DataFrame of schedule information. + """ + doc = self.get_year_doc('{}_games'.format(year)) + table = doc('table#games') + df = sportsref.utils.parse_table(table) + return df From 580198d6819b5f20819a1aabca7cede17b4ddf9a Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 18 Jan 2018 13:11:22 -0500 Subject: [PATCH 08/57] euro url fix --- sportsref/euro/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 661043b..c12a9a7 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -22,7 +22,7 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): def __init__(self, player_id): self.player_id = player_id - self.url_base = (sportsref.cbb.BASE_URL + + self.url_base = (sportsref.euro.BASE_URL + '/players/{0}').format(self.player_id) self.main_url = self.url_base + '.html' From 6facc766ad4b2b14169d0eca4a537c838ce5ee59 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 18 Jan 2018 13:14:06 -0500 Subject: [PATCH 09/57] url fix #2 --- sportsref/euro/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/__init__.py b/sportsref/euro/__init__.py index 1e3c5e8..4aa4a16 100644 --- a/sportsref/euro/__init__.py +++ b/sportsref/euro/__init__.py @@ -8,7 +8,7 @@ from .teams import Team from .players import Player -BASE_URL = 'http://www.sports-reference.com/euro' +BASE_URL = 'http://www.basketball-reference.com/euro' __all__ = [ 'BASE_URL', From b9fa0f67ff644d01aa843e5b381eaf6b5b3c4591 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 18 Jan 2018 13:40:02 -0500 Subject: [PATCH 10/57] commented out doc prints --- sportsref/cbb/players.py | 4 ++-- sportsref/euro/players.py | 4 ++-- sportsref/nba/players.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py index 661043b..b255a6e 100644 --- a/sportsref/cbb/players.py +++ b/sportsref/cbb/players.py @@ -120,9 +120,9 @@ def _get_stats_table(self, table_id, kind='R', summary=False): table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) - print(table_id) + #print(table_id) table = doc(table_id) - print(doc(table_id)) + #print(doc(table_id)) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index c12a9a7..8fe7b5e 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -120,9 +120,9 @@ def _get_stats_table(self, table_id, kind='R', summary=False): table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) - print(table_id) + #print(table_id) table = doc(table_id) - print(doc(table_id)) + #print(doc(table_id)) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df diff --git a/sportsref/nba/players.py b/sportsref/nba/players.py index f0794e5..5513057 100644 --- a/sportsref/nba/players.py +++ b/sportsref/nba/players.py @@ -141,9 +141,9 @@ def _get_stats_table(self, table_id, kind='R', summary=False): doc = self.get_main_doc() table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) - print(table_id) + #print(table_id) table = doc(table_id) - print(table) + #print(table) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df From eb4452307bd24f3338c0422d946c09f497cdf32d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 24 Jan 2018 14:37:07 -0500 Subject: [PATCH 11/57] fixed table_ids in player --- sportsref/euro/players.py | 36 ++++++------------------------------ sportsref/nba/players.py | 1 + 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 8fe7b5e..8f0746b 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -24,7 +24,7 @@ def __init__(self, player_id): self.player_id = player_id self.url_base = (sportsref.euro.BASE_URL + '/players/{0}').format(self.player_id) - self.main_url = self.url_base + '.html' + self.main_url = self.url_base + '.htm' def __eq__(self, other): return self.player_id == other.player_id @@ -108,28 +108,25 @@ def weight(self): @sportsref.decorators.kind_rpb(include_type=True) def _get_stats_table(self, table_id, kind='R', summary=False): """Gets a stats table from the player page; helper function that does - the work for per-game, per-100-poss, etc. stats. + the work for per-game, per-36-min, etc. stats. :table_id: the ID of the HTML table. - :kind: specifies regular season, playoffs, or both. One of 'R', 'P', - 'B'. Defaults to 'R'. + :kind: specifies regular season, playoffs. One of 'R', 'P'. + Defaults to 'R'. :returns: A DataFrame of stats. """ doc = self.get_main_doc() - #print(doc) table_id = 'table#{}{}'.format( - 'playoffs_' if kind == 'P' else '', table_id) + table_id, 'ALL1' if kind == 'P' else 'ALL0') - #print(table_id) table = doc(table_id) - #print(doc(table_id)) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df @sportsref.decorators.memoize def stats_per_game(self, kind='R', summary=False): """Returns a DataFrame of per-game box score stats.""" - return self._get_stats_table('players_per_game', kind=kind, summary=summary) + return self._get_stats_table('per_game', kind=kind, summary=summary) @sportsref.decorators.memoize def stats_totals(self, kind='R', summary=False): @@ -141,27 +138,6 @@ def stats_per36(self, kind='R', summary=False): """Returns a DataFrame of per-36-minutes stats.""" return self._get_stats_table('per_minute', kind=kind, summary=summary) - @sportsref.decorators.memoize - def stats_per100(self, kind='R', summary=False): - """Returns a DataFrame of per-100-possession stats.""" - return self._get_stats_table('per_poss', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_advanced(self, kind='R', summary=False): - """Returns a DataFrame of advanced stats.""" - return self._get_stats_table('advanced', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_shooting(self, kind='R', summary=False): - """Returns a DataFrame of shooting stats.""" - return self._get_stats_table('shooting', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_pbp(self, kind='R', summary=False): - """Returns a DataFrame of play-by-play stats.""" - return self._get_stats_table('advanced_pbp', kind=kind, - summary=summary) - @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) def gamelog_basic(self, year, kind='R'): diff --git a/sportsref/nba/players.py b/sportsref/nba/players.py index 5513057..40f0658 100644 --- a/sportsref/nba/players.py +++ b/sportsref/nba/players.py @@ -139,6 +139,7 @@ def _get_stats_table(self, table_id, kind='R', summary=False): :returns: A DataFrame of stats. """ doc = self.get_main_doc() + #print(doc) table_id = 'table#{}{}'.format( 'playoffs_' if kind == 'P' else '', table_id) #print(table_id) From 62cab9e55784315675252620f05d54d8fb124bf3 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 24 Jan 2018 14:54:57 -0500 Subject: [PATCH 12/57] name fix --- sportsref/euro/players.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 8f0746b..67cf5cc 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -51,7 +51,7 @@ def get_sub_doc(self, rel_url): def name(self): """Returns the name of the player as a string.""" doc = self.get_main_doc() - return doc('h1[itemprop="name"]').text() + return doc('h1[itemprop="name"]').text().replace(' Europe Stats', '') @sportsref.decorators.memoize def age(self, year, month=2, day=1): @@ -77,7 +77,7 @@ def position(self): """TODO: Docstring for position. :returns: TODO """ - raise Exception('not yet implemented - nba.Player.position') + raise Exception('not yet implemented - euro.Player.position') @sportsref.decorators.memoize def height(self): @@ -138,6 +138,13 @@ def stats_per36(self, kind='R', summary=False): """Returns a DataFrame of per-36-minutes stats.""" return self._get_stats_table('per_minute', kind=kind, summary=summary) + @sportsref.decorators.memoize + def stats_advanced(self, kind='R', summary=False): + """Returns a dataframe of advanced stats. + :returns: TODO (would need to pull from team page, not housed in player page) + """ + raise Exception('not yet implemented - euro.stats_advanced') + @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) def gamelog_basic(self, year, kind='R'): From c44a156b1716774c2de6d1511a6e4446613464fe Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 24 Jan 2018 23:34:21 -0500 Subject: [PATCH 13/57] test gamelog euro --- sportsref/euro/players.py | 42 ++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 67cf5cc..d18c6e3 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -3,6 +3,7 @@ import datetime import re +import requests import numpy as np from pyquery import PyQuery as pq @@ -42,6 +43,10 @@ def __str__(self): def get_main_doc(self): return pq(sportsref.utils.get_html(self.main_url)) + @sportsref.decorators.memoize + def get_doc_url(self, url): + return pq(sportsref.utils.get_html(url)) + @sportsref.decorators.memoize def get_sub_doc(self, rel_url): url = '{}/{}'.format(self.url_base, rel_url) @@ -147,7 +152,7 @@ def stats_advanced(self, kind='R', summary=False): @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_basic(self, year, kind='R'): + def gamelog_basic(self, year, league_id): """Returns a table of a player's basic game-by-game stats for a season. :param year: The year representing the desired season. @@ -157,27 +162,18 @@ def gamelog_basic(self, year, kind='R'): game of the season. :rtype: pd.DataFrame """ - doc = self.get_sub_doc('gamelog/{}'.format(year)) - table = (doc('table#pgl_basic_playoffs') - if kind == 'P' else doc('table#pgl_basic')) - df = sportsref.utils.parse_table(table) - return df - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_advanced(self, year, kind='R'): - """Returns a table of a player's advanced game-by-game stats for a - season. + params = { 'player_id' : self.player_id, + 'year_id' : year, + 'lg_id' : league_id + } - :param year: The year representing the desired season. - :param kind: specifies regular season, playoffs, or both. One of 'R', - 'P', 'B'. Defaults to 'R'. - :returns: A DataFrame of the player's advanced stats from each game of - the season. - :rtype: pd.DataFrame - """ - doc = self.get_sub_doc('gamelog-advanced/{}'.format(year)) - table = (doc('table#pgl_advanced_playoffs') - if kind == 'P' else doc('table#pgl_advanced')) - df = sportsref.utils.parse_table(table) - return df + url = sportsref.euro.BASE_URL + '/pgl_euro.cgi + print(url) + doc = self.get_doc_url(url) + + return doc + #table = (doc('table#pgl_basic_playoffs') + # if kind == 'P' else doc('table#pgl_basic')) + #df = sportsref.utils.parse_table(table) + #return df From c30ca4c587760ad390d8670a44a0596b0fbff77d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 24 Jan 2018 23:37:49 -0500 Subject: [PATCH 14/57] small fix --- sportsref/euro/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index d18c6e3..a9587c6 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -168,7 +168,7 @@ def gamelog_basic(self, year, league_id): 'lg_id' : league_id } - url = sportsref.euro.BASE_URL + '/pgl_euro.cgi + url = sportsref.euro.BASE_URL + '/pgl_euro.cgi' print(url) doc = self.get_doc_url(url) From bdedfbb090aaa1a610dcd724e7737815cf870050 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 31 Jan 2018 18:54:20 -0500 Subject: [PATCH 15/57] player gamelogs working - also have caching print statements in for debugging, leaving those in for now (will remove eventually) --- sportsref/decorators.py | 10 ++++++++++ sportsref/euro/players.py | 36 ++++++++++++++++++++---------------- sportsref/nba/players.py | 3 +++ sportsref/utils.py | 7 +++++++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/sportsref/decorators.py b/sportsref/decorators.py index c2c6f00..d709212 100644 --- a/sportsref/decorators.py +++ b/sportsref/decorators.py @@ -178,11 +178,18 @@ def memoize(fun): @funcutils.wraps(fun) def wrapper(*args, **kwargs): + print('CACHE BEFORE') + print(cache) + hash_args = tuple(args) hash_kwargs = frozenset(sorted(kwargs.items())) key = (hash_args, hash_kwargs) + print('KEY in wrapper') + print(key) + def _copy(v): + print('COPY') if isinstance(v, pq): return v.clone() else: @@ -190,8 +197,11 @@ def _copy(v): try: ret = _copy(cache[key]) + print('RET worked') + print(ret) return ret except KeyError: + print('KEYERROR') cache[key] = fun(*args, **kwargs) ret = _copy(cache[key]) return ret diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index a9587c6..458dcf4 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -44,7 +44,8 @@ def get_main_doc(self): return pq(sportsref.utils.get_html(self.main_url)) @sportsref.decorators.memoize - def get_doc_url(self, url): + def get_gamelog_doc(self, year, league): + url = '{}/pgl_euro.cgi?player_id={}&year_id={}&lg_id={}'.format(sportsref.euro.BASE_URL, self.player_id, year, league) return pq(sportsref.utils.get_html(url)) @sportsref.decorators.memoize @@ -52,6 +53,18 @@ def get_sub_doc(self, rel_url): url = '{}/{}'.format(self.url_base, rel_url) return pq(sportsref.utils.get_html(url)) + @sportsref.decorators.memoize + def available_gamelogs(self): + + tup_list = [] + doc = self.get_main_doc() + for li in doc('#bottom_nav_container')('ul')('li').items(): + href = li('a').attr('href') + if href and 'pgl_euro.cgi?' in href: + tup_list.append((int(re.search(r'year_id=(.*?)&', href).group(1)), re.search(r'lg_id=(.*?)$', href).group(1))) + + return tup_list + @sportsref.decorators.memoize def name(self): """Returns the name of the player as a string.""" @@ -151,8 +164,8 @@ def stats_advanced(self, kind='R', summary=False): raise Exception('not yet implemented - euro.stats_advanced') @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_basic(self, year, league_id): + @sportsref.decorators.kind_rpb(include_type=False) + def gamelog_basic(self, year, league): """Returns a table of a player's basic game-by-game stats for a season. :param year: The year representing the desired season. @@ -163,17 +176,8 @@ def gamelog_basic(self, year, league_id): :rtype: pd.DataFrame """ - params = { 'player_id' : self.player_id, - 'year_id' : year, - 'lg_id' : league_id - } + doc = self.get_gamelog_doc(year, league) - url = sportsref.euro.BASE_URL + '/pgl_euro.cgi' - print(url) - doc = self.get_doc_url(url) - - return doc - #table = (doc('table#pgl_basic_playoffs') - # if kind == 'P' else doc('table#pgl_basic')) - #df = sportsref.utils.parse_table(table) - #return df + table = doc('table#pgl_basic') + df = sportsref.utils.parse_table(table) + return df diff --git a/sportsref/nba/players.py b/sportsref/nba/players.py index 40f0658..cf57794 100644 --- a/sportsref/nba/players.py +++ b/sportsref/nba/players.py @@ -21,6 +21,7 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): from the player's Basketball Reference player page.""" def __init__(self, player_id): + print('init called') self.player_id = player_id self.url_base = (sportsref.nba.BASE_URL + '/players/{0[0]}/{0}').format(self.player_id) @@ -40,6 +41,7 @@ def __str__(self): @sportsref.decorators.memoize def get_main_doc(self): + print('GET_MAIN_DOC called') return pq(sportsref.utils.get_html(self.main_url)) @sportsref.decorators.memoize @@ -200,6 +202,7 @@ def gamelog_basic(self, year, kind='R'): doc = self.get_sub_doc('gamelog/{}'.format(year)) table = (doc('table#pgl_basic_playoffs') if kind == 'P' else doc('table#pgl_basic')) + print('STARTED PARSING') df = sportsref.utils.parse_table(table) return df diff --git a/sportsref/utils.py b/sportsref/utils.py index c0d4e94..ff6fe49 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -26,7 +26,10 @@ def get_html(url): :url: the absolute URL of the desired page. :returns: a string of HTML. """ + print('GET_HTML called') + with throttle_lock: + print('inside_lock') # sleep until THROTTLE_DELAY secs have passed since last request wait_left = THROTTLE_DELAY - (time.time() - last_request_time.value) @@ -34,6 +37,8 @@ def get_html(url): time.sleep(wait_left) # make request + print('REQUEST MADE') + print('URL: ' + url) response = requests.get(url) # update last request time for throttling @@ -45,6 +50,8 @@ def get_html(url): 'Status Code {} received fetching URL "{}"' .format(response.status_code, url) ) + + print('HTML part') html = response.text html = html.replace('', '') From 822c989e736931922e4ebcf88d7fcca7e220dd19 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Wed, 31 Jan 2018 20:30:51 -0500 Subject: [PATCH 16/57] added level variable for All/Euro/Club play (very different than NBA) --- sportsref/euro/players.py | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 458dcf4..49bcc78 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -17,15 +17,16 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - """Each instance of this class represents an CBB player, uniquely + """Each instance of this class represents an EuroBB player, uniquely identified by a player ID. The instance methods give various data available from the player's Sports Reference player page.""" def __init__(self, player_id): self.player_id = player_id - self.url_base = (sportsref.euro.BASE_URL + - '/players/{0}').format(self.player_id) - self.main_url = self.url_base + '.htm' + self.main_url = self.get_main_url(player_id) + + def get_main_url(self, player_id): + return (sportsref.euro.BASE_URL + '/players/{0}.htm').format(player_id) def __eq__(self, other): return self.player_id == other.player_id @@ -40,19 +41,21 @@ def __str__(self): return self.name() @sportsref.decorators.memoize - def get_main_doc(self): - return pq(sportsref.utils.get_html(self.main_url)) - + def get_main_doc(self, level='B'): + #Need to have a level option this deep in process because all vs club vs tourney means a completely different doc for euro, instead of nba which is just a different table and same doc + + player_id = self.player_id + if level == 'C': + player_id += '-club' + if level == 'E': + player_id += '-tournament' + return pq(sportsref.utils.get_html(self.get_main_url(player_id))) + @sportsref.decorators.memoize def get_gamelog_doc(self, year, league): url = '{}/pgl_euro.cgi?player_id={}&year_id={}&lg_id={}'.format(sportsref.euro.BASE_URL, self.player_id, year, league) return pq(sportsref.utils.get_html(url)) - @sportsref.decorators.memoize - def get_sub_doc(self, rel_url): - url = '{}/{}'.format(self.url_base, rel_url) - return pq(sportsref.utils.get_html(url)) - @sportsref.decorators.memoize def available_gamelogs(self): @@ -124,37 +127,41 @@ def weight(self): return None @sportsref.decorators.kind_rpb(include_type=True) - def _get_stats_table(self, table_id, kind='R', summary=False): + def _get_stats_table(self, table_id, kind='R', level='B', summary=False): """Gets a stats table from the player page; helper function that does the work for per-game, per-36-min, etc. stats. :table_id: the ID of the HTML table. :kind: specifies regular season, playoffs. One of 'R', 'P'. Defaults to 'R'. + :level: specifies Club play (C), Eurocup/Euroleague play (E), or Both (B) - defaults to B :returns: A DataFrame of stats. """ - doc = self.get_main_doc() - table_id = 'table#{}{}'.format( - table_id, 'ALL1' if kind == 'P' else 'ALL0') + doc = self.get_main_doc(level=level) + if level == 'E': + table_id = 'table#{}EUR0'.format(table_id) + else: + table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') + print(table_id) table = doc(table_id) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df @sportsref.decorators.memoize - def stats_per_game(self, kind='R', summary=False): + def stats_per_game(self, kind='R', level='B', summary=False): """Returns a DataFrame of per-game box score stats.""" - return self._get_stats_table('per_game', kind=kind, summary=summary) + return self._get_stats_table('per_game', kind=kind, level=level, summary=summary) @sportsref.decorators.memoize - def stats_totals(self, kind='R', summary=False): + def stats_totals(self, kind='R', level='B', summary=False): """Returns a DataFrame of total box score statistics by season.""" - return self._get_stats_table('totals', kind=kind, summary=summary) + return self._get_stats_table('totals', kind=kind, level=level, summary=summary) @sportsref.decorators.memoize - def stats_per36(self, kind='R', summary=False): + def stats_per36(self, kind='R', level='B', summary=False): """Returns a DataFrame of per-36-minutes stats.""" - return self._get_stats_table('per_minute', kind=kind, summary=summary) + return self._get_stats_table('per_minute', kind=kind, level=level, summary=summary) @sportsref.decorators.memoize def stats_advanced(self, kind='R', summary=False): From 42d8aefcdb96d6171a93bdc0c92acbf51e9836eb Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 01:26:14 -0500 Subject: [PATCH 17/57] take print statements out --- sportsref/decorators.py | 10 ---------- sportsref/euro/players.py | 2 -- sportsref/utils.py | 6 ------ 3 files changed, 18 deletions(-) diff --git a/sportsref/decorators.py b/sportsref/decorators.py index d709212..c2c6f00 100644 --- a/sportsref/decorators.py +++ b/sportsref/decorators.py @@ -178,18 +178,11 @@ def memoize(fun): @funcutils.wraps(fun) def wrapper(*args, **kwargs): - print('CACHE BEFORE') - print(cache) - hash_args = tuple(args) hash_kwargs = frozenset(sorted(kwargs.items())) key = (hash_args, hash_kwargs) - print('KEY in wrapper') - print(key) - def _copy(v): - print('COPY') if isinstance(v, pq): return v.clone() else: @@ -197,11 +190,8 @@ def _copy(v): try: ret = _copy(cache[key]) - print('RET worked') - print(ret) return ret except KeyError: - print('KEYERROR') cache[key] = fun(*args, **kwargs) ret = _copy(cache[key]) return ret diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 49bcc78..ffbf1ed 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -138,12 +138,10 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): :returns: A DataFrame of stats. """ doc = self.get_main_doc(level=level) - if level == 'E': table_id = 'table#{}EUR0'.format(table_id) else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') - print(table_id) table = doc(table_id) df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) return df diff --git a/sportsref/utils.py b/sportsref/utils.py index ff6fe49..e520703 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -26,10 +26,8 @@ def get_html(url): :url: the absolute URL of the desired page. :returns: a string of HTML. """ - print('GET_HTML called') with throttle_lock: - print('inside_lock') # sleep until THROTTLE_DELAY secs have passed since last request wait_left = THROTTLE_DELAY - (time.time() - last_request_time.value) @@ -37,8 +35,6 @@ def get_html(url): time.sleep(wait_left) # make request - print('REQUEST MADE') - print('URL: ' + url) response = requests.get(url) # update last request time for throttling @@ -51,7 +47,6 @@ def get_html(url): .format(response.status_code, url) ) - print('HTML part') html = response.text html = html.replace('', '') @@ -330,7 +325,6 @@ def rel_url_to_id(url): ): return url - print('WARNING. NO MATCH WAS FOUND FOR "{}"'.format(url)) return url From a25f4783cdcfc1373fd1b69b4c3b5d7b2af1358d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 01:39:06 -0500 Subject: [PATCH 18/57] fix --- sportsref/euro/players.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index ffbf1ed..f202b70 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -137,7 +137,9 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): :level: specifies Club play (C), Eurocup/Euroleague play (E), or Both (B) - defaults to B :returns: A DataFrame of stats. """ - doc = self.get_main_doc(level=level) + + if level == 'E': + doc = self.get_main_doc(level=level) table_id = 'table#{}EUR0'.format(table_id) else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From 11594cc4e946029d009ee91abd6a8f47333d1d4a Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 02:11:20 -0500 Subject: [PATCH 19/57] fix --- sportsref/euro/players.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index f202b70..6887917 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -137,9 +137,8 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): :level: specifies Club play (C), Eurocup/Euroleague play (E), or Both (B) - defaults to B :returns: A DataFrame of stats. """ - + doc = self.get_main_doc(level=level) if level == 'E': - doc = self.get_main_doc(level=level) table_id = 'table#{}EUR0'.format(table_id) else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From 7a416d54433982f7354e5d6414d0357040369537 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 02:29:04 -0500 Subject: [PATCH 20/57] club table fix --- sportsref/euro/players.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 6887917..b9c9ae6 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -140,6 +140,8 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): doc = self.get_main_doc(level=level) if level == 'E': table_id = 'table#{}EUR0'.format(table_id) + if level =='C': + table_id = 'table#{}{}'.format(table_id, 'CLU1' if kind == 'P' else 'CLU0') else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From d4bc8c266ec1c36c6a29662f798499060ce6b868 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 02:32:25 -0500 Subject: [PATCH 21/57] club table fix --- sportsref/euro/players.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index 49bcc78..fc247ea 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -140,6 +140,8 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): doc = self.get_main_doc(level=level) if level == 'E': table_id = 'table#{}EUR0'.format(table_id) + if level == 'C': + table_id = 'table#{}{}'.format(table_id, 'CLU1' if kind == 'P' else 'CLU0') else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From 02f4d8594e0e1d24e71f7cf3323464d12cb8f68a Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 02:58:51 -0500 Subject: [PATCH 22/57] I'm dumb --- sportsref/euro/players.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index b9c9ae6..998751c 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -137,10 +137,10 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): :level: specifies Club play (C), Eurocup/Euroleague play (E), or Both (B) - defaults to B :returns: A DataFrame of stats. """ - doc = self.get_main_doc(level=level) + doc = self.get_main_doc(level=level) if level == 'E': table_id = 'table#{}EUR0'.format(table_id) - if level =='C': + elif level =='C': table_id = 'table#{}{}'.format(table_id, 'CLU1' if kind == 'P' else 'CLU0') else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From 679e8dbfb419d82d40d1b6ca22a1f74974ad7a0d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 03:01:00 -0500 Subject: [PATCH 23/57] still dumb --- sportsref/euro/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index fc247ea..ceabbb6 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -140,7 +140,7 @@ def _get_stats_table(self, table_id, kind='R', level='B', summary=False): doc = self.get_main_doc(level=level) if level == 'E': table_id = 'table#{}EUR0'.format(table_id) - if level == 'C': + elif level == 'C': table_id = 'table#{}{}'.format(table_id, 'CLU1' if kind == 'P' else 'CLU0') else: table_id = 'table#{}{}'.format(table_id, 'ALL1' if kind == 'P' else 'ALL0') From 5570f48d98d2490ffa9597d268eb1f16b323b027 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 03:14:54 -0500 Subject: [PATCH 24/57] test notebook --- euro_player_test.ipynb | 2419 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2419 insertions(+) create mode 100644 euro_player_test.ipynb diff --git a/euro_player_test.ipynb b/euro_player_test.ipynb new file mode 100644 index 0000000..cc36f87 --- /dev/null +++ b/euro_player_test.ipynb @@ -0,0 +1,2419 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sportsref - Euro" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Regenerating PSFConstants file\n", + "Regenerating GPFConstants file\n" + ] + } + ], + "source": [ + "from sportsref import euro\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "p = euro.Player('luka-doncic-1')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## simple methods: Almost no changes\n", + "\n", + "#### only change: Milos Teodosic Europe Stats -> Milos Teodosic" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Luka Doncic\n", + "17.93972602739726\n", + "78\n" + ] + } + ], + "source": [ + "print(p.name())\n", + "print(p.age(2017))\n", + "print(p.height())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Gamelogs - different url style" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(2015, 'SPA'), (2016, 'ELG'), (2016, 'SPA'), (2017, 'ELG'), (2017, 'SPA'), (2018, 'ELG'), (2018, 'SPA')]\n" + ] + } + ], + "source": [ + "# new method: to me, would be useful/necessary\n", + "# because gamelogs are split by league and year\n", + "\n", + "print(p.available_gamelogs())" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "
Per Game Table
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02015-04-30-real-madrid16-061Real-MadridTrueUnicaja-MalagaW1.4666671.01.01.000...0.00.00.00.00.00.00.00.03.02.7
12015-05-03-obradoiro16-064Real-MadridFalseObradoiroW1.7500000.02.00.000...0.00.00.00.00.00.00.01.01.0-1.2
22015-05-20-vitoria16-081Real-MadridFalseVitoriaL5.0000000.00.0NaN...1.01.02.00.00.00.00.00.02.03.0
32015-05-29-real-madrid16-090Real-MadridTrueGran-CanariaW10.8500001.03.00.333...0.03.03.00.00.00.01.00.02.00.2
42015-05-31-gran-canaria16-092Real-MadridFalseGran-CanariaW4.9833330.00.0NaN...0.01.01.00.00.00.00.00.00.00.3
\n", + "

5 rows × 26 columns

\n", + "" + ], + "text/plain": [ + " boxscore_id age team_id is_home opp_id \\\n", + "0 2015-04-30-real-madrid 16-061 Real-Madrid True Unicaja-Malaga \n", + "1 2015-05-03-obradoiro 16-064 Real-Madrid False Obradoiro \n", + "2 2015-05-20-vitoria 16-081 Real-Madrid False Vitoria \n", + "3 2015-05-29-real-madrid 16-090 Real-Madrid True Gran-Canaria \n", + "4 2015-05-31-gran-canaria 16-092 Real-Madrid False Gran-Canaria \n", + "\n", + " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", + "0 W 1.466667 1.0 1.0 1.000 ... 0.0 0.0 0.0 0.0 \n", + "1 W 1.750000 0.0 2.0 0.000 ... 0.0 0.0 0.0 0.0 \n", + "2 L 5.000000 0.0 0.0 NaN ... 1.0 1.0 2.0 0.0 \n", + "3 W 10.850000 1.0 3.0 0.333 ... 0.0 3.0 3.0 0.0 \n", + "4 W 4.983333 0.0 0.0 NaN ... 0.0 1.0 1.0 0.0 \n", + "\n", + " stl blk tov pf pts game_score \n", + "0 0.0 0.0 0.0 0.0 3.0 2.7 \n", + "1 0.0 0.0 0.0 1.0 1.0 -1.2 \n", + "2 0.0 0.0 0.0 0.0 2.0 3.0 \n", + "3 0.0 0.0 1.0 0.0 2.0 0.2 \n", + "4 0.0 0.0 0.0 0.0 0.0 0.3 \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p.gamelog_basic(2015, 'SPA').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02017-10-12-anadolu-efes18-226Real-MadridFalseAnadolu-EfesW26.6000009.014.00.643...2.02.04.04.00.00.02.01.027.022.8
12017-10-19-real-madrid18-233Real-MadridTrueCska-MoscowW26.0833332.08.00.250...1.05.06.02.02.01.02.02.014.011.9
22017-10-24-real-madrid18-238Real-MadridTrueMilanoW28.4166677.014.00.500...2.06.08.05.03.00.01.00.027.028.3
32017-10-26-zalgiris18-240Real-MadridFalseZalgirisW27.7500009.013.00.692...2.07.09.04.00.00.03.02.028.025.0
42017-11-02-real-madrid18-247Real-MadridTrueKhimkiL25.6000003.010.00.300...2.05.07.03.01.00.03.01.012.08.8
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " boxscore_id age team_id is_home opp_id \\\n", + "0 2017-10-12-anadolu-efes 18-226 Real-Madrid False Anadolu-Efes \n", + "1 2017-10-19-real-madrid 18-233 Real-Madrid True Cska-Moscow \n", + "2 2017-10-24-real-madrid 18-238 Real-Madrid True Milano \n", + "3 2017-10-26-zalgiris 18-240 Real-Madrid False Zalgiris \n", + "4 2017-11-02-real-madrid 18-247 Real-Madrid True Khimki \n", + "\n", + " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", + "0 W 26.600000 9.0 14.0 0.643 ... 2.0 2.0 4.0 4.0 \n", + "1 W 26.083333 2.0 8.0 0.250 ... 1.0 5.0 6.0 2.0 \n", + "2 W 28.416667 7.0 14.0 0.500 ... 2.0 6.0 8.0 5.0 \n", + "3 W 27.750000 9.0 13.0 0.692 ... 2.0 7.0 9.0 4.0 \n", + "4 L 25.600000 3.0 10.0 0.300 ... 2.0 5.0 7.0 3.0 \n", + "\n", + " stl blk tov pf pts game_score \n", + "0 0.0 0.0 2.0 1.0 27.0 22.8 \n", + "1 2.0 1.0 2.0 2.0 14.0 11.9 \n", + "2 3.0 0.0 1.0 0.0 27.0 28.3 \n", + "3 0.0 0.0 3.0 2.0 28.0 25.0 \n", + "4 1.0 0.0 3.0 1.0 12.0 8.8 \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p.gamelog_basic(2018, 'ELG').head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## stat_tables:\n", + "\n", + "\n", + "### took out stats_per100, stats_advanced, stats_shooting, stats_pbp (data not on bballref)\n", + "\n", + "### changed table_ids\n", + "\n", + "### parameters:\n", + "\n", + "### Kind (works the same)\n", + "\n", + "### Level (needed, because different docs are pulled from)\n", + "\n", + "#### -B (pulls from main milos-teodosic doc - default)\n", + "#### -C (pulls from milos-teodosic-club)\n", + "#### -E (pulls from milos-teodosic-tournament, which is Eurocup/Euroleague play)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='B' - Both" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='R', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB3.0NaN2.70.31.00.3330.30.7...0.30.30.70.00.00.00.00.32.0False
12016Liga ACB, EuroLeague43.0NaN13.31.42.90.5000.51.3...0.52.22.72.00.30.31.41.54.5False
22017Liga ACB, EuroLeague67.0NaN19.92.65.70.4461.02.9...1.03.44.43.70.80.31.91.37.8False
32018EuroLeague, Liga ACB37.0NaN24.64.910.50.4731.64.9...1.14.55.64.61.10.32.11.315.8False
\n", + "

4 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", + "0 2015 Liga ACB 3.0 NaN 2.7 0.3 1.0 \n", + "1 2016 Liga ACB, EuroLeague 43.0 NaN 13.3 1.4 2.9 \n", + "2 2017 Liga ACB, EuroLeague 67.0 NaN 19.9 2.6 5.7 \n", + "3 2018 EuroLeague, Liga ACB 37.0 NaN 24.6 4.9 10.5 \n", + "\n", + " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", + "0 0.333 0.3 0.7 ... 0.3 0.3 \n", + "1 0.500 0.5 1.3 ... 0.5 2.2 \n", + "2 0.446 1.0 2.9 ... 1.0 3.4 \n", + "3 0.473 1.6 4.9 ... 1.1 4.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", + "1 2.7 2.0 0.3 0.3 1.4 1.5 4.5 \n", + "2 4.4 3.7 0.8 0.3 1.9 1.3 7.8 \n", + "3 5.6 4.6 1.1 0.3 2.1 1.3 15.8 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "\n", + "[4 rows x 27 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='P', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB2.0NaN8.00.51.50.3330.00.5...0.02.02.00.00.00.00.50.01.0True
12016Liga ACB8.0NaN8.01.32.40.5260.31.1...0.31.41.60.90.30.10.91.63.1True
22017Liga ACB10.0NaN19.22.36.00.3830.52.4...0.93.84.72.70.30.01.31.16.5True
\n", + "

3 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 2015 Liga ACB 2.0 NaN 8.0 0.5 1.5 0.333 \n", + "1 2016 Liga ACB 8.0 NaN 8.0 1.3 2.4 0.526 \n", + "2 2017 Liga ACB 10.0 NaN 19.2 2.3 6.0 0.383 \n", + "\n", + " fg3_per_g fg3a_per_g ... orb_per_g drb_per_g trb_per_g \\\n", + "0 0.0 0.5 ... 0.0 2.0 2.0 \n", + "1 0.3 1.1 ... 0.3 1.4 1.6 \n", + "2 0.5 2.4 ... 0.9 3.8 4.7 \n", + "\n", + " ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.0 0.0 0.0 0.5 0.0 1.0 \n", + "1 0.9 0.3 0.1 0.9 1.6 3.1 \n", + "2 2.7 0.3 0.0 1.3 1.1 6.5 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "\n", + "[3 rows x 27 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='B', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB3.0NaN2.70.31.00.3330.30.7...0.30.30.70.00.00.00.00.32.0False
12016Liga ACB, EuroLeague43.0NaN13.31.42.90.5000.51.3...0.52.22.72.00.30.31.41.54.5False
22017Liga ACB, EuroLeague67.0NaN19.92.65.70.4461.02.9...1.03.44.43.70.80.31.91.37.8False
32018EuroLeague, Liga ACB37.0NaN24.64.910.50.4731.64.9...1.14.55.64.61.10.32.11.315.8False
42015Liga ACB2.0NaN8.00.51.50.3330.00.5...0.02.02.00.00.00.00.50.01.0True
\n", + "

5 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", + "0 2015 Liga ACB 3.0 NaN 2.7 0.3 1.0 \n", + "1 2016 Liga ACB, EuroLeague 43.0 NaN 13.3 1.4 2.9 \n", + "2 2017 Liga ACB, EuroLeague 67.0 NaN 19.9 2.6 5.7 \n", + "3 2018 EuroLeague, Liga ACB 37.0 NaN 24.6 4.9 10.5 \n", + "4 2015 Liga ACB 2.0 NaN 8.0 0.5 1.5 \n", + "\n", + " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", + "0 0.333 0.3 0.7 ... 0.3 0.3 \n", + "1 0.500 0.5 1.3 ... 0.5 2.2 \n", + "2 0.446 1.0 2.9 ... 1.0 3.4 \n", + "3 0.473 1.6 4.9 ... 1.1 4.5 \n", + "4 0.333 0.0 0.5 ... 0.0 2.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", + "1 2.7 2.0 0.3 0.3 1.4 1.5 4.5 \n", + "2 4.4 3.7 0.8 0.3 1.9 1.3 7.8 \n", + "3 5.6 4.6 1.1 0.3 2.1 1.3 15.8 \n", + "4 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 True \n", + "\n", + "[5 rows x 27 columns]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='C' - Club" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='R', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes3.0NaN2.70.31.00.333...0.30.30.70.00.00.00.00.32.0False
12016/euro/teams/real-madrid/2016.htmlLiga ACBes31.0NaN14.21.63.10.526...0.62.22.82.00.40.31.51.94.9False
22017/euro/teams/real-madrid/2017.htmlLiga ACBes32.0NaN19.92.75.80.460...1.03.34.33.10.70.42.01.37.8False
32018/euro/teams/real-madrid/2018.htmlLiga ACBes17.0NaN23.64.69.80.473...1.14.85.94.60.90.21.91.614.1False
\n", + "

4 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 3.0 NaN \n", + "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 31.0 NaN \n", + "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 32.0 NaN \n", + "3 2018 /euro/teams/real-madrid/2018.html Liga ACB es 17.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 2.7 0.3 1.0 0.333 ... 0.3 0.3 \n", + "1 14.2 1.6 3.1 0.526 ... 0.6 2.2 \n", + "2 19.9 2.7 5.8 0.460 ... 1.0 3.3 \n", + "3 23.6 4.6 9.8 0.473 ... 1.1 4.8 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", + "1 2.8 2.0 0.4 0.3 1.5 1.9 4.9 \n", + "2 4.3 3.1 0.7 0.4 2.0 1.3 7.8 \n", + "3 5.9 4.6 0.9 0.2 1.9 1.6 14.1 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "\n", + "[4 rows x 29 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='P', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes2.0NaN8.00.51.50.333...0.02.02.00.00.00.00.50.01.0True
12016/euro/teams/real-madrid/2016.htmlLiga ACBes8.0NaN8.01.32.40.526...0.31.41.60.90.30.10.91.63.1True
22017/euro/teams/real-madrid/2017.htmlLiga ACBes10.0NaN19.22.36.00.383...0.93.84.72.70.30.01.31.16.5True
\n", + "

3 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 2.0 NaN \n", + "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 8.0 NaN \n", + "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 10.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 8.0 0.5 1.5 0.333 ... 0.0 2.0 \n", + "1 8.0 1.3 2.4 0.526 ... 0.3 1.4 \n", + "2 19.2 2.3 6.0 0.383 ... 0.9 3.8 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", + "1 1.6 0.9 0.3 0.1 0.9 1.6 3.1 \n", + "2 4.7 2.7 0.3 0.0 1.3 1.1 6.5 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "\n", + "[3 rows x 29 columns]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='B', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes3.0NaN2.70.31.00.333...0.30.30.70.00.00.00.00.32.0False
12016/euro/teams/real-madrid/2016.htmlLiga ACBes31.0NaN14.21.63.10.526...0.62.22.82.00.40.31.51.94.9False
22017/euro/teams/real-madrid/2017.htmlLiga ACBes32.0NaN19.92.75.80.460...1.03.34.33.10.70.42.01.37.8False
32018/euro/teams/real-madrid/2018.htmlLiga ACBes17.0NaN23.64.69.80.473...1.14.85.94.60.90.21.91.614.1False
42015/euro/teams/real-madrid/2015.htmlLiga ACBes2.0NaN8.00.51.50.333...0.02.02.00.00.00.00.50.01.0True
\n", + "

5 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 3.0 NaN \n", + "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 31.0 NaN \n", + "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 32.0 NaN \n", + "3 2018 /euro/teams/real-madrid/2018.html Liga ACB es 17.0 NaN \n", + "4 2015 /euro/teams/real-madrid/2015.html Liga ACB es 2.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 2.7 0.3 1.0 0.333 ... 0.3 0.3 \n", + "1 14.2 1.6 3.1 0.526 ... 0.6 2.2 \n", + "2 19.9 2.7 5.8 0.460 ... 1.0 3.3 \n", + "3 23.6 4.6 9.8 0.473 ... 1.1 4.8 \n", + "4 8.0 0.5 1.5 0.333 ... 0.0 2.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", + "1 2.8 2.0 0.4 0.3 1.5 1.9 4.9 \n", + "2 4.3 3.1 0.7 0.4 2.0 1.3 7.8 \n", + "3 5.9 4.6 0.9 0.2 1.9 1.6 14.1 \n", + "4 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 True \n", + "\n", + "[5 rows x 29 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='E' - Eurocup/Euroleague (because Eurocup/Euroleague will never have sep playoffs, kind modifier does nothing) -> need to deal with duplicate when kind='B' " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='B', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5False
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8False
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3False
32016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5True
42017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8True
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", + "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", + "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", + "3 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", + "4 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", + "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", + "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", + "3 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", + "4 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", + "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", + "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", + "3 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", + "4 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 True \n", + "4 True \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='R', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5False
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8False
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3False
\n", + "

3 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", + "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", + "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", + "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", + "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", + "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", + "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "\n", + "[3 rows x 28 columns]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "df = p.stats_per_game(kind='P', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5True
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8True
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3True
\n", + "

3 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", + "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", + "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", + "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", + "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", + "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", + "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "\n", + "[3 rows x 28 columns]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 17071e35685b74a5253c314bd0e9207b3ccd0489 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 18:07:33 -0500 Subject: [PATCH 25/57] initial teams changes --- sportsref/euro/teams.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 86d56f9..67f40b0 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -10,7 +10,7 @@ class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): def __init__(self, team_id): - self.team_id = team_id.upper() + self.team_id = team_id def __eq__(self, other): return (self.team_id == other.team_id) @@ -20,13 +20,13 @@ def __hash__(self): @sportsref.decorators.memoize def team_year_url(self, yr_str): - return (sportsref.nba.BASE_URL + + return (sportsref.euro.BASE_URL + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) @sportsref.decorators.memoize def get_main_doc(self): relURL = '/teams/{}'.format(self.team_id) - teamURL = sportsref.nba.BASE_URL + relURL + teamURL = sportsref.euro.BASE_URL + relURL mainDoc = pq(sportsref.utils.get_html(teamURL)) return mainDoc From 04e29b0eeccc5a9cd5ad1e07c3f99bfb5a1ccbbd Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 18:23:05 -0500 Subject: [PATCH 26/57] name working --- sportsref/euro/teams.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 67f40b0..2361767 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -45,7 +45,7 @@ def name(self): :returns: A string corresponding to the team's full name. """ doc = self.get_main_doc() - name = doc('div#info h1[itemprop="name"]').text() + name = doc('title').text().replace(' Seasons | Basketball-Reference.com', '') return name @sportsref.decorators.memoize From 928c3e73149d925ca26370fb4618f3290f3f9291 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 19:46:06 -0500 Subject: [PATCH 27/57] table id's (no level yet) --- sportsref/euro/teams.py | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 2361767..a1b45b1 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -31,7 +31,7 @@ def get_main_doc(self): return mainDoc @sportsref.decorators.memoize - def get_year_doc(self, yr_str): + def get_year_level_doc(self, yr_str, level='B'): return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) @sportsref.decorators.memoize @@ -48,28 +48,30 @@ def name(self): name = doc('title').text().replace(' Seasons | Basketball-Reference.com', '') return name - @sportsref.decorators.memoize - def roster(self, year): - """Returns the roster table for the given year. - - :year: The year for which we want the roster; defaults to current year. - :returns: A DataFrame containing roster information for that year. - """ + def get_stats_table(self, table_id, year, level='B'): doc = self.get_year_doc(year) - table = doc('table#roster') + table = doc('table#{}'.format(table_id) df = sportsref.utils.parse_table(table) - df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) + return df - # TODO: kind_rpb @sportsref.decorators.memoize - def schedule(self, year): - """Gets schedule information for a team-season. + def all_team_opp_stats(self, year, level='B'): + return self.get_stats_table(year, 'team_and_opp', level=level) + + @sportsref.decorators.memoize + def stats_per_game(self, year, level='B'): + return self.get_stats_table(year, 'per_game', level=level) + + @sportsref.decorators.memoize + def stats_totals(self, year, level='B'): + return self.get_stats_table(year, 'totals', level=level) + + @sportsref.decorators.memoize + def stats_per36(self, year, level='B'): + return self.get_stats_table(year, 'per_minute', level=level) + + @sportsref.decorators.memoize + def stats_advanced(self, year, level='B'): + return self.get_stats_table(year, 'advanced', level=level) - :year: The year for which we want the schedule. - :returns: DataFrame of schedule information. - """ - doc = self.get_year_doc('{}_games'.format(year)) - table = doc('table#games') - df = sportsref.utils.parse_table(table) - return df From 889a1ac308ae76e51439a59ed6337000dea9b97b Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 21:17:50 -0500 Subject: [PATCH 28/57] tables fixed --- sportsref/euro/teams.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index a1b45b1..990eaa3 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -19,7 +19,13 @@ def __hash__(self): return hash(self.team_id) @sportsref.decorators.memoize - def team_year_url(self, yr_str): + def team_year_url(self, year, level='B'): + yr_str = str(year) + if level == 'C': + yr_str += '_' + self.get_league_id(year=year) + elif level == 'E': + yr_str += '_euroleague' + return (sportsref.euro.BASE_URL + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) @@ -31,8 +37,21 @@ def get_main_doc(self): return mainDoc @sportsref.decorators.memoize - def get_year_level_doc(self, yr_str, level='B'): - return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) + def get_year_doc(self, yr_str, level='B'): + return pq(sportsref.utils.get_html(self.team_year_url(yr_str, level=level))) + + @sportsref.decorators.memoize + def get_league_id(self, year=2018): + """ Year parameter here in case team switched club-play leagues - also makes it easier to find in doc""" + doc = self.get_main_doc() + table = doc('table#team-index-club') + + start = '/euro/' + end = '/{}.html'.format(year) + + for a in table('a[href$="{}"]'.format(end)).items(): + if 'years' not in a.attr('href'): + return a.attr('href')[len(start):-len(end)] @sportsref.decorators.memoize def name(self): @@ -49,29 +68,29 @@ def name(self): return name def get_stats_table(self, table_id, year, level='B'): - doc = self.get_year_doc(year) - table = doc('table#{}'.format(table_id) + doc = self.get_year_doc(year, level=level) + table = doc('table#{}'.format(table_id)) df = sportsref.utils.parse_table(table) return df @sportsref.decorators.memoize def all_team_opp_stats(self, year, level='B'): - return self.get_stats_table(year, 'team_and_opp', level=level) + return self.get_stats_table('team_and_opp', year, level=level) @sportsref.decorators.memoize def stats_per_game(self, year, level='B'): - return self.get_stats_table(year, 'per_game', level=level) + return self.get_stats_table('per_game', year, level=level) @sportsref.decorators.memoize def stats_totals(self, year, level='B'): - return self.get_stats_table(year, 'totals', level=level) + return self.get_stats_table('totals', year, level=level) @sportsref.decorators.memoize def stats_per36(self, year, level='B'): - return self.get_stats_table(year, 'per_minute', level=level) + return self.get_stats_table('per_minute', year, level=level) @sportsref.decorators.memoize def stats_advanced(self, year, level='B'): - return self.get_stats_table(year, 'advanced', level=level) + return self.get_stats_table('advanced', year, level=level) From 8c926822837d52848287a1a52ae6365d58c56f6f Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 21:22:28 -0500 Subject: [PATCH 29/57] add test notebook --- euro_teams_test.ipynb | 6369 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6369 insertions(+) create mode 100644 euro_teams_test.ipynb diff --git a/euro_teams_test.ipynb b/euro_teams_test.ipynb new file mode 100644 index 0000000..3b76214 --- /dev/null +++ b/euro_teams_test.ipynb @@ -0,0 +1,6369 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from sportsref import euro" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "t = euro.Team('barcelona')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "i = t.get_league_id()\n", + "name = t.name()" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "spain-liga-acb\n", + "FC Barcelona\n" + ] + } + ], + "source": [ + "print(i)\n", + "print(name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tables are same as player: \n", + "\n", + "### 'E' = Euroleague\n", + "### 'C' = Club play\n", + "### 'B' = both (combined in 1 table, not concatenated together like playoff/reg season tables)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## all team and opp stats table:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "df = t.all_team_opp_stats(2017, level = 'B')" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: []" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: [], ((, 2017, 'E'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: [], ((, 2017, 'C'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: []}\n", + "KEY in wrapper\n", + "((, 2017, 'E'), frozenset())\n", + "COPY\n", + "RET worked\n", + "Empty DataFrame\n", + "Columns: []\n", + "Index: []\n" + ] + } + ], + "source": [ + "df = t.all_team_opp_stats(2017, level = 'E')" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: []" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: [], ((, 2017, 'E'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: [], ((, 2017, 'C'), frozenset()): Empty DataFrame\n", + "Columns: []\n", + "Index: []}\n", + "KEY in wrapper\n", + "((, 2017, 'C'), frozenset())\n", + "COPY\n", + "RET worked\n", + "Empty DataFrame\n", + "Columns: []\n", + "Index: []\n" + ] + } + ], + "source": [ + "df = t.all_team_opp_stats(2017, level = 'C')" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: []" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## per game table" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", + "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", + "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", + "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", + "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", + "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", + "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", + "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", + "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", + "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", + "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", + "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", + "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", + "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "5 1.0 2.5 0.406 ... 0.5 1.3 \n", + "6 0.9 2.8 0.309 ... 0.4 2.4 \n", + "7 0.7 1.7 0.403 ... 0.6 1.4 \n", + "8 1.1 2.0 0.527 ... 0.7 2.4 \n", + "9 0.0 0.0 NaN ... 2.1 3.8 \n", + "10 1.0 3.3 0.308 ... 0.1 0.8 \n", + "11 1.0 2.5 0.422 ... 0.3 1.1 \n", + "12 0.1 0.7 0.200 ... 1.1 3.4 \n", + "13 0.9 2.0 0.450 ... 0.8 2.2 \n", + "14 0.0 0.0 NaN ... 1.3 1.8 \n", + "15 0.1 0.7 0.133 ... 0.2 0.6 \n", + "16 0.3 0.8 0.333 ... 0.2 0.7 \n", + "17 1.7 4.0 0.417 ... 0.0 1.3 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "20 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", + "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", + "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", + "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", + "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", + "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", + "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", + "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", + "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", + "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", + "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", + "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", + "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", + "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 12.3 Tyrese Rice \n", + "1 10.8 Ante Tomic \n", + "2 9.4 Petteri Koponen \n", + "3 5.5 Victor Claver \n", + "4 8.3 Aleksandar Vezenkov \n", + "5 6.2 Brad Oleson \n", + "6 7.1 Stratos Perperoglou \n", + "7 4.7 Alex Renfroe \n", + "8 9.9 Justin Doellman \n", + "9 4.6 Joey Dorsey \n", + "10 6.5 Juan Carlos Navarro \n", + "11 4.7 Marcus Eriksson \n", + "12 8.3 Vitor Faverani \n", + "13 5.9 Jonathan Holmes \n", + "14 2.7 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.5 Xavier Munford \n", + "17 6.7 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "20 2.0 Rodions Kurucs \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", + "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", + "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", + "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", + "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", + "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", + "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", + "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.8 5.7 0.320 ... 0.3 1.4 \n", + "1 0.0 0.0 0.000 ... 2.2 3.7 \n", + "2 2.0 4.4 0.462 ... 0.2 1.5 \n", + "3 0.9 2.3 0.377 ... 0.9 3.5 \n", + "4 1.1 2.4 0.479 ... 0.8 2.4 \n", + "5 0.8 2.4 0.345 ... 0.5 1.4 \n", + "6 0.9 2.4 0.358 ... 0.4 2.8 \n", + "7 0.7 1.8 0.387 ... 0.6 1.5 \n", + "8 1.0 1.9 0.536 ... 0.7 2.5 \n", + "9 0.0 0.0 NaN ... 2.7 3.6 \n", + "10 1.0 3.5 0.286 ... 0.1 1.0 \n", + "11 0.5 1.5 0.353 ... 0.3 0.9 \n", + "12 0.1 0.8 0.143 ... 0.9 3.3 \n", + "13 0.6 1.7 0.333 ... 1.1 1.6 \n", + "14 0.0 0.0 NaN ... 1.0 2.5 \n", + "15 0.1 0.3 0.333 ... 0.2 0.4 \n", + "16 0.2 0.6 0.333 ... 0.4 0.6 \n", + "17 1.5 3.0 0.500 ... 0.0 0.5 \n", + "18 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", + "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", + "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", + "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", + "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", + "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", + "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", + "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", + "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", + "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", + "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", + "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", + "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", + "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", + "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", + "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", + "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", + "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 13.0 Tyrese Rice \n", + "1 8.8 Ante Tomic \n", + "2 10.1 Petteri Koponen \n", + "3 6.0 Victor Claver \n", + "4 7.5 Aleksandar Vezenkov \n", + "5 5.3 Brad Oleson \n", + "6 6.4 Stratos Perperoglou \n", + "7 3.9 Alex Renfroe \n", + "8 7.8 Justin Doellman \n", + "9 5.5 Joey Dorsey \n", + "10 5.7 Juan Carlos Navarro \n", + "11 2.0 Marcus Eriksson \n", + "12 7.7 Vitor Faverani \n", + "13 5.1 Jonathan Holmes \n", + "14 2.6 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.0 Xavier Munford \n", + "17 4.5 Pau Ribas \n", + "18 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", + "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", + "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", + "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", + "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", + "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", + "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.4 4.7 0.293 ... 0.2 1.3 \n", + "1 0.0 0.1 0.500 ... 2.0 5.8 \n", + "2 1.2 3.1 0.378 ... 0.9 2.2 \n", + "3 1.2 2.6 0.453 ... 0.6 1.2 \n", + "4 0.9 2.2 0.413 ... 0.8 3.3 \n", + "5 1.1 3.1 0.353 ... 0.4 1.8 \n", + "6 0.9 3.2 0.277 ... 0.3 2.2 \n", + "7 1.4 3.1 0.447 ... 0.3 1.3 \n", + "8 0.7 1.6 0.419 ... 0.6 1.3 \n", + "9 1.2 2.3 0.519 ... 0.7 2.4 \n", + "10 0.0 0.0 NaN ... 1.5 3.9 \n", + "11 1.0 3.0 0.333 ... 0.1 0.6 \n", + "12 0.0 0.0 NaN ... 1.5 1.4 \n", + "13 0.2 0.5 0.333 ... 1.5 3.5 \n", + "14 0.1 1.0 0.083 ... 0.2 0.8 \n", + "15 1.7 2.7 0.625 ... 0.0 3.7 \n", + "16 0.3 1.0 0.333 ... 0.0 0.8 \n", + "17 2.0 6.0 0.333 ... 0.0 3.0 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", + "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", + "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", + "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", + "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", + "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", + "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", + "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", + "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", + "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", + "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", + "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", + "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", + "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", + "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", + "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", + "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", + "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 11.6 Tyrese Rice \n", + "1 12.7 Ante Tomic \n", + "2 9.0 Aleksandar Vezenkov \n", + "3 7.0 Brad Oleson \n", + "4 5.0 Victor Claver \n", + "5 8.7 Petteri Koponen \n", + "6 7.8 Stratos Perperoglou \n", + "7 6.7 Marcus Eriksson \n", + "8 5.4 Alex Renfroe \n", + "9 12.6 Justin Doellman \n", + "10 3.7 Joey Dorsey \n", + "11 7.3 Juan Carlos Navarro \n", + "12 2.7 Moussa Diagne \n", + "13 9.2 Vitor Faverani \n", + "14 1.1 Stefan Peno \n", + "15 7.7 Jonathan Holmes \n", + "16 2.0 Xavier Munford \n", + "17 11.0 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'B'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", + "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", + "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", + "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", + "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", + "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", + "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", + "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", + "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", + "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", + "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", + "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", + "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", + "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "5 1.0 2.5 0.406 ... 0.5 1.3 \n", + "6 0.9 2.8 0.309 ... 0.4 2.4 \n", + "7 0.7 1.7 0.403 ... 0.6 1.4 \n", + "8 1.1 2.0 0.527 ... 0.7 2.4 \n", + "9 0.0 0.0 NaN ... 2.1 3.8 \n", + "10 1.0 3.3 0.308 ... 0.1 0.8 \n", + "11 1.0 2.5 0.422 ... 0.3 1.1 \n", + "12 0.1 0.7 0.200 ... 1.1 3.4 \n", + "13 0.9 2.0 0.450 ... 0.8 2.2 \n", + "14 0.0 0.0 NaN ... 1.3 1.8 \n", + "15 0.1 0.7 0.133 ... 0.2 0.6 \n", + "16 0.3 0.8 0.333 ... 0.2 0.7 \n", + "17 1.7 4.0 0.417 ... 0.0 1.3 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "20 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", + "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", + "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", + "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", + "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", + "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", + "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", + "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", + "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", + "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", + "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", + "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", + "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", + "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 12.3 Tyrese Rice \n", + "1 10.8 Ante Tomic \n", + "2 9.4 Petteri Koponen \n", + "3 5.5 Victor Claver \n", + "4 8.3 Aleksandar Vezenkov \n", + "5 6.2 Brad Oleson \n", + "6 7.1 Stratos Perperoglou \n", + "7 4.7 Alex Renfroe \n", + "8 9.9 Justin Doellman \n", + "9 4.6 Joey Dorsey \n", + "10 6.5 Juan Carlos Navarro \n", + "11 4.7 Marcus Eriksson \n", + "12 8.3 Vitor Faverani \n", + "13 5.9 Jonathan Holmes \n", + "14 2.7 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.5 Xavier Munford \n", + "17 6.7 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "20 2.0 Rodions Kurucs \n", + "\n", + "[21 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per_game(2017, level='B')" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-161.0NaN27.54.210.80.3901.65.20.307...0.21.31.64.11.00.12.52.312.3Tyrese Rice
1ante-tomic-161.0NaN22.44.37.30.5900.00.00.333...2.14.86.92.00.60.61.62.210.8Ante Tomic
2petteri-koponen-154.0NaN22.13.17.20.4361.63.80.417...0.31.71.92.10.70.11.31.99.4Petteri Koponen
3victor-claver-156.0NaN21.22.04.30.4710.92.20.395...0.83.44.31.20.90.41.32.05.5Victor Claver
4aleksandar-vezenkov-162.0NaN18.63.05.50.5531.12.70.420...0.92.33.21.00.60.20.71.98.3Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 12.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 10.8 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 9.4 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 5.5 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 8.3 \n", + "\n", + " player_name \n", + "0 Tyrese Rice \n", + "1 Ante Tomic \n", + "2 Petteri Koponen \n", + "3 Victor Claver \n", + "4 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", + "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", + "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", + "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", + "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", + "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", + "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", + "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", + "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", + "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", + "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", + "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", + "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", + "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "5 1.0 2.5 0.406 ... 0.5 1.3 \n", + "6 0.9 2.8 0.309 ... 0.4 2.4 \n", + "7 0.7 1.7 0.403 ... 0.6 1.4 \n", + "8 1.1 2.0 0.527 ... 0.7 2.4 \n", + "9 0.0 0.0 NaN ... 2.1 3.8 \n", + "10 1.0 3.3 0.308 ... 0.1 0.8 \n", + "11 1.0 2.5 0.422 ... 0.3 1.1 \n", + "12 0.1 0.7 0.200 ... 1.1 3.4 \n", + "13 0.9 2.0 0.450 ... 0.8 2.2 \n", + "14 0.0 0.0 NaN ... 1.3 1.8 \n", + "15 0.1 0.7 0.133 ... 0.2 0.6 \n", + "16 0.3 0.8 0.333 ... 0.2 0.7 \n", + "17 1.7 4.0 0.417 ... 0.0 1.3 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "20 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", + "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", + "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", + "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", + "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", + "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", + "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", + "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", + "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", + "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", + "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", + "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", + "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", + "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 12.3 Tyrese Rice \n", + "1 10.8 Ante Tomic \n", + "2 9.4 Petteri Koponen \n", + "3 5.5 Victor Claver \n", + "4 8.3 Aleksandar Vezenkov \n", + "5 6.2 Brad Oleson \n", + "6 7.1 Stratos Perperoglou \n", + "7 4.7 Alex Renfroe \n", + "8 9.9 Justin Doellman \n", + "9 4.6 Joey Dorsey \n", + "10 6.5 Juan Carlos Navarro \n", + "11 4.7 Marcus Eriksson \n", + "12 8.3 Vitor Faverani \n", + "13 5.9 Jonathan Holmes \n", + "14 2.7 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.5 Xavier Munford \n", + "17 6.7 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "20 2.0 Rodions Kurucs \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", + "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", + "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", + "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", + "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", + "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", + "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", + "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.8 5.7 0.320 ... 0.3 1.4 \n", + "1 0.0 0.0 0.000 ... 2.2 3.7 \n", + "2 2.0 4.4 0.462 ... 0.2 1.5 \n", + "3 0.9 2.3 0.377 ... 0.9 3.5 \n", + "4 1.1 2.4 0.479 ... 0.8 2.4 \n", + "5 0.8 2.4 0.345 ... 0.5 1.4 \n", + "6 0.9 2.4 0.358 ... 0.4 2.8 \n", + "7 0.7 1.8 0.387 ... 0.6 1.5 \n", + "8 1.0 1.9 0.536 ... 0.7 2.5 \n", + "9 0.0 0.0 NaN ... 2.7 3.6 \n", + "10 1.0 3.5 0.286 ... 0.1 1.0 \n", + "11 0.5 1.5 0.353 ... 0.3 0.9 \n", + "12 0.1 0.8 0.143 ... 0.9 3.3 \n", + "13 0.6 1.7 0.333 ... 1.1 1.6 \n", + "14 0.0 0.0 NaN ... 1.0 2.5 \n", + "15 0.1 0.3 0.333 ... 0.2 0.4 \n", + "16 0.2 0.6 0.333 ... 0.4 0.6 \n", + "17 1.5 3.0 0.500 ... 0.0 0.5 \n", + "18 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", + "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", + "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", + "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", + "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", + "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", + "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", + "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", + "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", + "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", + "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", + "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", + "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", + "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", + "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", + "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", + "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", + "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 13.0 Tyrese Rice \n", + "1 8.8 Ante Tomic \n", + "2 10.1 Petteri Koponen \n", + "3 6.0 Victor Claver \n", + "4 7.5 Aleksandar Vezenkov \n", + "5 5.3 Brad Oleson \n", + "6 6.4 Stratos Perperoglou \n", + "7 3.9 Alex Renfroe \n", + "8 7.8 Justin Doellman \n", + "9 5.5 Joey Dorsey \n", + "10 5.7 Juan Carlos Navarro \n", + "11 2.0 Marcus Eriksson \n", + "12 7.7 Vitor Faverani \n", + "13 5.1 Jonathan Holmes \n", + "14 2.6 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.0 Xavier Munford \n", + "17 4.5 Pau Ribas \n", + "18 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", + "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", + "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", + "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", + "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", + "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", + "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.4 4.7 0.293 ... 0.2 1.3 \n", + "1 0.0 0.1 0.500 ... 2.0 5.8 \n", + "2 1.2 3.1 0.378 ... 0.9 2.2 \n", + "3 1.2 2.6 0.453 ... 0.6 1.2 \n", + "4 0.9 2.2 0.413 ... 0.8 3.3 \n", + "5 1.1 3.1 0.353 ... 0.4 1.8 \n", + "6 0.9 3.2 0.277 ... 0.3 2.2 \n", + "7 1.4 3.1 0.447 ... 0.3 1.3 \n", + "8 0.7 1.6 0.419 ... 0.6 1.3 \n", + "9 1.2 2.3 0.519 ... 0.7 2.4 \n", + "10 0.0 0.0 NaN ... 1.5 3.9 \n", + "11 1.0 3.0 0.333 ... 0.1 0.6 \n", + "12 0.0 0.0 NaN ... 1.5 1.4 \n", + "13 0.2 0.5 0.333 ... 1.5 3.5 \n", + "14 0.1 1.0 0.083 ... 0.2 0.8 \n", + "15 1.7 2.7 0.625 ... 0.0 3.7 \n", + "16 0.3 1.0 0.333 ... 0.0 0.8 \n", + "17 2.0 6.0 0.333 ... 0.0 3.0 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", + "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", + "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", + "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", + "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", + "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", + "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", + "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", + "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", + "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", + "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", + "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", + "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", + "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", + "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", + "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", + "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", + "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 11.6 Tyrese Rice \n", + "1 12.7 Ante Tomic \n", + "2 9.0 Aleksandar Vezenkov \n", + "3 7.0 Brad Oleson \n", + "4 5.0 Victor Claver \n", + "5 8.7 Petteri Koponen \n", + "6 7.8 Stratos Perperoglou \n", + "7 6.7 Marcus Eriksson \n", + "8 5.4 Alex Renfroe \n", + "9 12.6 Justin Doellman \n", + "10 3.7 Joey Dorsey \n", + "11 7.3 Juan Carlos Navarro \n", + "12 2.7 Moussa Diagne \n", + "13 9.2 Vitor Faverani \n", + "14 1.1 Stefan Peno \n", + "15 7.7 Jonathan Holmes \n", + "16 2.0 Xavier Munford \n", + "17 11.0 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'E'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", + "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", + "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", + "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", + "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", + "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", + "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", + "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.8 5.7 0.320 ... 0.3 1.4 \n", + "1 0.0 0.0 0.000 ... 2.2 3.7 \n", + "2 2.0 4.4 0.462 ... 0.2 1.5 \n", + "3 0.9 2.3 0.377 ... 0.9 3.5 \n", + "4 1.1 2.4 0.479 ... 0.8 2.4 \n", + "5 0.8 2.4 0.345 ... 0.5 1.4 \n", + "6 0.9 2.4 0.358 ... 0.4 2.8 \n", + "7 0.7 1.8 0.387 ... 0.6 1.5 \n", + "8 1.0 1.9 0.536 ... 0.7 2.5 \n", + "9 0.0 0.0 NaN ... 2.7 3.6 \n", + "10 1.0 3.5 0.286 ... 0.1 1.0 \n", + "11 0.5 1.5 0.353 ... 0.3 0.9 \n", + "12 0.1 0.8 0.143 ... 0.9 3.3 \n", + "13 0.6 1.7 0.333 ... 1.1 1.6 \n", + "14 0.0 0.0 NaN ... 1.0 2.5 \n", + "15 0.1 0.3 0.333 ... 0.2 0.4 \n", + "16 0.2 0.6 0.333 ... 0.4 0.6 \n", + "17 1.5 3.0 0.500 ... 0.0 0.5 \n", + "18 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", + "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", + "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", + "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", + "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", + "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", + "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", + "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", + "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", + "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", + "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", + "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", + "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", + "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", + "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", + "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", + "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", + "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 13.0 Tyrese Rice \n", + "1 8.8 Ante Tomic \n", + "2 10.1 Petteri Koponen \n", + "3 6.0 Victor Claver \n", + "4 7.5 Aleksandar Vezenkov \n", + "5 5.3 Brad Oleson \n", + "6 6.4 Stratos Perperoglou \n", + "7 3.9 Alex Renfroe \n", + "8 7.8 Justin Doellman \n", + "9 5.5 Joey Dorsey \n", + "10 5.7 Juan Carlos Navarro \n", + "11 2.0 Marcus Eriksson \n", + "12 7.7 Vitor Faverani \n", + "13 5.1 Jonathan Holmes \n", + "14 2.6 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.0 Xavier Munford \n", + "17 4.5 Pau Ribas \n", + "18 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per_game(2017, level='E')" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-130.0NaN29.64.612.10.3761.85.70.320...0.31.41.64.91.10.12.62.113.0Tyrese Rice
1ante-tomic-129.0NaN21.83.66.90.5250.00.00.000...2.23.75.92.00.60.71.92.18.8Ante Tomic
2petteri-koponen-127.0NaN22.63.37.60.4292.04.40.462...0.21.51.71.90.70.01.31.910.1Petteri Koponen
3victor-claver-127.0NaN22.02.14.50.4590.92.30.377...0.93.54.41.30.90.31.21.76.0Victor Claver
4aleksandar-vezenkov-130.0NaN18.42.74.70.5771.12.40.479...0.82.43.21.10.70.20.61.57.5Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", + "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", + "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.8 5.7 0.320 ... 0.3 1.4 \n", + "1 0.0 0.0 0.000 ... 2.2 3.7 \n", + "2 2.0 4.4 0.462 ... 0.2 1.5 \n", + "3 0.9 2.3 0.377 ... 0.9 3.5 \n", + "4 1.1 2.4 0.479 ... 0.8 2.4 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 1.6 4.9 1.1 0.1 2.6 2.1 13.0 \n", + "1 5.9 2.0 0.6 0.7 1.9 2.1 8.8 \n", + "2 1.7 1.9 0.7 0.0 1.3 1.9 10.1 \n", + "3 4.4 1.3 0.9 0.3 1.2 1.7 6.0 \n", + "4 3.2 1.1 0.7 0.2 0.6 1.5 7.5 \n", + "\n", + " player_name \n", + "0 Tyrese Rice \n", + "1 Ante Tomic \n", + "2 Petteri Koponen \n", + "3 Victor Claver \n", + "4 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", + "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", + "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", + "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", + "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", + "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", + "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", + "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", + "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", + "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", + "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", + "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", + "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", + "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "5 1.0 2.5 0.406 ... 0.5 1.3 \n", + "6 0.9 2.8 0.309 ... 0.4 2.4 \n", + "7 0.7 1.7 0.403 ... 0.6 1.4 \n", + "8 1.1 2.0 0.527 ... 0.7 2.4 \n", + "9 0.0 0.0 NaN ... 2.1 3.8 \n", + "10 1.0 3.3 0.308 ... 0.1 0.8 \n", + "11 1.0 2.5 0.422 ... 0.3 1.1 \n", + "12 0.1 0.7 0.200 ... 1.1 3.4 \n", + "13 0.9 2.0 0.450 ... 0.8 2.2 \n", + "14 0.0 0.0 NaN ... 1.3 1.8 \n", + "15 0.1 0.7 0.133 ... 0.2 0.6 \n", + "16 0.3 0.8 0.333 ... 0.2 0.7 \n", + "17 1.7 4.0 0.417 ... 0.0 1.3 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "20 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", + "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", + "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", + "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", + "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", + "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", + "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", + "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", + "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", + "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", + "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", + "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", + "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", + "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 12.3 Tyrese Rice \n", + "1 10.8 Ante Tomic \n", + "2 9.4 Petteri Koponen \n", + "3 5.5 Victor Claver \n", + "4 8.3 Aleksandar Vezenkov \n", + "5 6.2 Brad Oleson \n", + "6 7.1 Stratos Perperoglou \n", + "7 4.7 Alex Renfroe \n", + "8 9.9 Justin Doellman \n", + "9 4.6 Joey Dorsey \n", + "10 6.5 Juan Carlos Navarro \n", + "11 4.7 Marcus Eriksson \n", + "12 8.3 Vitor Faverani \n", + "13 5.9 Jonathan Holmes \n", + "14 2.7 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.5 Xavier Munford \n", + "17 6.7 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "20 2.0 Rodions Kurucs \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", + "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", + "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", + "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", + "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", + "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", + "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", + "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.8 5.7 0.320 ... 0.3 1.4 \n", + "1 0.0 0.0 0.000 ... 2.2 3.7 \n", + "2 2.0 4.4 0.462 ... 0.2 1.5 \n", + "3 0.9 2.3 0.377 ... 0.9 3.5 \n", + "4 1.1 2.4 0.479 ... 0.8 2.4 \n", + "5 0.8 2.4 0.345 ... 0.5 1.4 \n", + "6 0.9 2.4 0.358 ... 0.4 2.8 \n", + "7 0.7 1.8 0.387 ... 0.6 1.5 \n", + "8 1.0 1.9 0.536 ... 0.7 2.5 \n", + "9 0.0 0.0 NaN ... 2.7 3.6 \n", + "10 1.0 3.5 0.286 ... 0.1 1.0 \n", + "11 0.5 1.5 0.353 ... 0.3 0.9 \n", + "12 0.1 0.8 0.143 ... 0.9 3.3 \n", + "13 0.6 1.7 0.333 ... 1.1 1.6 \n", + "14 0.0 0.0 NaN ... 1.0 2.5 \n", + "15 0.1 0.3 0.333 ... 0.2 0.4 \n", + "16 0.2 0.6 0.333 ... 0.4 0.6 \n", + "17 1.5 3.0 0.500 ... 0.0 0.5 \n", + "18 0.0 1.0 0.000 ... 0.0 0.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", + "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", + "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", + "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", + "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", + "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", + "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", + "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", + "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", + "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", + "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", + "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", + "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", + "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", + "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", + "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", + "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", + "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 13.0 Tyrese Rice \n", + "1 8.8 Ante Tomic \n", + "2 10.1 Petteri Koponen \n", + "3 6.0 Victor Claver \n", + "4 7.5 Aleksandar Vezenkov \n", + "5 5.3 Brad Oleson \n", + "6 6.4 Stratos Perperoglou \n", + "7 3.9 Alex Renfroe \n", + "8 7.8 Justin Doellman \n", + "9 5.5 Joey Dorsey \n", + "10 5.7 Juan Carlos Navarro \n", + "11 2.0 Marcus Eriksson \n", + "12 7.7 Vitor Faverani \n", + "13 5.1 Jonathan Holmes \n", + "14 2.6 Moussa Diagne \n", + "15 1.1 Stefan Peno \n", + "16 1.0 Xavier Munford \n", + "17 4.5 Pau Ribas \n", + "18 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", + "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", + "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", + "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", + "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", + "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", + "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.4 4.7 0.293 ... 0.2 1.3 \n", + "1 0.0 0.1 0.500 ... 2.0 5.8 \n", + "2 1.2 3.1 0.378 ... 0.9 2.2 \n", + "3 1.2 2.6 0.453 ... 0.6 1.2 \n", + "4 0.9 2.2 0.413 ... 0.8 3.3 \n", + "5 1.1 3.1 0.353 ... 0.4 1.8 \n", + "6 0.9 3.2 0.277 ... 0.3 2.2 \n", + "7 1.4 3.1 0.447 ... 0.3 1.3 \n", + "8 0.7 1.6 0.419 ... 0.6 1.3 \n", + "9 1.2 2.3 0.519 ... 0.7 2.4 \n", + "10 0.0 0.0 NaN ... 1.5 3.9 \n", + "11 1.0 3.0 0.333 ... 0.1 0.6 \n", + "12 0.0 0.0 NaN ... 1.5 1.4 \n", + "13 0.2 0.5 0.333 ... 1.5 3.5 \n", + "14 0.1 1.0 0.083 ... 0.2 0.8 \n", + "15 1.7 2.7 0.625 ... 0.0 3.7 \n", + "16 0.3 1.0 0.333 ... 0.0 0.8 \n", + "17 2.0 6.0 0.333 ... 0.0 3.0 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", + "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", + "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", + "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", + "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", + "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", + "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", + "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", + "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", + "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", + "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", + "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", + "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", + "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", + "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", + "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", + "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", + "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 11.6 Tyrese Rice \n", + "1 12.7 Ante Tomic \n", + "2 9.0 Aleksandar Vezenkov \n", + "3 7.0 Brad Oleson \n", + "4 5.0 Victor Claver \n", + "5 8.7 Petteri Koponen \n", + "6 7.8 Stratos Perperoglou \n", + "7 6.7 Marcus Eriksson \n", + "8 5.4 Alex Renfroe \n", + "9 12.6 Justin Doellman \n", + "10 3.7 Joey Dorsey \n", + "11 7.3 Juan Carlos Navarro \n", + "12 2.7 Moussa Diagne \n", + "13 9.2 Vitor Faverani \n", + "14 1.1 Stefan Peno \n", + "15 7.7 Jonathan Holmes \n", + "16 2.0 Xavier Munford \n", + "17 11.0 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'C'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", + "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", + "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", + "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", + "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", + "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", + "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.4 4.7 0.293 ... 0.2 1.3 \n", + "1 0.0 0.1 0.500 ... 2.0 5.8 \n", + "2 1.2 3.1 0.378 ... 0.9 2.2 \n", + "3 1.2 2.6 0.453 ... 0.6 1.2 \n", + "4 0.9 2.2 0.413 ... 0.8 3.3 \n", + "5 1.1 3.1 0.353 ... 0.4 1.8 \n", + "6 0.9 3.2 0.277 ... 0.3 2.2 \n", + "7 1.4 3.1 0.447 ... 0.3 1.3 \n", + "8 0.7 1.6 0.419 ... 0.6 1.3 \n", + "9 1.2 2.3 0.519 ... 0.7 2.4 \n", + "10 0.0 0.0 NaN ... 1.5 3.9 \n", + "11 1.0 3.0 0.333 ... 0.1 0.6 \n", + "12 0.0 0.0 NaN ... 1.5 1.4 \n", + "13 0.2 0.5 0.333 ... 1.5 3.5 \n", + "14 0.1 1.0 0.083 ... 0.2 0.8 \n", + "15 1.7 2.7 0.625 ... 0.0 3.7 \n", + "16 0.3 1.0 0.333 ... 0.0 0.8 \n", + "17 2.0 6.0 0.333 ... 0.0 3.0 \n", + "18 0.0 0.0 NaN ... 0.0 0.0 \n", + "19 0.0 0.0 NaN ... 1.0 1.0 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", + "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", + "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", + "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", + "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", + "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", + "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", + "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", + "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", + "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", + "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", + "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", + "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", + "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", + "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", + "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", + "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", + "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", + "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", + "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pts_per_g player_name \n", + "0 11.6 Tyrese Rice \n", + "1 12.7 Ante Tomic \n", + "2 9.0 Aleksandar Vezenkov \n", + "3 7.0 Brad Oleson \n", + "4 5.0 Victor Claver \n", + "5 8.7 Petteri Koponen \n", + "6 7.8 Stratos Perperoglou \n", + "7 6.7 Marcus Eriksson \n", + "8 5.4 Alex Renfroe \n", + "9 12.6 Justin Doellman \n", + "10 3.7 Joey Dorsey \n", + "11 7.3 Juan Carlos Navarro \n", + "12 2.7 Moussa Diagne \n", + "13 9.2 Vitor Faverani \n", + "14 1.1 Stefan Peno \n", + "15 7.7 Jonathan Holmes \n", + "16 2.0 Xavier Munford \n", + "17 11.0 Pau Ribas \n", + "18 0.0 Pol Figueras \n", + "19 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per_game(2017, level='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-131.030.025.53.89.50.4061.44.70.293...0.21.31.53.40.80.02.42.511.6Tyrese Rice
1ante-tomic-132.027.022.94.97.60.6430.00.10.500...2.05.87.92.10.60.51.32.312.7Ante Tomic
2aleksandar-vezenkov-132.06.018.93.36.10.5361.23.10.378...0.92.23.20.80.50.30.82.29.0Aleksandar Vezenkov
3brad-oleson-129.020.020.82.44.40.5471.22.60.453...0.61.21.81.70.60.11.11.67.0Brad Oleson
4victor-claver-129.023.020.41.94.00.4830.92.20.413...0.83.34.11.20.90.61.42.35.0Victor Claver
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", + "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", + "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", + "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.4 4.7 0.293 ... 0.2 1.3 \n", + "1 0.0 0.1 0.500 ... 2.0 5.8 \n", + "2 1.2 3.1 0.378 ... 0.9 2.2 \n", + "3 1.2 2.6 0.453 ... 0.6 1.2 \n", + "4 0.9 2.2 0.413 ... 0.8 3.3 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 1.5 3.4 0.8 0.0 2.4 2.5 11.6 \n", + "1 7.9 2.1 0.6 0.5 1.3 2.3 12.7 \n", + "2 3.2 0.8 0.5 0.3 0.8 2.2 9.0 \n", + "3 1.8 1.7 0.6 0.1 1.1 1.6 7.0 \n", + "4 4.1 1.2 0.9 0.6 1.4 2.3 5.0 \n", + "\n", + " player_name \n", + "0 Tyrese Rice \n", + "1 Ante Tomic \n", + "2 Aleksandar Vezenkov \n", + "3 Brad Oleson \n", + "4 Victor Claver \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## totals table" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", + "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", + "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", + "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", + "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", + "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", + "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", + "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", + "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", + "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", + "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", + "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", + "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", + "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", + "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", + "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", + "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", + "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", + "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", + "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", + "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", + "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", + "1 36.0 99.0 135.0 661.0 Ante Tomic \n", + "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", + "3 24.0 74.0 111.0 309.0 Victor Claver \n", + "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "5 9.0 51.0 87.0 330.0 Brad Oleson \n", + "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", + "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", + "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", + "9 4.0 33.0 44.0 268.0 Justin Doellman \n", + "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", + "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", + "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", + "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", + "14 1.0 17.0 28.0 24.0 Stefan Peno \n", + "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", + "16 2.0 16.0 11.0 17.0 Xavier Munford \n", + "17 0.0 3.0 3.0 20.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", + "20 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", + "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", + "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", + "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", + "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", + "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", + "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk tov \\\n", + "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", + "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", + "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", + "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", + "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", + "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", + "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", + "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", + "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", + "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", + "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", + "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", + "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", + "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", + "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", + "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", + "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", + "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", + "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf pts player_name \n", + "0 63.0 389.0 Tyrese Rice \n", + "1 62.0 256.0 Ante Tomic \n", + "2 52.0 274.0 Petteri Koponen \n", + "3 45.0 163.0 Victor Claver \n", + "4 46.0 226.0 Aleksandar Vezenkov \n", + "5 40.0 128.0 Brad Oleson \n", + "6 33.0 140.0 Stratos Perperoglou \n", + "7 34.0 67.0 Alex Renfroe \n", + "8 23.0 117.0 Justin Doellman \n", + "9 41.0 93.0 Joey Dorsey \n", + "10 20.0 91.0 Juan Carlos Navarro \n", + "11 26.0 44.0 Marcus Eriksson \n", + "12 17.0 69.0 Vitor Faverani \n", + "13 19.0 36.0 Jonathan Holmes \n", + "14 18.0 21.0 Moussa Diagne \n", + "15 10.0 11.0 Stefan Peno \n", + "16 2.0 5.0 Xavier Munford \n", + "17 2.0 9.0 Pau Ribas \n", + "18 0.0 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", + "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", + "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", + "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", + "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", + "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", + "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", + "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", + "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", + "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", + "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", + "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", + "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", + "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", + "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", + "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", + "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", + "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", + "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", + "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", + "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", + "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", + "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", + "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", + "1 16.0 43.0 73.0 405.0 Ante Tomic \n", + "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", + "3 4.0 31.0 47.0 202.0 Brad Oleson \n", + "4 16.0 41.0 66.0 146.0 Victor Claver \n", + "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", + "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", + "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", + "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", + "9 2.0 19.0 21.0 151.0 Justin Doellman \n", + "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", + "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", + "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", + "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", + "14 0.0 11.0 18.0 13.0 Stefan Peno \n", + "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", + "16 2.0 7.0 9.0 12.0 Xavier Munford \n", + "17 0.0 2.0 1.0 11.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'B'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", + "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", + "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", + "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", + "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", + "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", + "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", + "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", + "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", + "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", + "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", + "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", + "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", + "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", + "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", + "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", + "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", + "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", + "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", + "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", + "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", + "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", + "1 36.0 99.0 135.0 661.0 Ante Tomic \n", + "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", + "3 24.0 74.0 111.0 309.0 Victor Claver \n", + "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "5 9.0 51.0 87.0 330.0 Brad Oleson \n", + "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", + "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", + "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", + "9 4.0 33.0 44.0 268.0 Justin Doellman \n", + "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", + "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", + "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", + "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", + "14 1.0 17.0 28.0 24.0 Stefan Peno \n", + "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", + "16 2.0 16.0 11.0 17.0 Xavier Munford \n", + "17 0.0 3.0 3.0 20.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", + "20 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_totals(2017, level='B')" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-161.0NaN1680.0256.0657.00.39098.0319.00.307...15.080.095.0252.058.04.0151.0142.0750.0Tyrese Rice
1ante-tomic-161.0NaN1367.0262.0444.00.5901.03.00.333...128.0295.0423.0124.035.036.099.0135.0661.0Ante Tomic
2petteri-koponen-154.0NaN1196.0169.0388.00.43685.0204.00.417...15.090.0105.0112.039.03.071.0100.0509.0Petteri Koponen
3victor-claver-156.0NaN1187.0112.0238.00.47149.0124.00.395...46.0192.0238.069.051.024.074.0111.0309.0Victor Claver
4aleksandar-vezenkov-162.0NaN1156.0187.0338.00.55371.0169.00.420...55.0143.0198.061.037.015.045.0115.0513.0Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 319.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 3.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 204.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 124.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 169.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk \\\n", + "0 0.307 ... 15.0 80.0 95.0 252.0 58.0 4.0 \n", + "1 0.333 ... 128.0 295.0 423.0 124.0 35.0 36.0 \n", + "2 0.417 ... 15.0 90.0 105.0 112.0 39.0 3.0 \n", + "3 0.395 ... 46.0 192.0 238.0 69.0 51.0 24.0 \n", + "4 0.420 ... 55.0 143.0 198.0 61.0 37.0 15.0 \n", + "\n", + " tov pf pts player_name \n", + "0 151.0 142.0 750.0 Tyrese Rice \n", + "1 99.0 135.0 661.0 Ante Tomic \n", + "2 71.0 100.0 509.0 Petteri Koponen \n", + "3 74.0 111.0 309.0 Victor Claver \n", + "4 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", + "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", + "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", + "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", + "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", + "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", + "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", + "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", + "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", + "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", + "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", + "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", + "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", + "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", + "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", + "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", + "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", + "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", + "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", + "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", + "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", + "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", + "1 36.0 99.0 135.0 661.0 Ante Tomic \n", + "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", + "3 24.0 74.0 111.0 309.0 Victor Claver \n", + "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "5 9.0 51.0 87.0 330.0 Brad Oleson \n", + "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", + "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", + "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", + "9 4.0 33.0 44.0 268.0 Justin Doellman \n", + "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", + "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", + "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", + "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", + "14 1.0 17.0 28.0 24.0 Stefan Peno \n", + "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", + "16 2.0 16.0 11.0 17.0 Xavier Munford \n", + "17 0.0 3.0 3.0 20.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", + "20 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", + "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", + "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", + "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", + "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", + "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", + "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk tov \\\n", + "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", + "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", + "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", + "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", + "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", + "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", + "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", + "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", + "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", + "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", + "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", + "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", + "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", + "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", + "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", + "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", + "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", + "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", + "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf pts player_name \n", + "0 63.0 389.0 Tyrese Rice \n", + "1 62.0 256.0 Ante Tomic \n", + "2 52.0 274.0 Petteri Koponen \n", + "3 45.0 163.0 Victor Claver \n", + "4 46.0 226.0 Aleksandar Vezenkov \n", + "5 40.0 128.0 Brad Oleson \n", + "6 33.0 140.0 Stratos Perperoglou \n", + "7 34.0 67.0 Alex Renfroe \n", + "8 23.0 117.0 Justin Doellman \n", + "9 41.0 93.0 Joey Dorsey \n", + "10 20.0 91.0 Juan Carlos Navarro \n", + "11 26.0 44.0 Marcus Eriksson \n", + "12 17.0 69.0 Vitor Faverani \n", + "13 19.0 36.0 Jonathan Holmes \n", + "14 18.0 21.0 Moussa Diagne \n", + "15 10.0 11.0 Stefan Peno \n", + "16 2.0 5.0 Xavier Munford \n", + "17 2.0 9.0 Pau Ribas \n", + "18 0.0 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", + "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", + "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", + "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", + "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", + "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", + "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", + "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", + "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", + "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", + "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", + "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", + "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", + "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", + "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", + "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", + "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", + "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", + "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", + "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", + "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", + "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", + "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", + "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", + "1 16.0 43.0 73.0 405.0 Ante Tomic \n", + "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", + "3 4.0 31.0 47.0 202.0 Brad Oleson \n", + "4 16.0 41.0 66.0 146.0 Victor Claver \n", + "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", + "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", + "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", + "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", + "9 2.0 19.0 21.0 151.0 Justin Doellman \n", + "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", + "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", + "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", + "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", + "14 0.0 11.0 18.0 13.0 Stefan Peno \n", + "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", + "16 2.0 7.0 9.0 12.0 Xavier Munford \n", + "17 0.0 2.0 1.0 11.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'E'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", + "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", + "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", + "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", + "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", + "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", + "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk tov \\\n", + "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", + "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", + "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", + "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", + "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", + "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", + "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", + "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", + "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", + "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", + "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", + "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", + "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", + "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", + "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", + "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", + "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", + "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", + "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf pts player_name \n", + "0 63.0 389.0 Tyrese Rice \n", + "1 62.0 256.0 Ante Tomic \n", + "2 52.0 274.0 Petteri Koponen \n", + "3 45.0 163.0 Victor Claver \n", + "4 46.0 226.0 Aleksandar Vezenkov \n", + "5 40.0 128.0 Brad Oleson \n", + "6 33.0 140.0 Stratos Perperoglou \n", + "7 34.0 67.0 Alex Renfroe \n", + "8 23.0 117.0 Justin Doellman \n", + "9 41.0 93.0 Joey Dorsey \n", + "10 20.0 91.0 Juan Carlos Navarro \n", + "11 26.0 44.0 Marcus Eriksson \n", + "12 17.0 69.0 Vitor Faverani \n", + "13 19.0 36.0 Jonathan Holmes \n", + "14 18.0 21.0 Moussa Diagne \n", + "15 10.0 11.0 Stefan Peno \n", + "16 2.0 5.0 Xavier Munford \n", + "17 2.0 9.0 Pau Ribas \n", + "18 0.0 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_totals(2017, level='E')" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-130.0NaN889.0137.0364.00.37655.0172.00.320...8.041.049.0146.034.03.077.063.0389.0Tyrese Rice
1ante-tomic-129.0NaN633.0105.0200.00.5250.01.00.000...63.0108.0171.058.017.020.056.062.0256.0Ante Tomic
2petteri-koponen-127.0NaN610.088.0205.00.42955.0119.00.462...5.041.046.051.020.00.036.052.0274.0Petteri Koponen
3victor-claver-127.0NaN594.056.0122.00.45923.061.00.377...23.095.0118.034.025.08.033.045.0163.0Victor Claver
4aleksandar-vezenkov-130.0NaN552.082.0142.00.57734.071.00.479...25.072.097.034.020.06.019.046.0226.0Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", + "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", + "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk tov \\\n", + "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", + "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", + "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", + "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", + "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", + "\n", + " pf pts player_name \n", + "0 63.0 389.0 Tyrese Rice \n", + "1 62.0 256.0 Ante Tomic \n", + "2 52.0 274.0 Petteri Koponen \n", + "3 45.0 163.0 Victor Claver \n", + "4 46.0 226.0 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", + "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", + "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", + "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", + "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", + "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", + "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", + "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", + "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", + "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", + "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", + "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", + "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", + "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", + "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", + "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", + "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", + "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", + "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", + "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", + "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", + "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", + "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", + "1 36.0 99.0 135.0 661.0 Ante Tomic \n", + "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", + "3 24.0 74.0 111.0 309.0 Victor Claver \n", + "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "5 9.0 51.0 87.0 330.0 Brad Oleson \n", + "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", + "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", + "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", + "9 4.0 33.0 44.0 268.0 Justin Doellman \n", + "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", + "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", + "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", + "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", + "14 1.0 17.0 28.0 24.0 Stefan Peno \n", + "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", + "16 2.0 16.0 11.0 17.0 Xavier Munford \n", + "17 0.0 3.0 3.0 20.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", + "20 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", + "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", + "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", + "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", + "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", + "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", + "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk tov \\\n", + "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", + "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", + "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", + "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", + "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", + "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", + "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", + "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", + "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", + "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", + "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", + "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", + "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", + "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", + "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", + "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", + "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", + "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", + "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf pts player_name \n", + "0 63.0 389.0 Tyrese Rice \n", + "1 62.0 256.0 Ante Tomic \n", + "2 52.0 274.0 Petteri Koponen \n", + "3 45.0 163.0 Victor Claver \n", + "4 46.0 226.0 Aleksandar Vezenkov \n", + "5 40.0 128.0 Brad Oleson \n", + "6 33.0 140.0 Stratos Perperoglou \n", + "7 34.0 67.0 Alex Renfroe \n", + "8 23.0 117.0 Justin Doellman \n", + "9 41.0 93.0 Joey Dorsey \n", + "10 20.0 91.0 Juan Carlos Navarro \n", + "11 26.0 44.0 Marcus Eriksson \n", + "12 17.0 69.0 Vitor Faverani \n", + "13 19.0 36.0 Jonathan Holmes \n", + "14 18.0 21.0 Moussa Diagne \n", + "15 10.0 11.0 Stefan Peno \n", + "16 2.0 5.0 Xavier Munford \n", + "17 2.0 9.0 Pau Ribas \n", + "18 0.0 2.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", + "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", + "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", + "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", + "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", + "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", + "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", + "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", + "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", + "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", + "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", + "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", + "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", + "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", + "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", + "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", + "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", + "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", + "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", + "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", + "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", + "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", + "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", + "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", + "1 16.0 43.0 73.0 405.0 Ante Tomic \n", + "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", + "3 4.0 31.0 47.0 202.0 Brad Oleson \n", + "4 16.0 41.0 66.0 146.0 Victor Claver \n", + "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", + "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", + "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", + "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", + "9 2.0 19.0 21.0 151.0 Justin Doellman \n", + "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", + "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", + "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", + "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", + "14 0.0 11.0 18.0 13.0 Stefan Peno \n", + "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", + "16 2.0 7.0 9.0 12.0 Xavier Munford \n", + "17 0.0 2.0 1.0 11.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'C'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", + "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", + "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", + "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", + "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", + "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", + "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", + "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl \\\n", + "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", + "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", + "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", + "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", + "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", + "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", + "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", + "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", + "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", + "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", + "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", + "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", + "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", + "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", + "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", + "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", + "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", + "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", + "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", + "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", + "1 16.0 43.0 73.0 405.0 Ante Tomic \n", + "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", + "3 4.0 31.0 47.0 202.0 Brad Oleson \n", + "4 16.0 41.0 66.0 146.0 Victor Claver \n", + "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", + "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", + "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", + "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", + "9 2.0 19.0 21.0 151.0 Justin Doellman \n", + "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", + "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", + "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", + "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", + "14 0.0 11.0 18.0 13.0 Stefan Peno \n", + "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", + "16 2.0 7.0 9.0 12.0 Xavier Munford \n", + "17 0.0 2.0 1.0 11.0 Pau Ribas \n", + "18 0.0 3.0 1.0 0.0 Pol Figueras \n", + "19 0.0 0.0 0.0 1.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_totals(2017, level='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-131.030.0791.0119.0293.00.40643.0147.00.293...7.039.046.0106.024.01.074.079.0361.0Tyrese Rice
1ante-tomic-132.027.0734.0157.0244.00.6431.02.00.500...65.0187.0252.066.018.016.043.073.0405.0Ante Tomic
2aleksandar-vezenkov-132.06.0604.0105.0196.00.53637.098.00.378...30.071.0101.027.017.09.026.069.0287.0Aleksandar Vezenkov
3brad-oleson-129.020.0603.070.0128.00.54734.075.00.453...17.036.053.049.018.04.031.047.0202.0Brad Oleson
4victor-claver-129.023.0593.056.0116.00.48326.063.00.413...23.097.0120.035.026.016.041.066.0146.0Victor Claver
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg fga fg_pct fg3 \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", + "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", + "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", + "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", + "\n", + " fg3a fg3_pct ... orb drb trb ast stl blk \\\n", + "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 1.0 \n", + "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 16.0 \n", + "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 9.0 \n", + "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 4.0 \n", + "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 16.0 \n", + "\n", + " tov pf pts player_name \n", + "0 74.0 79.0 361.0 Tyrese Rice \n", + "1 43.0 73.0 405.0 Ante Tomic \n", + "2 26.0 69.0 287.0 Aleksandar Vezenkov \n", + "3 31.0 47.0 202.0 Brad Oleson \n", + "4 41.0 66.0 146.0 Victor Claver \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## per36 table" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", + "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", + "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", + "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", + "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "5 1.7 4.3 0.406 ... 0.9 \n", + "6 1.5 5.0 0.309 ... 0.6 \n", + "7 2.9 6.9 0.422 ... 0.9 \n", + "8 1.3 3.3 0.403 ... 1.1 \n", + "9 1.8 3.5 0.527 ... 1.1 \n", + "10 0.0 0.0 NaN ... 4.5 \n", + "11 2.5 8.0 0.308 ... 0.2 \n", + "12 0.3 1.5 0.200 ... 2.5 \n", + "13 0.0 0.0 NaN ... 5.4 \n", + "14 0.5 3.8 0.133 ... 1.0 \n", + "15 2.3 5.0 0.450 ... 2.0 \n", + "16 1.4 4.2 0.333 ... 0.9 \n", + "17 4.2 10.0 0.417 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 12.0 0.000 ... 0.0 \n", + "20 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", + "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", + "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", + "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", + "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", + "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", + "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", + "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", + "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", + "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", + "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", + "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", + "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "5 2.8 10.6 Brad Oleson \n", + "6 3.4 12.5 Stratos Perperoglou \n", + "7 3.9 13.1 Marcus Eriksson \n", + "8 4.0 9.4 Alex Renfroe \n", + "9 2.8 16.9 Justin Doellman \n", + "10 5.9 9.8 Joey Dorsey \n", + "11 3.0 16.0 Juan Carlos Navarro \n", + "12 4.8 18.6 Vitor Faverani \n", + "13 6.6 11.1 Moussa Diagne \n", + "14 7.0 6.0 Stefan Peno \n", + "15 7.6 14.9 Jonathan Holmes \n", + "16 5.1 7.9 Xavier Munford \n", + "17 2.5 16.7 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 24.0 Rodions Kurucs \n", + "20 0.0 12.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", + "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", + "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", + "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", + "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", + "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", + "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.2 7.0 0.320 ... 0.3 \n", + "1 0.0 0.1 0.000 ... 3.6 \n", + "2 3.2 7.0 0.462 ... 0.3 \n", + "3 1.4 3.7 0.377 ... 1.4 \n", + "4 2.2 4.6 0.479 ... 1.6 \n", + "5 1.4 4.0 0.345 ... 0.8 \n", + "6 1.5 4.1 0.358 ... 0.6 \n", + "7 1.4 3.7 0.387 ... 1.2 \n", + "8 1.8 3.4 0.536 ... 1.2 \n", + "9 0.0 0.0 NaN ... 5.7 \n", + "10 2.3 8.2 0.286 ... 0.1 \n", + "11 2.0 5.6 0.353 ... 1.2 \n", + "12 0.3 1.8 0.143 ... 2.1 \n", + "13 1.6 4.9 0.333 ... 3.2 \n", + "14 0.0 0.0 NaN ... 3.6 \n", + "15 0.7 2.3 0.333 ... 1.5 \n", + "16 1.1 3.2 0.333 ... 2.1 \n", + "17 5.4 10.8 0.500 ... 0.0 \n", + "18 0.0 12.0 0.000 ... 0.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", + "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", + "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", + "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", + "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", + "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", + "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", + "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", + "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", + "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", + "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", + "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", + "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", + "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", + "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", + "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", + "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 2.6 15.8 Tyrese Rice \n", + "1 3.5 14.6 Ante Tomic \n", + "2 3.1 16.2 Petteri Koponen \n", + "3 2.7 9.9 Victor Claver \n", + "4 3.0 14.7 Aleksandar Vezenkov \n", + "5 2.8 8.9 Brad Oleson \n", + "6 2.6 11.0 Stratos Perperoglou \n", + "7 4.1 8.0 Alex Renfroe \n", + "8 2.8 14.1 Justin Doellman \n", + "9 5.1 11.5 Joey Dorsey \n", + "10 2.9 13.3 Juan Carlos Navarro \n", + "11 4.3 7.3 Marcus Eriksson \n", + "12 4.4 17.9 Vitor Faverani \n", + "13 7.7 14.6 Jonathan Holmes \n", + "14 8.2 9.6 Moussa Diagne \n", + "15 7.5 8.2 Stefan Peno \n", + "16 2.1 5.3 Xavier Munford \n", + "17 3.6 16.2 Pau Ribas \n", + "18 0.0 24.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", + "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", + "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", + "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", + "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", + "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.0 6.7 0.293 ... 0.3 \n", + "1 0.0 0.1 0.500 ... 3.2 \n", + "2 2.2 5.8 0.378 ... 1.8 \n", + "3 2.0 4.5 0.453 ... 1.0 \n", + "4 1.6 3.8 0.413 ... 1.4 \n", + "5 1.8 5.2 0.353 ... 0.6 \n", + "6 1.6 5.6 0.277 ... 0.6 \n", + "7 3.3 7.5 0.447 ... 0.7 \n", + "8 1.3 3.0 0.419 ... 1.1 \n", + "9 1.8 3.6 0.519 ... 1.1 \n", + "10 0.0 0.0 NaN ... 3.3 \n", + "11 2.6 7.8 0.333 ... 0.3 \n", + "12 0.0 0.0 NaN ... 6.5 \n", + "13 0.4 1.1 0.333 ... 3.2 \n", + "14 0.4 4.5 0.083 ... 0.8 \n", + "15 3.3 5.3 0.625 ... 0.0 \n", + "16 1.7 5.0 0.333 ... 0.0 \n", + "17 3.1 9.4 0.333 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", + "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", + "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", + "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", + "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", + "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", + "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", + "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", + "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", + "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", + "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", + "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", + "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", + "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", + "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", + "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", + "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", + "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.6 16.4 Tyrese Rice \n", + "1 3.6 19.9 Ante Tomic \n", + "2 4.1 17.1 Aleksandar Vezenkov \n", + "3 2.8 12.1 Brad Oleson \n", + "4 4.0 8.9 Victor Claver \n", + "5 2.9 14.4 Petteri Koponen \n", + "6 4.1 13.8 Stratos Perperoglou \n", + "7 3.7 15.9 Marcus Eriksson \n", + "8 4.0 10.6 Alex Renfroe \n", + "9 2.8 19.9 Justin Doellman \n", + "10 6.8 8.0 Joey Dorsey \n", + "11 3.1 19.0 Juan Carlos Navarro \n", + "12 5.6 12.1 Moussa Diagne \n", + "13 5.3 19.6 Vitor Faverani \n", + "14 6.8 4.9 Stefan Peno \n", + "15 7.3 15.3 Jonathan Holmes \n", + "16 7.5 10.0 Xavier Munford \n", + "17 1.6 17.2 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 12.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'B'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", + "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", + "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", + "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", + "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "5 1.7 4.3 0.406 ... 0.9 \n", + "6 1.5 5.0 0.309 ... 0.6 \n", + "7 2.9 6.9 0.422 ... 0.9 \n", + "8 1.3 3.3 0.403 ... 1.1 \n", + "9 1.8 3.5 0.527 ... 1.1 \n", + "10 0.0 0.0 NaN ... 4.5 \n", + "11 2.5 8.0 0.308 ... 0.2 \n", + "12 0.3 1.5 0.200 ... 2.5 \n", + "13 0.0 0.0 NaN ... 5.4 \n", + "14 0.5 3.8 0.133 ... 1.0 \n", + "15 2.3 5.0 0.450 ... 2.0 \n", + "16 1.4 4.2 0.333 ... 0.9 \n", + "17 4.2 10.0 0.417 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 12.0 0.000 ... 0.0 \n", + "20 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", + "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", + "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", + "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", + "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", + "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", + "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", + "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", + "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", + "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", + "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", + "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", + "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "5 2.8 10.6 Brad Oleson \n", + "6 3.4 12.5 Stratos Perperoglou \n", + "7 3.9 13.1 Marcus Eriksson \n", + "8 4.0 9.4 Alex Renfroe \n", + "9 2.8 16.9 Justin Doellman \n", + "10 5.9 9.8 Joey Dorsey \n", + "11 3.0 16.0 Juan Carlos Navarro \n", + "12 4.8 18.6 Vitor Faverani \n", + "13 6.6 11.1 Moussa Diagne \n", + "14 7.0 6.0 Stefan Peno \n", + "15 7.6 14.9 Jonathan Holmes \n", + "16 5.1 7.9 Xavier Munford \n", + "17 2.5 16.7 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 24.0 Rodions Kurucs \n", + "20 0.0 12.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per36(2017, level='B')" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-161.0NaN1680.05.514.10.3902.16.80.307...0.31.72.05.41.20.13.23.016.1Tyrese Rice
1ante-tomic-161.0NaN1367.06.911.70.5900.00.10.333...3.47.811.13.30.90.92.63.617.4Ante Tomic
2petteri-koponen-154.0NaN1196.05.111.70.4362.66.10.417...0.52.73.23.41.20.12.13.015.3Petteri Koponen
3victor-claver-156.0NaN1187.03.47.20.4711.53.80.395...1.45.87.22.11.50.72.23.49.4Victor Claver
4aleksandar-vezenkov-162.0NaN1156.05.810.50.5532.25.30.420...1.74.56.21.91.20.51.43.616.0Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", + "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", + "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", + "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", + "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "5 1.7 4.3 0.406 ... 0.9 \n", + "6 1.5 5.0 0.309 ... 0.6 \n", + "7 2.9 6.9 0.422 ... 0.9 \n", + "8 1.3 3.3 0.403 ... 1.1 \n", + "9 1.8 3.5 0.527 ... 1.1 \n", + "10 0.0 0.0 NaN ... 4.5 \n", + "11 2.5 8.0 0.308 ... 0.2 \n", + "12 0.3 1.5 0.200 ... 2.5 \n", + "13 0.0 0.0 NaN ... 5.4 \n", + "14 0.5 3.8 0.133 ... 1.0 \n", + "15 2.3 5.0 0.450 ... 2.0 \n", + "16 1.4 4.2 0.333 ... 0.9 \n", + "17 4.2 10.0 0.417 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 12.0 0.000 ... 0.0 \n", + "20 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", + "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", + "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", + "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", + "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", + "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", + "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", + "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", + "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", + "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", + "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", + "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", + "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "5 2.8 10.6 Brad Oleson \n", + "6 3.4 12.5 Stratos Perperoglou \n", + "7 3.9 13.1 Marcus Eriksson \n", + "8 4.0 9.4 Alex Renfroe \n", + "9 2.8 16.9 Justin Doellman \n", + "10 5.9 9.8 Joey Dorsey \n", + "11 3.0 16.0 Juan Carlos Navarro \n", + "12 4.8 18.6 Vitor Faverani \n", + "13 6.6 11.1 Moussa Diagne \n", + "14 7.0 6.0 Stefan Peno \n", + "15 7.6 14.9 Jonathan Holmes \n", + "16 5.1 7.9 Xavier Munford \n", + "17 2.5 16.7 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 24.0 Rodions Kurucs \n", + "20 0.0 12.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", + "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", + "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", + "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", + "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", + "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", + "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.2 7.0 0.320 ... 0.3 \n", + "1 0.0 0.1 0.000 ... 3.6 \n", + "2 3.2 7.0 0.462 ... 0.3 \n", + "3 1.4 3.7 0.377 ... 1.4 \n", + "4 2.2 4.6 0.479 ... 1.6 \n", + "5 1.4 4.0 0.345 ... 0.8 \n", + "6 1.5 4.1 0.358 ... 0.6 \n", + "7 1.4 3.7 0.387 ... 1.2 \n", + "8 1.8 3.4 0.536 ... 1.2 \n", + "9 0.0 0.0 NaN ... 5.7 \n", + "10 2.3 8.2 0.286 ... 0.1 \n", + "11 2.0 5.6 0.353 ... 1.2 \n", + "12 0.3 1.8 0.143 ... 2.1 \n", + "13 1.6 4.9 0.333 ... 3.2 \n", + "14 0.0 0.0 NaN ... 3.6 \n", + "15 0.7 2.3 0.333 ... 1.5 \n", + "16 1.1 3.2 0.333 ... 2.1 \n", + "17 5.4 10.8 0.500 ... 0.0 \n", + "18 0.0 12.0 0.000 ... 0.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", + "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", + "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", + "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", + "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", + "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", + "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", + "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", + "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", + "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", + "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", + "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", + "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", + "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", + "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", + "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", + "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 2.6 15.8 Tyrese Rice \n", + "1 3.5 14.6 Ante Tomic \n", + "2 3.1 16.2 Petteri Koponen \n", + "3 2.7 9.9 Victor Claver \n", + "4 3.0 14.7 Aleksandar Vezenkov \n", + "5 2.8 8.9 Brad Oleson \n", + "6 2.6 11.0 Stratos Perperoglou \n", + "7 4.1 8.0 Alex Renfroe \n", + "8 2.8 14.1 Justin Doellman \n", + "9 5.1 11.5 Joey Dorsey \n", + "10 2.9 13.3 Juan Carlos Navarro \n", + "11 4.3 7.3 Marcus Eriksson \n", + "12 4.4 17.9 Vitor Faverani \n", + "13 7.7 14.6 Jonathan Holmes \n", + "14 8.2 9.6 Moussa Diagne \n", + "15 7.5 8.2 Stefan Peno \n", + "16 2.1 5.3 Xavier Munford \n", + "17 3.6 16.2 Pau Ribas \n", + "18 0.0 24.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", + "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", + "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", + "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", + "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", + "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.0 6.7 0.293 ... 0.3 \n", + "1 0.0 0.1 0.500 ... 3.2 \n", + "2 2.2 5.8 0.378 ... 1.8 \n", + "3 2.0 4.5 0.453 ... 1.0 \n", + "4 1.6 3.8 0.413 ... 1.4 \n", + "5 1.8 5.2 0.353 ... 0.6 \n", + "6 1.6 5.6 0.277 ... 0.6 \n", + "7 3.3 7.5 0.447 ... 0.7 \n", + "8 1.3 3.0 0.419 ... 1.1 \n", + "9 1.8 3.6 0.519 ... 1.1 \n", + "10 0.0 0.0 NaN ... 3.3 \n", + "11 2.6 7.8 0.333 ... 0.3 \n", + "12 0.0 0.0 NaN ... 6.5 \n", + "13 0.4 1.1 0.333 ... 3.2 \n", + "14 0.4 4.5 0.083 ... 0.8 \n", + "15 3.3 5.3 0.625 ... 0.0 \n", + "16 1.7 5.0 0.333 ... 0.0 \n", + "17 3.1 9.4 0.333 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", + "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", + "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", + "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", + "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", + "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", + "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", + "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", + "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", + "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", + "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", + "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", + "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", + "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", + "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", + "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", + "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", + "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.6 16.4 Tyrese Rice \n", + "1 3.6 19.9 Ante Tomic \n", + "2 4.1 17.1 Aleksandar Vezenkov \n", + "3 2.8 12.1 Brad Oleson \n", + "4 4.0 8.9 Victor Claver \n", + "5 2.9 14.4 Petteri Koponen \n", + "6 4.1 13.8 Stratos Perperoglou \n", + "7 3.7 15.9 Marcus Eriksson \n", + "8 4.0 10.6 Alex Renfroe \n", + "9 2.8 19.9 Justin Doellman \n", + "10 6.8 8.0 Joey Dorsey \n", + "11 3.1 19.0 Juan Carlos Navarro \n", + "12 5.6 12.1 Moussa Diagne \n", + "13 5.3 19.6 Vitor Faverani \n", + "14 6.8 4.9 Stefan Peno \n", + "15 7.3 15.3 Jonathan Holmes \n", + "16 7.5 10.0 Xavier Munford \n", + "17 1.6 17.2 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 12.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'E'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", + "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", + "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", + "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", + "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", + "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", + "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.2 7.0 0.320 ... 0.3 \n", + "1 0.0 0.1 0.000 ... 3.6 \n", + "2 3.2 7.0 0.462 ... 0.3 \n", + "3 1.4 3.7 0.377 ... 1.4 \n", + "4 2.2 4.6 0.479 ... 1.6 \n", + "5 1.4 4.0 0.345 ... 0.8 \n", + "6 1.5 4.1 0.358 ... 0.6 \n", + "7 1.4 3.7 0.387 ... 1.2 \n", + "8 1.8 3.4 0.536 ... 1.2 \n", + "9 0.0 0.0 NaN ... 5.7 \n", + "10 2.3 8.2 0.286 ... 0.1 \n", + "11 2.0 5.6 0.353 ... 1.2 \n", + "12 0.3 1.8 0.143 ... 2.1 \n", + "13 1.6 4.9 0.333 ... 3.2 \n", + "14 0.0 0.0 NaN ... 3.6 \n", + "15 0.7 2.3 0.333 ... 1.5 \n", + "16 1.1 3.2 0.333 ... 2.1 \n", + "17 5.4 10.8 0.500 ... 0.0 \n", + "18 0.0 12.0 0.000 ... 0.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", + "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", + "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", + "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", + "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", + "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", + "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", + "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", + "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", + "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", + "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", + "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", + "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", + "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", + "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", + "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", + "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 2.6 15.8 Tyrese Rice \n", + "1 3.5 14.6 Ante Tomic \n", + "2 3.1 16.2 Petteri Koponen \n", + "3 2.7 9.9 Victor Claver \n", + "4 3.0 14.7 Aleksandar Vezenkov \n", + "5 2.8 8.9 Brad Oleson \n", + "6 2.6 11.0 Stratos Perperoglou \n", + "7 4.1 8.0 Alex Renfroe \n", + "8 2.8 14.1 Justin Doellman \n", + "9 5.1 11.5 Joey Dorsey \n", + "10 2.9 13.3 Juan Carlos Navarro \n", + "11 4.3 7.3 Marcus Eriksson \n", + "12 4.4 17.9 Vitor Faverani \n", + "13 7.7 14.6 Jonathan Holmes \n", + "14 8.2 9.6 Moussa Diagne \n", + "15 7.5 8.2 Stefan Peno \n", + "16 2.1 5.3 Xavier Munford \n", + "17 3.6 16.2 Pau Ribas \n", + "18 0.0 24.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per36(2017, level='E')" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-130.0NaN889.05.514.70.3762.27.00.320...0.31.72.05.91.40.13.12.615.8Tyrese Rice
1ante-tomic-129.0NaN633.06.011.40.5250.00.10.000...3.66.19.73.31.01.13.23.514.6Ante Tomic
2petteri-koponen-127.0NaN610.05.212.10.4293.27.00.462...0.32.42.73.01.20.02.13.116.2Petteri Koponen
3victor-claver-127.0NaN594.03.47.40.4591.43.70.377...1.45.87.22.11.50.52.02.79.9Victor Claver
4aleksandar-vezenkov-130.0NaN552.05.39.30.5772.24.60.479...1.64.76.32.21.30.41.23.014.7Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", + "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", + "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.2 7.0 0.320 ... 0.3 \n", + "1 0.0 0.1 0.000 ... 3.6 \n", + "2 3.2 7.0 0.462 ... 0.3 \n", + "3 1.4 3.7 0.377 ... 1.4 \n", + "4 2.2 4.6 0.479 ... 1.6 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", + "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", + "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", + "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 2.6 15.8 Tyrese Rice \n", + "1 3.5 14.6 Ante Tomic \n", + "2 3.1 16.2 Petteri Koponen \n", + "3 2.7 9.9 Victor Claver \n", + "4 3.0 14.7 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", + "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", + "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", + "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", + "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", + "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", + "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", + "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", + "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", + "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", + "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", + "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", + "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", + "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", + "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "5 1.7 4.3 0.406 ... 0.9 \n", + "6 1.5 5.0 0.309 ... 0.6 \n", + "7 2.9 6.9 0.422 ... 0.9 \n", + "8 1.3 3.3 0.403 ... 1.1 \n", + "9 1.8 3.5 0.527 ... 1.1 \n", + "10 0.0 0.0 NaN ... 4.5 \n", + "11 2.5 8.0 0.308 ... 0.2 \n", + "12 0.3 1.5 0.200 ... 2.5 \n", + "13 0.0 0.0 NaN ... 5.4 \n", + "14 0.5 3.8 0.133 ... 1.0 \n", + "15 2.3 5.0 0.450 ... 2.0 \n", + "16 1.4 4.2 0.333 ... 0.9 \n", + "17 4.2 10.0 0.417 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 12.0 0.000 ... 0.0 \n", + "20 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", + "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", + "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", + "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", + "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", + "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", + "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", + "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", + "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", + "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", + "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", + "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", + "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "5 2.8 10.6 Brad Oleson \n", + "6 3.4 12.5 Stratos Perperoglou \n", + "7 3.9 13.1 Marcus Eriksson \n", + "8 4.0 9.4 Alex Renfroe \n", + "9 2.8 16.9 Justin Doellman \n", + "10 5.9 9.8 Joey Dorsey \n", + "11 3.0 16.0 Juan Carlos Navarro \n", + "12 4.8 18.6 Vitor Faverani \n", + "13 6.6 11.1 Moussa Diagne \n", + "14 7.0 6.0 Stefan Peno \n", + "15 7.6 14.9 Jonathan Holmes \n", + "16 5.1 7.9 Xavier Munford \n", + "17 2.5 16.7 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 24.0 Rodions Kurucs \n", + "20 0.0 12.0 Wesley Sena \n", + "\n", + "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", + "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", + "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", + "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", + "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", + "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", + "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", + "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", + "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", + "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", + "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", + "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", + "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", + "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", + "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", + "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", + "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", + "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", + "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.2 7.0 0.320 ... 0.3 \n", + "1 0.0 0.1 0.000 ... 3.6 \n", + "2 3.2 7.0 0.462 ... 0.3 \n", + "3 1.4 3.7 0.377 ... 1.4 \n", + "4 2.2 4.6 0.479 ... 1.6 \n", + "5 1.4 4.0 0.345 ... 0.8 \n", + "6 1.5 4.1 0.358 ... 0.6 \n", + "7 1.4 3.7 0.387 ... 1.2 \n", + "8 1.8 3.4 0.536 ... 1.2 \n", + "9 0.0 0.0 NaN ... 5.7 \n", + "10 2.3 8.2 0.286 ... 0.1 \n", + "11 2.0 5.6 0.353 ... 1.2 \n", + "12 0.3 1.8 0.143 ... 2.1 \n", + "13 1.6 4.9 0.333 ... 3.2 \n", + "14 0.0 0.0 NaN ... 3.6 \n", + "15 0.7 2.3 0.333 ... 1.5 \n", + "16 1.1 3.2 0.333 ... 2.1 \n", + "17 5.4 10.8 0.500 ... 0.0 \n", + "18 0.0 12.0 0.000 ... 0.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", + "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", + "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", + "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", + "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", + "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", + "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", + "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", + "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", + "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", + "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", + "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", + "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", + "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", + "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", + "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", + "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", + "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 2.6 15.8 Tyrese Rice \n", + "1 3.5 14.6 Ante Tomic \n", + "2 3.1 16.2 Petteri Koponen \n", + "3 2.7 9.9 Victor Claver \n", + "4 3.0 14.7 Aleksandar Vezenkov \n", + "5 2.8 8.9 Brad Oleson \n", + "6 2.6 11.0 Stratos Perperoglou \n", + "7 4.1 8.0 Alex Renfroe \n", + "8 2.8 14.1 Justin Doellman \n", + "9 5.1 11.5 Joey Dorsey \n", + "10 2.9 13.3 Juan Carlos Navarro \n", + "11 4.3 7.3 Marcus Eriksson \n", + "12 4.4 17.9 Vitor Faverani \n", + "13 7.7 14.6 Jonathan Holmes \n", + "14 8.2 9.6 Moussa Diagne \n", + "15 7.5 8.2 Stefan Peno \n", + "16 2.1 5.3 Xavier Munford \n", + "17 3.6 16.2 Pau Ribas \n", + "18 0.0 24.0 Rodions Kurucs \n", + "\n", + "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", + "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", + "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", + "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", + "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", + "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.0 6.7 0.293 ... 0.3 \n", + "1 0.0 0.1 0.500 ... 3.2 \n", + "2 2.2 5.8 0.378 ... 1.8 \n", + "3 2.0 4.5 0.453 ... 1.0 \n", + "4 1.6 3.8 0.413 ... 1.4 \n", + "5 1.8 5.2 0.353 ... 0.6 \n", + "6 1.6 5.6 0.277 ... 0.6 \n", + "7 3.3 7.5 0.447 ... 0.7 \n", + "8 1.3 3.0 0.419 ... 1.1 \n", + "9 1.8 3.6 0.519 ... 1.1 \n", + "10 0.0 0.0 NaN ... 3.3 \n", + "11 2.6 7.8 0.333 ... 0.3 \n", + "12 0.0 0.0 NaN ... 6.5 \n", + "13 0.4 1.1 0.333 ... 3.2 \n", + "14 0.4 4.5 0.083 ... 0.8 \n", + "15 3.3 5.3 0.625 ... 0.0 \n", + "16 1.7 5.0 0.333 ... 0.0 \n", + "17 3.1 9.4 0.333 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", + "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", + "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", + "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", + "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", + "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", + "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", + "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", + "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", + "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", + "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", + "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", + "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", + "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", + "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", + "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", + "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", + "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.6 16.4 Tyrese Rice \n", + "1 3.6 19.9 Ante Tomic \n", + "2 4.1 17.1 Aleksandar Vezenkov \n", + "3 2.8 12.1 Brad Oleson \n", + "4 4.0 8.9 Victor Claver \n", + "5 2.9 14.4 Petteri Koponen \n", + "6 4.1 13.8 Stratos Perperoglou \n", + "7 3.7 15.9 Marcus Eriksson \n", + "8 4.0 10.6 Alex Renfroe \n", + "9 2.8 19.9 Justin Doellman \n", + "10 6.8 8.0 Joey Dorsey \n", + "11 3.1 19.0 Juan Carlos Navarro \n", + "12 5.6 12.1 Moussa Diagne \n", + "13 5.3 19.6 Vitor Faverani \n", + "14 6.8 4.9 Stefan Peno \n", + "15 7.3 15.3 Jonathan Holmes \n", + "16 7.5 10.0 Xavier Munford \n", + "17 1.6 17.2 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 12.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]}\n", + "KEY in wrapper\n", + "((, 2017, 'C'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", + "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", + "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", + "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", + "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", + "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", + "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", + "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", + "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", + "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", + "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", + "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", + "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", + "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", + "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", + "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", + "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", + "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", + "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.0 6.7 0.293 ... 0.3 \n", + "1 0.0 0.1 0.500 ... 3.2 \n", + "2 2.2 5.8 0.378 ... 1.8 \n", + "3 2.0 4.5 0.453 ... 1.0 \n", + "4 1.6 3.8 0.413 ... 1.4 \n", + "5 1.8 5.2 0.353 ... 0.6 \n", + "6 1.6 5.6 0.277 ... 0.6 \n", + "7 3.3 7.5 0.447 ... 0.7 \n", + "8 1.3 3.0 0.419 ... 1.1 \n", + "9 1.8 3.6 0.519 ... 1.1 \n", + "10 0.0 0.0 NaN ... 3.3 \n", + "11 2.6 7.8 0.333 ... 0.3 \n", + "12 0.0 0.0 NaN ... 6.5 \n", + "13 0.4 1.1 0.333 ... 3.2 \n", + "14 0.4 4.5 0.083 ... 0.8 \n", + "15 3.3 5.3 0.625 ... 0.0 \n", + "16 1.7 5.0 0.333 ... 0.0 \n", + "17 3.1 9.4 0.333 ... 0.0 \n", + "18 0.0 0.0 NaN ... 0.0 \n", + "19 0.0 0.0 NaN ... 12.0 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", + "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", + "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", + "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", + "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", + "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", + "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", + "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", + "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", + "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", + "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", + "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", + "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", + "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", + "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", + "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", + "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", + "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", + "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", + "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.6 16.4 Tyrese Rice \n", + "1 3.6 19.9 Ante Tomic \n", + "2 4.1 17.1 Aleksandar Vezenkov \n", + "3 2.8 12.1 Brad Oleson \n", + "4 4.0 8.9 Victor Claver \n", + "5 2.9 14.4 Petteri Koponen \n", + "6 4.1 13.8 Stratos Perperoglou \n", + "7 3.7 15.9 Marcus Eriksson \n", + "8 4.0 10.6 Alex Renfroe \n", + "9 2.8 19.9 Justin Doellman \n", + "10 6.8 8.0 Joey Dorsey \n", + "11 3.1 19.0 Juan Carlos Navarro \n", + "12 5.6 12.1 Moussa Diagne \n", + "13 5.3 19.6 Vitor Faverani \n", + "14 6.8 4.9 Stefan Peno \n", + "15 7.3 15.3 Jonathan Holmes \n", + "16 7.5 10.0 Xavier Munford \n", + "17 1.6 17.2 Pau Ribas \n", + "18 3.0 0.0 Pol Figueras \n", + "19 0.0 12.0 Wesley Sena \n", + "\n", + "[20 rows x 26 columns]\n" + ] + } + ], + "source": [ + "df = t.stats_per36(2017, level='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-131.030.0791.05.413.30.4062.06.70.293...0.31.82.14.81.10.03.43.616.4Tyrese Rice
1ante-tomic-132.027.0734.07.712.00.6430.00.10.500...3.29.212.43.20.90.82.13.619.9Ante Tomic
2aleksandar-vezenkov-132.06.0604.06.311.70.5362.25.80.378...1.84.26.01.61.00.51.54.117.1Aleksandar Vezenkov
3brad-oleson-129.020.0603.04.27.60.5472.04.50.453...1.02.13.22.91.10.21.92.812.1Brad Oleson
4victor-claver-129.023.0593.03.47.00.4831.63.80.413...1.45.97.32.11.61.02.54.08.9Victor Claver
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", + "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", + "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", + "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", + "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.0 6.7 0.293 ... 0.3 \n", + "1 0.0 0.1 0.500 ... 3.2 \n", + "2 2.2 5.8 0.378 ... 1.8 \n", + "3 2.0 4.5 0.453 ... 1.0 \n", + "4 1.6 3.8 0.413 ... 1.4 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", + "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", + "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", + "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", + "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.6 16.4 Tyrese Rice \n", + "1 3.6 19.9 Ante Tomic \n", + "2 4.1 17.1 Aleksandar Vezenkov \n", + "3 2.8 12.1 Brad Oleson \n", + "4 4.0 8.9 Victor Claver \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Advanced stats table" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", + "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", + "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", + "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", + "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", + "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", + "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", + "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", + "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", + "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", + "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", + "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", + "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", + "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", + "5 0.183 16.1 17.0 13.6 Brad Oleson \n", + "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", + "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", + "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", + "9 0.267 11.9 13.2 22.4 Justin Doellman \n", + "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", + "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", + "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", + "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", + "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", + "15 0.357 20.5 34.4 17.6 Stefan Peno \n", + "16 0.000 17.0 47.1 22.5 Xavier Munford \n", + "17 0.267 18.6 15.2 23.5 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", + "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", + "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", + "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", + "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", + "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", + "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", + "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", + "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", + "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", + "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", + "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", + "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", + "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", + "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", + "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", + "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", + "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", + "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", + "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", + "1 0.465 19.5 18.9 24.0 Ante Tomic \n", + "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", + "3 0.295 10.6 19.3 14.7 Victor Claver \n", + "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", + "5 0.098 16.8 15.8 12.4 Brad Oleson \n", + "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", + "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", + "8 0.202 12.1 12.0 19.9 Justin Doellman \n", + "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", + "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", + "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", + "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", + "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", + "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", + "15 0.500 18.1 38.1 16.8 Stefan Peno \n", + "16 0.000 10.2 50.0 27.0 Xavier Munford \n", + "17 0.000 10.3 12.5 20.4 Pau Ribas \n", + "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", + "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", + "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", + "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", + "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", + "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", + "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", + "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", + "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", + "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", + "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", + "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", + "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", + "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", + "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", + "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", + "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", + "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", + "1 0.574 21.3 12.3 24.3 Ante Tomic \n", + "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", + "3 0.250 15.6 17.9 14.7 Brad Oleson \n", + "4 0.121 10.9 25.1 14.1 Victor Claver \n", + "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", + "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", + "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", + "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", + "9 0.327 11.7 14.1 25.2 Justin Doellman \n", + "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", + "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", + "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", + "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", + "14 0.300 21.6 32.7 18.1 Stefan Peno \n", + "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", + "16 0.000 22.4 43.8 19.0 Xavier Munford \n", + "17 0.500 25.8 17.0 26.1 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", + "KEY in wrapper\n", + "((, 2017, 'B'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", + "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", + "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", + "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", + "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", + "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", + "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", + "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", + "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", + "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", + "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", + "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", + "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", + "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", + "5 0.183 16.1 17.0 13.6 Brad Oleson \n", + "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", + "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", + "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", + "9 0.267 11.9 13.2 22.4 Justin Doellman \n", + "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", + "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", + "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", + "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", + "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", + "15 0.357 20.5 34.4 17.6 Stefan Peno \n", + "16 0.000 17.0 47.1 22.5 Xavier Munford \n", + "17 0.267 18.6 15.2 23.5 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", + "20 2.000 0.0 0.0 32.0 Wesley Sena \n" + ] + } + ], + "source": [ + "df = t.stats_advanced(2017, level='B')" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-161.01680.00.511NaN0.4860.26531.017.126.9Tyrese Rice
1ante-tomic-161.01367.00.605NaN0.0070.52520.415.324.1Ante Tomic
2petteri-koponen-154.01196.00.593NaN0.5260.24218.914.221.4Petteri Koponen
3victor-claver-156.01187.00.594NaN0.5210.21010.722.214.4Victor Claver
4aleksandar-vezenkov-162.01156.00.686NaN0.5000.24011.110.718.5Aleksandar Vezenkov
\n", + "
" + ], + "text/plain": [ + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov " + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", + "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", + "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", + "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", + "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", + "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", + "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", + "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", + "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", + "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", + "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", + "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", + "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", + "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", + "5 0.183 16.1 17.0 13.6 Brad Oleson \n", + "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", + "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", + "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", + "9 0.267 11.9 13.2 22.4 Justin Doellman \n", + "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", + "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", + "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", + "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", + "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", + "15 0.357 20.5 34.4 17.6 Stefan Peno \n", + "16 0.000 17.0 47.1 22.5 Xavier Munford \n", + "17 0.267 18.6 15.2 23.5 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", + "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", + "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", + "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", + "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", + "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", + "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", + "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", + "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", + "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", + "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", + "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", + "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", + "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", + "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", + "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", + "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", + "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", + "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", + "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", + "1 0.465 19.5 18.9 24.0 Ante Tomic \n", + "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", + "3 0.295 10.6 19.3 14.7 Victor Claver \n", + "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", + "5 0.098 16.8 15.8 12.4 Brad Oleson \n", + "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", + "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", + "8 0.202 12.1 12.0 19.9 Justin Doellman \n", + "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", + "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", + "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", + "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", + "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", + "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", + "15 0.500 18.1 38.1 16.8 Stefan Peno \n", + "16 0.000 10.2 50.0 27.0 Xavier Munford \n", + "17 0.000 10.3 12.5 20.4 Pau Ribas \n", + "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", + "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", + "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", + "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", + "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", + "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", + "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", + "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", + "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", + "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", + "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", + "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", + "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", + "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", + "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", + "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", + "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", + "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", + "1 0.574 21.3 12.3 24.3 Ante Tomic \n", + "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", + "3 0.250 15.6 17.9 14.7 Brad Oleson \n", + "4 0.121 10.9 25.1 14.1 Victor Claver \n", + "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", + "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", + "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", + "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", + "9 0.327 11.7 14.1 25.2 Justin Doellman \n", + "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", + "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", + "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", + "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", + "14 0.300 21.6 32.7 18.1 Stefan Peno \n", + "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", + "16 0.000 22.4 43.8 19.0 Xavier Munford \n", + "17 0.500 25.8 17.0 26.1 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", + "KEY in wrapper\n", + "((, 2017, 'E'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", + "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", + "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", + "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", + "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", + "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", + "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", + "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", + "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", + "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", + "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", + "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", + "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", + "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", + "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", + "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", + "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", + "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", + "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", + "1 0.465 19.5 18.9 24.0 Ante Tomic \n", + "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", + "3 0.295 10.6 19.3 14.7 Victor Claver \n", + "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", + "5 0.098 16.8 15.8 12.4 Brad Oleson \n", + "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", + "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", + "8 0.202 12.1 12.0 19.9 Justin Doellman \n", + "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", + "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", + "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", + "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", + "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", + "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", + "15 0.500 18.1 38.1 16.8 Stefan Peno \n", + "16 0.000 10.2 50.0 27.0 Xavier Munford \n", + "17 0.000 10.3 12.5 20.4 Pau Ribas \n", + "18 0.000 0.0 0.0 34.0 Rodions Kurucs \n" + ] + } + ], + "source": [ + "df = t.stats_advanced(2017, level='E')" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-130.0889.00.4910.4520.4730.20134.016.327.2Tyrese Rice
1ante-tomic-129.0633.00.5310.5250.0050.46519.518.924.0Ante Tomic
2petteri-koponen-127.0610.00.6070.5630.5800.22917.013.821.9Petteri Koponen
3victor-claver-127.0594.00.5910.5530.5000.29510.619.314.7Victor Claver
4aleksandar-vezenkov-130.0552.00.7220.6970.5000.23212.610.816.2Aleksandar Vezenkov
\n", + "
" + ], + "text/plain": [ + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", + "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", + "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", + "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", + "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", + "1 0.465 19.5 18.9 24.0 Ante Tomic \n", + "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", + "3 0.295 10.6 19.3 14.7 Victor Claver \n", + "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov " + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CACHE BEFORE\n", + "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", + "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", + "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", + "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", + "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", + "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", + "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", + "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", + "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", + "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", + "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", + "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", + "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", + "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", + "5 0.183 16.1 17.0 13.6 Brad Oleson \n", + "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", + "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", + "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", + "9 0.267 11.9 13.2 22.4 Justin Doellman \n", + "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", + "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", + "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", + "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", + "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", + "15 0.357 20.5 34.4 17.6 Stefan Peno \n", + "16 0.000 17.0 47.1 22.5 Xavier Munford \n", + "17 0.267 18.6 15.2 23.5 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", + "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", + "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", + "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", + "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", + "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", + "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", + "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", + "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", + "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", + "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", + "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", + "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", + "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", + "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", + "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", + "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", + "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", + "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", + "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", + "1 0.465 19.5 18.9 24.0 Ante Tomic \n", + "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", + "3 0.295 10.6 19.3 14.7 Victor Claver \n", + "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", + "5 0.098 16.8 15.8 12.4 Brad Oleson \n", + "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", + "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", + "8 0.202 12.1 12.0 19.9 Justin Doellman \n", + "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", + "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", + "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", + "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", + "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", + "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", + "15 0.500 18.1 38.1 16.8 Stefan Peno \n", + "16 0.000 10.2 50.0 27.0 Xavier Munford \n", + "17 0.000 10.3 12.5 20.4 Pau Ribas \n", + "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", + "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", + "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", + "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", + "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", + "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", + "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", + "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", + "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", + "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", + "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", + "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", + "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", + "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", + "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", + "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", + "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", + "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", + "1 0.574 21.3 12.3 24.3 Ante Tomic \n", + "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", + "3 0.250 15.6 17.9 14.7 Brad Oleson \n", + "4 0.121 10.9 25.1 14.1 Victor Claver \n", + "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", + "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", + "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", + "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", + "9 0.327 11.7 14.1 25.2 Justin Doellman \n", + "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", + "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", + "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", + "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", + "14 0.300 21.6 32.7 18.1 Stefan Peno \n", + "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", + "16 0.000 22.4 43.8 19.0 Xavier Munford \n", + "17 0.500 25.8 17.0 26.1 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", + "KEY in wrapper\n", + "((, 2017, 'C'), frozenset())\n", + "COPY\n", + "RET worked\n", + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", + "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", + "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", + "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", + "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", + "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", + "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", + "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", + "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", + "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", + "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", + "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", + "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", + "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", + "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", + "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", + "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", + "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", + "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", + "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", + "1 0.574 21.3 12.3 24.3 Ante Tomic \n", + "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", + "3 0.250 15.6 17.9 14.7 Brad Oleson \n", + "4 0.121 10.9 25.1 14.1 Victor Claver \n", + "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", + "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", + "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", + "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", + "9 0.327 11.7 14.1 25.2 Justin Doellman \n", + "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", + "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", + "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", + "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", + "14 0.300 21.6 32.7 18.1 Stefan Peno \n", + "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", + "16 0.000 22.4 43.8 19.0 Xavier Munford \n", + "17 0.500 25.8 17.0 26.1 Pau Ribas \n", + "18 NaN 0.0 100.0 12.8 Pol Figueras \n", + "19 2.000 0.0 0.0 32.0 Wesley Sena \n" + ] + } + ], + "source": [ + "df = t.stats_advanced(2017, level='C')" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-131.0791.00.5350.4800.5020.34527.618.026.6Tyrese Rice
1ante-tomic-132.0734.00.6630.6450.0080.57421.312.324.3Ante Tomic
2aleksandar-vezenkov-132.0604.00.6610.6300.5000.2459.710.720.6Aleksandar Vezenkov
3brad-oleson-129.0603.00.7110.6800.5860.25015.617.914.7Brad Oleson
4victor-claver-129.0593.00.5980.5950.5430.12110.925.114.1Victor Claver
\n", + "
" + ], + "text/plain": [ + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", + "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", + "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", + "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", + "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", + "1 0.574 21.3 12.3 24.3 Ante Tomic \n", + "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", + "3 0.250 15.6 17.9 14.7 Brad Oleson \n", + "4 0.121 10.9 25.1 14.1 Victor Claver " + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 7b529759bfeaedaa9f44ca72baed422e60fd26ee Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 21:24:40 -0500 Subject: [PATCH 30/57] Update README.md todo --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a1a07a8..49d090e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# sportsref -Scraping sports data from sports-reference.com and related sites +# Todo: + +### Figure out why teams/all_teams_opp_stats table isn't parsing +### comment teams -> merge to master + +### euro/seasons + -NOTE: Very much still a WIP. Feel free to use, just bear in mind that the API -is subject to change. Documentation is on the to-do list, once the API is a bit -more rigid. From 724f07d9c4b1455db4f0659459f99ab9ba6c62d2 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Thu, 1 Feb 2018 21:24:55 -0500 Subject: [PATCH 31/57] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49d090e..1def3ae 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Todo: +# Develop Todo: ### Figure out why teams/all_teams_opp_stats table isn't parsing ### comment teams -> merge to master From 37e95d53e2e974988fbc28c3dc3279ec29e41ef1 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Fri, 2 Feb 2018 19:46:56 -0500 Subject: [PATCH 32/57] team_and_opp edge case fix in parse_table --- sportsref/decorators.py | 2 +- sportsref/euro/teams.py | 1 + sportsref/utils.py | 11 +++++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sportsref/decorators.py b/sportsref/decorators.py index d709212..8e7cb86 100644 --- a/sportsref/decorators.py +++ b/sportsref/decorators.py @@ -198,7 +198,7 @@ def _copy(v): try: ret = _copy(cache[key]) print('RET worked') - print(ret) + #print(ret) return ret except KeyError: print('KEYERROR') diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 990eaa3..9e4542e 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -70,6 +70,7 @@ def name(self): def get_stats_table(self, table_id, year, level='B'): doc = self.get_year_doc(year, level=level) table = doc('table#{}'.format(table_id)) + print(table_id) df = sportsref.utils.parse_table(table) return df diff --git a/sportsref/utils.py b/sportsref/utils.py index ff6fe49..933fc77 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -71,14 +71,21 @@ def parse_table(table, flatten=True, footer=False): """ if not len(table): return pd.DataFrame() - + # get columns columns = [c.attrib['data-stat'] for c in table('thead tr:not([class]) th[data-stat]')] # get data rows = list(table('tbody tr' if not footer else 'tfoot tr') - .not_('.thead, .stat_total, .stat_average').items()) + .not_('.thead, .stat_total, .stat_average').items()) + + # edge case for team and opp euro stats (not specifying it by id in case this approach works for other tables set up like this) + if len(columns) == 0: + columns = [c.attrib['data-stat'] for c in table('.thead th[data-stat]')] + columns[0] = 'team' + rows = list(table('tr').not_('.thead').items()) + data = [ [flatten_links(td) if flatten else td.text() for td in row.items('th,td')] From 083dbb392c1479e2f6900cb32f1b7c28a1455a85 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Fri, 2 Feb 2018 20:00:01 -0500 Subject: [PATCH 33/57] reran test notebook with fix --- euro_teams_test.ipynb | 4011 ++++------------------------------------- 1 file changed, 320 insertions(+), 3691 deletions(-) diff --git a/euro_teams_test.ipynb b/euro_teams_test.ipynb index 3b76214..ad0b3a3 100644 --- a/euro_teams_test.ipynb +++ b/euro_teams_test.ipynb @@ -2,18 +2,27 @@ "cells": [ { "cell_type": "code", - "execution_count": 35, + "execution_count": 1, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Regenerating PSFConstants file\n", + "Regenerating GPFConstants file\n" + ] + } + ], "source": [ "from sportsref import euro" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 2, "metadata": { "collapsed": true }, @@ -34,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -82,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 6, "metadata": { "scrolled": true }, @@ -108,20 +117,100 @@ " \n", " \n", " \n", + " team_id\n", + " g\n", + " mp\n", + " fg\n", + " fga\n", + " fg_pct\n", + " fg3\n", + " fg3a\n", + " fg3_pct\n", + " fg2\n", + " ...\n", + " ft_pct\n", + " orb\n", + " drb\n", + " trb\n", + " ast\n", + " stl\n", + " blk\n", + " tov\n", + " pf\n", + " pts\n", " \n", " \n", " \n", + " \n", + " 0\n", + " Team\n", + " 62.0\n", + " 13100.0\n", + " 1795.0\n", + " 3812.0\n", + " 0.471\n", + " 586.0\n", + " 1579.0\n", + " 0.371\n", + " 1209.0\n", + " ...\n", + " 0.744\n", + " 515.0\n", + " 1510.0\n", + " 2025.0\n", + " 1084.0\n", + " 437.0\n", + " 140.0\n", + " 884.0\n", + " 1313.0\n", + " 4988.0\n", + " \n", + " \n", + " 1\n", + " Opponent\n", + " 62.0\n", + " 13100.0\n", + " 1754.0\n", + " 4013.0\n", + " 0.437\n", + " 584.0\n", + " 1623.0\n", + " 0.360\n", + " 1170.0\n", + " ...\n", + " 0.763\n", + " 573.0\n", + " 1368.0\n", + " 1941.0\n", + " 1039.0\n", + " 453.0\n", + " 109.0\n", + " 779.0\n", + " 1318.0\n", + " 4897.0\n", + " \n", " \n", "\n", + "

2 rows × 24 columns

\n", "" ], "text/plain": [ - "Empty DataFrame\n", - "Columns: []\n", - "Index: []" + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 62.0 13100.0 1795.0 3812.0 0.471 586.0 1579.0 0.371 \n", + "1 Opponent 62.0 13100.0 1754.0 4013.0 0.437 584.0 1623.0 0.360 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 1209.0 ... 0.744 515.0 1510.0 2025.0 1084.0 437.0 140.0 884.0 \n", + "1 1170.0 ... 0.763 573.0 1368.0 1941.0 1039.0 453.0 109.0 779.0 \n", + "\n", + " pf pts \n", + "0 1313.0 4988.0 \n", + "1 1318.0 4897.0 \n", + "\n", + "[2 rows x 24 columns]" ] }, - "execution_count": 40, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -132,38 +221,16 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: [], ((, 2017, 'E'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: [], ((, 2017, 'C'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: []}\n", - "KEY in wrapper\n", - "((, 2017, 'E'), frozenset())\n", - "COPY\n", - "RET worked\n", - "Empty DataFrame\n", - "Columns: []\n", - "Index: []\n" - ] - } - ], + "outputs": [], "source": [ "df = t.all_team_opp_stats(2017, level = 'E')" ] }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -187,20 +254,100 @@ " \n", " \n", " \n", + " team_id\n", + " g\n", + " mp\n", + " fg\n", + " fga\n", + " fg_pct\n", + " fg3\n", + " fg3a\n", + " fg3_pct\n", + " fg2\n", + " ...\n", + " ft_pct\n", + " orb\n", + " drb\n", + " trb\n", + " ast\n", + " stl\n", + " blk\n", + " tov\n", + " pf\n", + " pts\n", " \n", " \n", " \n", + " \n", + " 0\n", + " Team\n", + " 30.0\n", + " 6025.0\n", + " 767.0\n", + " 1739.0\n", + " 0.441\n", + " 271.0\n", + " 716.0\n", + " 0.378\n", + " 496.0\n", + " ...\n", + " 0.737\n", + " 245.0\n", + " 680.0\n", + " 925.0\n", + " 517.0\n", + " 212.0\n", + " 61.0\n", + " 420.0\n", + " 553.0\n", + " 2141.0\n", + " \n", + " \n", + " 1\n", + " Opponent\n", + " 30.0\n", + " 6025.0\n", + " 834.0\n", + " 1844.0\n", + " 0.452\n", + " 263.0\n", + " 729.0\n", + " 0.361\n", + " 571.0\n", + " ...\n", + " 0.748\n", + " 254.0\n", + " 659.0\n", + " 913.0\n", + " 510.0\n", + " 232.0\n", + " 65.0\n", + " 357.0\n", + " 599.0\n", + " 2242.0\n", + " \n", " \n", "\n", + "

2 rows × 24 columns

\n", "" ], "text/plain": [ - "Empty DataFrame\n", - "Columns: []\n", - "Index: []" + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 30.0 6025.0 767.0 1739.0 0.441 271.0 716.0 0.378 \n", + "1 Opponent 30.0 6025.0 834.0 1844.0 0.452 263.0 729.0 0.361 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 496.0 ... 0.737 245.0 680.0 925.0 517.0 212.0 61.0 420.0 \n", + "1 571.0 ... 0.748 254.0 659.0 913.0 510.0 232.0 65.0 357.0 \n", + "\n", + " pf pts \n", + "0 553.0 2141.0 \n", + "1 599.0 2242.0 \n", + "\n", + "[2 rows x 24 columns]" ] }, - "execution_count": 42, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -211,38 +358,16 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: [], ((, 2017, 'E'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: [], ((, 2017, 'C'), frozenset()): Empty DataFrame\n", - "Columns: []\n", - "Index: []}\n", - "KEY in wrapper\n", - "((, 2017, 'C'), frozenset())\n", - "COPY\n", - "RET worked\n", - "Empty DataFrame\n", - "Columns: []\n", - "Index: []\n" - ] - } - ], + "outputs": [], "source": [ "df = t.all_team_opp_stats(2017, level = 'C')" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -266,20 +391,100 @@ " \n", " \n", " \n", + " team_id\n", + " g\n", + " mp\n", + " fg\n", + " fga\n", + " fg_pct\n", + " fg3\n", + " fg3a\n", + " fg3_pct\n", + " fg2\n", + " ...\n", + " ft_pct\n", + " orb\n", + " drb\n", + " trb\n", + " ast\n", + " stl\n", + " blk\n", + " tov\n", + " pf\n", + " pts\n", " \n", " \n", " \n", + " \n", + " 0\n", + " Team\n", + " 32.0\n", + " 7075.0\n", + " 1028.0\n", + " 2073.0\n", + " 0.496\n", + " 315.0\n", + " 863.0\n", + " 0.365\n", + " 713.0\n", + " ...\n", + " 0.748\n", + " 270.0\n", + " 830.0\n", + " 1100.0\n", + " 567.0\n", + " 225.0\n", + " 79.0\n", + " 464.0\n", + " 760.0\n", + " 2847.0\n", + " \n", + " \n", + " 1\n", + " Opponent\n", + " 32.0\n", + " 7075.0\n", + " 920.0\n", + " 2169.0\n", + " 0.424\n", + " 321.0\n", + " 894.0\n", + " 0.359\n", + " 599.0\n", + " ...\n", + " 0.773\n", + " 319.0\n", + " 709.0\n", + " 1028.0\n", + " 529.0\n", + " 221.0\n", + " 44.0\n", + " 422.0\n", + " 719.0\n", + " 2655.0\n", + " \n", " \n", "\n", + "

2 rows × 24 columns

\n", "" ], "text/plain": [ - "Empty DataFrame\n", - "Columns: []\n", - "Index: []" + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 32.0 7075.0 1028.0 2073.0 0.496 315.0 863.0 0.365 \n", + "1 Opponent 32.0 7075.0 920.0 2169.0 0.424 321.0 894.0 0.359 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 713.0 ... 0.748 270.0 830.0 1100.0 567.0 225.0 79.0 464.0 \n", + "1 599.0 ... 0.773 319.0 709.0 1028.0 529.0 221.0 44.0 422.0 \n", + "\n", + " pf pts \n", + "0 760.0 2847.0 \n", + "1 719.0 2655.0 \n", + "\n", + "[2 rows x 24 columns]" ] }, - "execution_count": 44, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -297,386 +502,16 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", - "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", - "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", - "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", - "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", - "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", - "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", - "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", - "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", - "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", - "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", - "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", - "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", - "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", - "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", - "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.6 5.2 0.307 ... 0.2 1.3 \n", - "1 0.0 0.0 0.333 ... 2.1 4.8 \n", - "2 1.6 3.8 0.417 ... 0.3 1.7 \n", - "3 0.9 2.2 0.395 ... 0.8 3.4 \n", - "4 1.1 2.7 0.420 ... 0.9 2.3 \n", - "5 1.0 2.5 0.406 ... 0.5 1.3 \n", - "6 0.9 2.8 0.309 ... 0.4 2.4 \n", - "7 0.7 1.7 0.403 ... 0.6 1.4 \n", - "8 1.1 2.0 0.527 ... 0.7 2.4 \n", - "9 0.0 0.0 NaN ... 2.1 3.8 \n", - "10 1.0 3.3 0.308 ... 0.1 0.8 \n", - "11 1.0 2.5 0.422 ... 0.3 1.1 \n", - "12 0.1 0.7 0.200 ... 1.1 3.4 \n", - "13 0.9 2.0 0.450 ... 0.8 2.2 \n", - "14 0.0 0.0 NaN ... 1.3 1.8 \n", - "15 0.1 0.7 0.133 ... 0.2 0.6 \n", - "16 0.3 0.8 0.333 ... 0.2 0.7 \n", - "17 1.7 4.0 0.417 ... 0.0 1.3 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "20 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", - "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", - "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", - "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", - "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", - "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", - "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", - "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", - "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", - "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", - "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", - "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", - "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", - "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", - "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", - "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", - "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", - "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 12.3 Tyrese Rice \n", - "1 10.8 Ante Tomic \n", - "2 9.4 Petteri Koponen \n", - "3 5.5 Victor Claver \n", - "4 8.3 Aleksandar Vezenkov \n", - "5 6.2 Brad Oleson \n", - "6 7.1 Stratos Perperoglou \n", - "7 4.7 Alex Renfroe \n", - "8 9.9 Justin Doellman \n", - "9 4.6 Joey Dorsey \n", - "10 6.5 Juan Carlos Navarro \n", - "11 4.7 Marcus Eriksson \n", - "12 8.3 Vitor Faverani \n", - "13 5.9 Jonathan Holmes \n", - "14 2.7 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.5 Xavier Munford \n", - "17 6.7 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "20 2.0 Rodions Kurucs \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", - "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", - "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", - "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", - "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", - "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", - "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", - "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.8 5.7 0.320 ... 0.3 1.4 \n", - "1 0.0 0.0 0.000 ... 2.2 3.7 \n", - "2 2.0 4.4 0.462 ... 0.2 1.5 \n", - "3 0.9 2.3 0.377 ... 0.9 3.5 \n", - "4 1.1 2.4 0.479 ... 0.8 2.4 \n", - "5 0.8 2.4 0.345 ... 0.5 1.4 \n", - "6 0.9 2.4 0.358 ... 0.4 2.8 \n", - "7 0.7 1.8 0.387 ... 0.6 1.5 \n", - "8 1.0 1.9 0.536 ... 0.7 2.5 \n", - "9 0.0 0.0 NaN ... 2.7 3.6 \n", - "10 1.0 3.5 0.286 ... 0.1 1.0 \n", - "11 0.5 1.5 0.353 ... 0.3 0.9 \n", - "12 0.1 0.8 0.143 ... 0.9 3.3 \n", - "13 0.6 1.7 0.333 ... 1.1 1.6 \n", - "14 0.0 0.0 NaN ... 1.0 2.5 \n", - "15 0.1 0.3 0.333 ... 0.2 0.4 \n", - "16 0.2 0.6 0.333 ... 0.4 0.6 \n", - "17 1.5 3.0 0.500 ... 0.0 0.5 \n", - "18 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", - "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", - "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", - "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", - "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", - "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", - "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", - "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", - "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", - "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", - "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", - "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", - "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", - "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", - "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", - "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", - "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", - "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 13.0 Tyrese Rice \n", - "1 8.8 Ante Tomic \n", - "2 10.1 Petteri Koponen \n", - "3 6.0 Victor Claver \n", - "4 7.5 Aleksandar Vezenkov \n", - "5 5.3 Brad Oleson \n", - "6 6.4 Stratos Perperoglou \n", - "7 3.9 Alex Renfroe \n", - "8 7.8 Justin Doellman \n", - "9 5.5 Joey Dorsey \n", - "10 5.7 Juan Carlos Navarro \n", - "11 2.0 Marcus Eriksson \n", - "12 7.7 Vitor Faverani \n", - "13 5.1 Jonathan Holmes \n", - "14 2.6 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.0 Xavier Munford \n", - "17 4.5 Pau Ribas \n", - "18 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", - "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", - "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", - "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", - "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", - "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", - "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.4 4.7 0.293 ... 0.2 1.3 \n", - "1 0.0 0.1 0.500 ... 2.0 5.8 \n", - "2 1.2 3.1 0.378 ... 0.9 2.2 \n", - "3 1.2 2.6 0.453 ... 0.6 1.2 \n", - "4 0.9 2.2 0.413 ... 0.8 3.3 \n", - "5 1.1 3.1 0.353 ... 0.4 1.8 \n", - "6 0.9 3.2 0.277 ... 0.3 2.2 \n", - "7 1.4 3.1 0.447 ... 0.3 1.3 \n", - "8 0.7 1.6 0.419 ... 0.6 1.3 \n", - "9 1.2 2.3 0.519 ... 0.7 2.4 \n", - "10 0.0 0.0 NaN ... 1.5 3.9 \n", - "11 1.0 3.0 0.333 ... 0.1 0.6 \n", - "12 0.0 0.0 NaN ... 1.5 1.4 \n", - "13 0.2 0.5 0.333 ... 1.5 3.5 \n", - "14 0.1 1.0 0.083 ... 0.2 0.8 \n", - "15 1.7 2.7 0.625 ... 0.0 3.7 \n", - "16 0.3 1.0 0.333 ... 0.0 0.8 \n", - "17 2.0 6.0 0.333 ... 0.0 3.0 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", - "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", - "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", - "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", - "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", - "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", - "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", - "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", - "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", - "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", - "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", - "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", - "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", - "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", - "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", - "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", - "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", - "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 11.6 Tyrese Rice \n", - "1 12.7 Ante Tomic \n", - "2 9.0 Aleksandar Vezenkov \n", - "3 7.0 Brad Oleson \n", - "4 5.0 Victor Claver \n", - "5 8.7 Petteri Koponen \n", - "6 7.8 Stratos Perperoglou \n", - "7 6.7 Marcus Eriksson \n", - "8 5.4 Alex Renfroe \n", - "9 12.6 Justin Doellman \n", - "10 3.7 Joey Dorsey \n", - "11 7.3 Juan Carlos Navarro \n", - "12 2.7 Moussa Diagne \n", - "13 9.2 Vitor Faverani \n", - "14 1.1 Stefan Peno \n", - "15 7.7 Jonathan Holmes \n", - "16 2.0 Xavier Munford \n", - "17 11.0 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'B'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", - "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", - "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", - "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", - "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", - "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", - "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", - "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", - "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", - "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", - "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", - "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", - "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", - "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", - "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", - "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.6 5.2 0.307 ... 0.2 1.3 \n", - "1 0.0 0.0 0.333 ... 2.1 4.8 \n", - "2 1.6 3.8 0.417 ... 0.3 1.7 \n", - "3 0.9 2.2 0.395 ... 0.8 3.4 \n", - "4 1.1 2.7 0.420 ... 0.9 2.3 \n", - "5 1.0 2.5 0.406 ... 0.5 1.3 \n", - "6 0.9 2.8 0.309 ... 0.4 2.4 \n", - "7 0.7 1.7 0.403 ... 0.6 1.4 \n", - "8 1.1 2.0 0.527 ... 0.7 2.4 \n", - "9 0.0 0.0 NaN ... 2.1 3.8 \n", - "10 1.0 3.3 0.308 ... 0.1 0.8 \n", - "11 1.0 2.5 0.422 ... 0.3 1.1 \n", - "12 0.1 0.7 0.200 ... 1.1 3.4 \n", - "13 0.9 2.0 0.450 ... 0.8 2.2 \n", - "14 0.0 0.0 NaN ... 1.3 1.8 \n", - "15 0.1 0.7 0.133 ... 0.2 0.6 \n", - "16 0.3 0.8 0.333 ... 0.2 0.7 \n", - "17 1.7 4.0 0.417 ... 0.0 1.3 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "20 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", - "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", - "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", - "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", - "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", - "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", - "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", - "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", - "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", - "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", - "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", - "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", - "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", - "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", - "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", - "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", - "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", - "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 12.3 Tyrese Rice \n", - "1 10.8 Ante Tomic \n", - "2 9.4 Petteri Koponen \n", - "3 5.5 Victor Claver \n", - "4 8.3 Aleksandar Vezenkov \n", - "5 6.2 Brad Oleson \n", - "6 7.1 Stratos Perperoglou \n", - "7 4.7 Alex Renfroe \n", - "8 9.9 Justin Doellman \n", - "9 4.6 Joey Dorsey \n", - "10 6.5 Juan Carlos Navarro \n", - "11 4.7 Marcus Eriksson \n", - "12 8.3 Vitor Faverani \n", - "13 5.9 Jonathan Holmes \n", - "14 2.7 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.5 Xavier Munford \n", - "17 6.7 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "20 2.0 Rodions Kurucs \n", - "\n", - "[21 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per_game(2017, level='B')" ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -881,7 +716,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 46, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -892,378 +727,16 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", - "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", - "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", - "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", - "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", - "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", - "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", - "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", - "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", - "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", - "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", - "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", - "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", - "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", - "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", - "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.6 5.2 0.307 ... 0.2 1.3 \n", - "1 0.0 0.0 0.333 ... 2.1 4.8 \n", - "2 1.6 3.8 0.417 ... 0.3 1.7 \n", - "3 0.9 2.2 0.395 ... 0.8 3.4 \n", - "4 1.1 2.7 0.420 ... 0.9 2.3 \n", - "5 1.0 2.5 0.406 ... 0.5 1.3 \n", - "6 0.9 2.8 0.309 ... 0.4 2.4 \n", - "7 0.7 1.7 0.403 ... 0.6 1.4 \n", - "8 1.1 2.0 0.527 ... 0.7 2.4 \n", - "9 0.0 0.0 NaN ... 2.1 3.8 \n", - "10 1.0 3.3 0.308 ... 0.1 0.8 \n", - "11 1.0 2.5 0.422 ... 0.3 1.1 \n", - "12 0.1 0.7 0.200 ... 1.1 3.4 \n", - "13 0.9 2.0 0.450 ... 0.8 2.2 \n", - "14 0.0 0.0 NaN ... 1.3 1.8 \n", - "15 0.1 0.7 0.133 ... 0.2 0.6 \n", - "16 0.3 0.8 0.333 ... 0.2 0.7 \n", - "17 1.7 4.0 0.417 ... 0.0 1.3 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "20 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", - "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", - "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", - "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", - "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", - "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", - "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", - "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", - "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", - "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", - "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", - "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", - "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", - "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", - "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", - "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", - "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", - "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 12.3 Tyrese Rice \n", - "1 10.8 Ante Tomic \n", - "2 9.4 Petteri Koponen \n", - "3 5.5 Victor Claver \n", - "4 8.3 Aleksandar Vezenkov \n", - "5 6.2 Brad Oleson \n", - "6 7.1 Stratos Perperoglou \n", - "7 4.7 Alex Renfroe \n", - "8 9.9 Justin Doellman \n", - "9 4.6 Joey Dorsey \n", - "10 6.5 Juan Carlos Navarro \n", - "11 4.7 Marcus Eriksson \n", - "12 8.3 Vitor Faverani \n", - "13 5.9 Jonathan Holmes \n", - "14 2.7 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.5 Xavier Munford \n", - "17 6.7 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "20 2.0 Rodions Kurucs \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", - "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", - "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", - "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", - "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", - "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", - "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", - "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.8 5.7 0.320 ... 0.3 1.4 \n", - "1 0.0 0.0 0.000 ... 2.2 3.7 \n", - "2 2.0 4.4 0.462 ... 0.2 1.5 \n", - "3 0.9 2.3 0.377 ... 0.9 3.5 \n", - "4 1.1 2.4 0.479 ... 0.8 2.4 \n", - "5 0.8 2.4 0.345 ... 0.5 1.4 \n", - "6 0.9 2.4 0.358 ... 0.4 2.8 \n", - "7 0.7 1.8 0.387 ... 0.6 1.5 \n", - "8 1.0 1.9 0.536 ... 0.7 2.5 \n", - "9 0.0 0.0 NaN ... 2.7 3.6 \n", - "10 1.0 3.5 0.286 ... 0.1 1.0 \n", - "11 0.5 1.5 0.353 ... 0.3 0.9 \n", - "12 0.1 0.8 0.143 ... 0.9 3.3 \n", - "13 0.6 1.7 0.333 ... 1.1 1.6 \n", - "14 0.0 0.0 NaN ... 1.0 2.5 \n", - "15 0.1 0.3 0.333 ... 0.2 0.4 \n", - "16 0.2 0.6 0.333 ... 0.4 0.6 \n", - "17 1.5 3.0 0.500 ... 0.0 0.5 \n", - "18 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", - "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", - "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", - "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", - "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", - "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", - "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", - "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", - "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", - "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", - "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", - "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", - "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", - "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", - "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", - "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", - "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", - "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 13.0 Tyrese Rice \n", - "1 8.8 Ante Tomic \n", - "2 10.1 Petteri Koponen \n", - "3 6.0 Victor Claver \n", - "4 7.5 Aleksandar Vezenkov \n", - "5 5.3 Brad Oleson \n", - "6 6.4 Stratos Perperoglou \n", - "7 3.9 Alex Renfroe \n", - "8 7.8 Justin Doellman \n", - "9 5.5 Joey Dorsey \n", - "10 5.7 Juan Carlos Navarro \n", - "11 2.0 Marcus Eriksson \n", - "12 7.7 Vitor Faverani \n", - "13 5.1 Jonathan Holmes \n", - "14 2.6 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.0 Xavier Munford \n", - "17 4.5 Pau Ribas \n", - "18 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", - "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", - "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", - "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", - "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", - "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", - "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.4 4.7 0.293 ... 0.2 1.3 \n", - "1 0.0 0.1 0.500 ... 2.0 5.8 \n", - "2 1.2 3.1 0.378 ... 0.9 2.2 \n", - "3 1.2 2.6 0.453 ... 0.6 1.2 \n", - "4 0.9 2.2 0.413 ... 0.8 3.3 \n", - "5 1.1 3.1 0.353 ... 0.4 1.8 \n", - "6 0.9 3.2 0.277 ... 0.3 2.2 \n", - "7 1.4 3.1 0.447 ... 0.3 1.3 \n", - "8 0.7 1.6 0.419 ... 0.6 1.3 \n", - "9 1.2 2.3 0.519 ... 0.7 2.4 \n", - "10 0.0 0.0 NaN ... 1.5 3.9 \n", - "11 1.0 3.0 0.333 ... 0.1 0.6 \n", - "12 0.0 0.0 NaN ... 1.5 1.4 \n", - "13 0.2 0.5 0.333 ... 1.5 3.5 \n", - "14 0.1 1.0 0.083 ... 0.2 0.8 \n", - "15 1.7 2.7 0.625 ... 0.0 3.7 \n", - "16 0.3 1.0 0.333 ... 0.0 0.8 \n", - "17 2.0 6.0 0.333 ... 0.0 3.0 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", - "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", - "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", - "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", - "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", - "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", - "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", - "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", - "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", - "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", - "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", - "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", - "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", - "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", - "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", - "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", - "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", - "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 11.6 Tyrese Rice \n", - "1 12.7 Ante Tomic \n", - "2 9.0 Aleksandar Vezenkov \n", - "3 7.0 Brad Oleson \n", - "4 5.0 Victor Claver \n", - "5 8.7 Petteri Koponen \n", - "6 7.8 Stratos Perperoglou \n", - "7 6.7 Marcus Eriksson \n", - "8 5.4 Alex Renfroe \n", - "9 12.6 Justin Doellman \n", - "10 3.7 Joey Dorsey \n", - "11 7.3 Juan Carlos Navarro \n", - "12 2.7 Moussa Diagne \n", - "13 9.2 Vitor Faverani \n", - "14 1.1 Stefan Peno \n", - "15 7.7 Jonathan Holmes \n", - "16 2.0 Xavier Munford \n", - "17 11.0 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'E'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", - "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", - "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", - "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", - "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", - "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", - "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", - "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.8 5.7 0.320 ... 0.3 1.4 \n", - "1 0.0 0.0 0.000 ... 2.2 3.7 \n", - "2 2.0 4.4 0.462 ... 0.2 1.5 \n", - "3 0.9 2.3 0.377 ... 0.9 3.5 \n", - "4 1.1 2.4 0.479 ... 0.8 2.4 \n", - "5 0.8 2.4 0.345 ... 0.5 1.4 \n", - "6 0.9 2.4 0.358 ... 0.4 2.8 \n", - "7 0.7 1.8 0.387 ... 0.6 1.5 \n", - "8 1.0 1.9 0.536 ... 0.7 2.5 \n", - "9 0.0 0.0 NaN ... 2.7 3.6 \n", - "10 1.0 3.5 0.286 ... 0.1 1.0 \n", - "11 0.5 1.5 0.353 ... 0.3 0.9 \n", - "12 0.1 0.8 0.143 ... 0.9 3.3 \n", - "13 0.6 1.7 0.333 ... 1.1 1.6 \n", - "14 0.0 0.0 NaN ... 1.0 2.5 \n", - "15 0.1 0.3 0.333 ... 0.2 0.4 \n", - "16 0.2 0.6 0.333 ... 0.4 0.6 \n", - "17 1.5 3.0 0.500 ... 0.0 0.5 \n", - "18 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", - "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", - "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", - "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", - "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", - "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", - "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", - "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", - "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", - "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", - "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", - "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", - "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", - "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", - "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", - "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", - "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", - "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 13.0 Tyrese Rice \n", - "1 8.8 Ante Tomic \n", - "2 10.1 Petteri Koponen \n", - "3 6.0 Victor Claver \n", - "4 7.5 Aleksandar Vezenkov \n", - "5 5.3 Brad Oleson \n", - "6 6.4 Stratos Perperoglou \n", - "7 3.9 Alex Renfroe \n", - "8 7.8 Justin Doellman \n", - "9 5.5 Joey Dorsey \n", - "10 5.7 Juan Carlos Navarro \n", - "11 2.0 Marcus Eriksson \n", - "12 7.7 Vitor Faverani \n", - "13 5.1 Jonathan Holmes \n", - "14 2.6 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.0 Xavier Munford \n", - "17 4.5 Pau Ribas \n", - "18 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per_game(2017, level='E')" ] }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -1468,7 +941,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 48, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -1479,382 +952,16 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", - "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", - "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 21.2 2.3 4.3 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 20.6 2.7 6.7 0.406 \n", - "7 alex-renfroe-1 37.0 NaN 18.1 1.7 3.7 0.464 \n", - "8 justin-doellman-1 27.0 NaN 21.2 3.6 7.2 0.492 \n", - "9 joey-dorsey-1 33.0 NaN 16.8 1.8 2.9 0.598 \n", - "10 juan-carlos-navarro-1 32.0 NaN 14.7 2.3 5.8 0.389 \n", - "11 marcus-eriksson-1 52.0 NaN 12.9 1.7 3.6 0.460 \n", - "12 vitor-faverani-1 15.0 NaN 16.0 2.9 5.1 0.571 \n", - "13 jonathan-holmes-1 10.0 NaN 14.3 2.0 3.8 0.526 \n", - "14 moussa-diagne-1 23.0 NaN 8.7 0.8 1.9 0.419 \n", - "15 stefan-peno-1 22.0 NaN 6.5 0.4 1.3 0.286 \n", - "16 xavier-munford-1 11.0 NaN 7.0 0.6 1.6 0.389 \n", - "17 pau-ribas-1 3.0 NaN 14.3 2.0 5.0 0.400 \n", - "18 pol-figueras-1 2.0 NaN 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 \n", - "20 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.6 5.2 0.307 ... 0.2 1.3 \n", - "1 0.0 0.0 0.333 ... 2.1 4.8 \n", - "2 1.6 3.8 0.417 ... 0.3 1.7 \n", - "3 0.9 2.2 0.395 ... 0.8 3.4 \n", - "4 1.1 2.7 0.420 ... 0.9 2.3 \n", - "5 1.0 2.5 0.406 ... 0.5 1.3 \n", - "6 0.9 2.8 0.309 ... 0.4 2.4 \n", - "7 0.7 1.7 0.403 ... 0.6 1.4 \n", - "8 1.1 2.0 0.527 ... 0.7 2.4 \n", - "9 0.0 0.0 NaN ... 2.1 3.8 \n", - "10 1.0 3.3 0.308 ... 0.1 0.8 \n", - "11 1.0 2.5 0.422 ... 0.3 1.1 \n", - "12 0.1 0.7 0.200 ... 1.1 3.4 \n", - "13 0.9 2.0 0.450 ... 0.8 2.2 \n", - "14 0.0 0.0 NaN ... 1.3 1.8 \n", - "15 0.1 0.7 0.133 ... 0.2 0.6 \n", - "16 0.3 0.8 0.333 ... 0.2 0.7 \n", - "17 1.7 4.0 0.417 ... 0.0 1.3 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "20 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.1 1.0 0.1 2.5 2.3 \n", - "1 6.9 2.0 0.6 0.6 1.6 2.2 \n", - "2 1.9 2.1 0.7 0.1 1.3 1.9 \n", - "3 4.3 1.2 0.9 0.4 1.3 2.0 \n", - "4 3.2 1.0 0.6 0.2 0.7 1.9 \n", - "5 1.8 1.8 0.6 0.2 1.0 1.6 \n", - "6 2.8 1.3 0.7 0.1 1.1 1.9 \n", - "7 2.0 1.9 0.9 0.1 1.2 2.0 \n", - "8 3.1 1.2 0.9 0.1 1.2 1.6 \n", - "9 5.9 1.0 0.4 0.4 1.8 2.8 \n", - "10 0.9 1.5 0.5 0.0 1.1 1.2 \n", - "11 1.4 0.8 0.3 0.1 0.5 1.4 \n", - "12 4.5 0.5 0.3 0.1 1.9 2.1 \n", - "13 3.0 0.2 0.4 0.4 2.0 3.0 \n", - "14 3.1 0.3 0.3 0.1 0.8 1.6 \n", - "15 0.8 0.8 0.2 0.0 0.8 1.3 \n", - "16 0.9 0.6 0.3 0.2 1.5 1.0 \n", - "17 1.3 1.3 0.7 0.0 1.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 12.3 Tyrese Rice \n", - "1 10.8 Ante Tomic \n", - "2 9.4 Petteri Koponen \n", - "3 5.5 Victor Claver \n", - "4 8.3 Aleksandar Vezenkov \n", - "5 6.2 Brad Oleson \n", - "6 7.1 Stratos Perperoglou \n", - "7 4.7 Alex Renfroe \n", - "8 9.9 Justin Doellman \n", - "9 4.6 Joey Dorsey \n", - "10 6.5 Juan Carlos Navarro \n", - "11 4.7 Marcus Eriksson \n", - "12 8.3 Vitor Faverani \n", - "13 5.9 Jonathan Holmes \n", - "14 2.7 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.5 Xavier Munford \n", - "17 6.7 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "20 2.0 Rodions Kurucs \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", - "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", - "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", - "5 brad-oleson-1 24.0 NaN 21.6 2.1 4.3 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 20.9 2.4 6.3 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 17.7 1.4 3.4 0.414 \n", - "8 justin-doellman-1 15.0 NaN 19.9 2.8 6.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 17.2 2.0 3.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 15.4 1.9 5.9 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 9.9 0.7 2.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 15.4 2.8 5.0 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 12.7 1.6 3.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 9.9 0.6 1.6 0.385 \n", - "15 stefan-peno-1 10.0 NaN 4.8 0.3 0.8 0.375 \n", - "16 xavier-munford-1 5.0 NaN 6.8 0.4 1.8 0.222 \n", - "17 pau-ribas-1 2.0 NaN 10.0 1.5 3.5 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.8 5.7 0.320 ... 0.3 1.4 \n", - "1 0.0 0.0 0.000 ... 2.2 3.7 \n", - "2 2.0 4.4 0.462 ... 0.2 1.5 \n", - "3 0.9 2.3 0.377 ... 0.9 3.5 \n", - "4 1.1 2.4 0.479 ... 0.8 2.4 \n", - "5 0.8 2.4 0.345 ... 0.5 1.4 \n", - "6 0.9 2.4 0.358 ... 0.4 2.8 \n", - "7 0.7 1.8 0.387 ... 0.6 1.5 \n", - "8 1.0 1.9 0.536 ... 0.7 2.5 \n", - "9 0.0 0.0 NaN ... 2.7 3.6 \n", - "10 1.0 3.5 0.286 ... 0.1 1.0 \n", - "11 0.5 1.5 0.353 ... 0.3 0.9 \n", - "12 0.1 0.8 0.143 ... 0.9 3.3 \n", - "13 0.6 1.7 0.333 ... 1.1 1.6 \n", - "14 0.0 0.0 NaN ... 1.0 2.5 \n", - "15 0.1 0.3 0.333 ... 0.2 0.4 \n", - "16 0.2 0.6 0.333 ... 0.4 0.6 \n", - "17 1.5 3.0 0.500 ... 0.0 0.5 \n", - "18 0.0 1.0 0.000 ... 0.0 0.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.6 4.9 1.1 0.1 2.6 2.1 \n", - "1 5.9 2.0 0.6 0.7 1.9 2.1 \n", - "2 1.7 1.9 0.7 0.0 1.3 1.9 \n", - "3 4.4 1.3 0.9 0.3 1.2 1.7 \n", - "4 3.2 1.1 0.7 0.2 0.6 1.5 \n", - "5 1.8 2.0 0.6 0.2 0.8 1.7 \n", - "6 3.1 1.5 0.7 0.2 1.0 1.5 \n", - "7 2.1 1.6 1.0 0.0 1.4 2.0 \n", - "8 3.1 1.2 0.9 0.1 0.9 1.5 \n", - "9 6.3 0.8 0.5 0.3 1.8 2.4 \n", - "10 1.1 1.8 0.4 0.0 1.8 1.3 \n", - "11 1.2 0.3 0.4 0.1 0.5 1.2 \n", - "12 4.2 0.6 0.3 0.2 1.7 1.9 \n", - "13 2.7 0.3 0.3 0.1 1.6 2.7 \n", - "14 3.5 0.4 0.3 0.1 0.9 2.3 \n", - "15 0.6 0.5 0.3 0.1 0.6 1.0 \n", - "16 1.0 0.4 0.2 0.0 1.8 0.4 \n", - "17 0.5 0.5 0.5 0.0 0.5 1.0 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 13.0 Tyrese Rice \n", - "1 8.8 Ante Tomic \n", - "2 10.1 Petteri Koponen \n", - "3 6.0 Victor Claver \n", - "4 7.5 Aleksandar Vezenkov \n", - "5 5.3 Brad Oleson \n", - "6 6.4 Stratos Perperoglou \n", - "7 3.9 Alex Renfroe \n", - "8 7.8 Justin Doellman \n", - "9 5.5 Joey Dorsey \n", - "10 5.7 Juan Carlos Navarro \n", - "11 2.0 Marcus Eriksson \n", - "12 7.7 Vitor Faverani \n", - "13 5.1 Jonathan Holmes \n", - "14 2.6 Moussa Diagne \n", - "15 1.1 Stefan Peno \n", - "16 1.0 Xavier Munford \n", - "17 4.5 Pau Ribas \n", - "18 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", - "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", - "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", - "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", - "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", - "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", - "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.4 4.7 0.293 ... 0.2 1.3 \n", - "1 0.0 0.1 0.500 ... 2.0 5.8 \n", - "2 1.2 3.1 0.378 ... 0.9 2.2 \n", - "3 1.2 2.6 0.453 ... 0.6 1.2 \n", - "4 0.9 2.2 0.413 ... 0.8 3.3 \n", - "5 1.1 3.1 0.353 ... 0.4 1.8 \n", - "6 0.9 3.2 0.277 ... 0.3 2.2 \n", - "7 1.4 3.1 0.447 ... 0.3 1.3 \n", - "8 0.7 1.6 0.419 ... 0.6 1.3 \n", - "9 1.2 2.3 0.519 ... 0.7 2.4 \n", - "10 0.0 0.0 NaN ... 1.5 3.9 \n", - "11 1.0 3.0 0.333 ... 0.1 0.6 \n", - "12 0.0 0.0 NaN ... 1.5 1.4 \n", - "13 0.2 0.5 0.333 ... 1.5 3.5 \n", - "14 0.1 1.0 0.083 ... 0.2 0.8 \n", - "15 1.7 2.7 0.625 ... 0.0 3.7 \n", - "16 0.3 1.0 0.333 ... 0.0 0.8 \n", - "17 2.0 6.0 0.333 ... 0.0 3.0 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", - "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", - "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", - "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", - "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", - "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", - "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", - "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", - "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", - "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", - "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", - "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", - "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", - "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", - "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", - "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", - "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", - "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 11.6 Tyrese Rice \n", - "1 12.7 Ante Tomic \n", - "2 9.0 Aleksandar Vezenkov \n", - "3 7.0 Brad Oleson \n", - "4 5.0 Victor Claver \n", - "5 8.7 Petteri Koponen \n", - "6 7.8 Stratos Perperoglou \n", - "7 6.7 Marcus Eriksson \n", - "8 5.4 Alex Renfroe \n", - "9 12.6 Justin Doellman \n", - "10 3.7 Joey Dorsey \n", - "11 7.3 Juan Carlos Navarro \n", - "12 2.7 Moussa Diagne \n", - "13 9.2 Vitor Faverani \n", - "14 1.1 Stefan Peno \n", - "15 7.7 Jonathan Holmes \n", - "16 2.0 Xavier Munford \n", - "17 11.0 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'C'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", - "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", - "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", - "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 21.7 3.0 6.8 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 20.3 3.0 7.0 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 15.1 2.4 4.6 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 18.4 2.0 4.0 0.500 \n", - "9 justin-doellman-1 12.0 8.0 22.8 4.5 8.4 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 16.5 1.5 2.2 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 13.9 2.6 5.7 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 8.1 0.9 2.0 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 16.8 3.2 5.3 0.594 \n", - "14 stefan-peno-1 12.0 0.0 7.9 0.4 1.7 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 18.0 3.0 5.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 7.2 0.8 1.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 \n", - "18 pol-figueras-1 2.0 0.0 6.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.4 4.7 0.293 ... 0.2 1.3 \n", - "1 0.0 0.1 0.500 ... 2.0 5.8 \n", - "2 1.2 3.1 0.378 ... 0.9 2.2 \n", - "3 1.2 2.6 0.453 ... 0.6 1.2 \n", - "4 0.9 2.2 0.413 ... 0.8 3.3 \n", - "5 1.1 3.1 0.353 ... 0.4 1.8 \n", - "6 0.9 3.2 0.277 ... 0.3 2.2 \n", - "7 1.4 3.1 0.447 ... 0.3 1.3 \n", - "8 0.7 1.6 0.419 ... 0.6 1.3 \n", - "9 1.2 2.3 0.519 ... 0.7 2.4 \n", - "10 0.0 0.0 NaN ... 1.5 3.9 \n", - "11 1.0 3.0 0.333 ... 0.1 0.6 \n", - "12 0.0 0.0 NaN ... 1.5 1.4 \n", - "13 0.2 0.5 0.333 ... 1.5 3.5 \n", - "14 0.1 1.0 0.083 ... 0.2 0.8 \n", - "15 1.7 2.7 0.625 ... 0.0 3.7 \n", - "16 0.3 1.0 0.333 ... 0.0 0.8 \n", - "17 2.0 6.0 0.333 ... 0.0 3.0 \n", - "18 0.0 0.0 NaN ... 0.0 0.0 \n", - "19 0.0 0.0 NaN ... 1.0 1.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", - "0 1.5 3.4 0.8 0.0 2.4 2.5 \n", - "1 7.9 2.1 0.6 0.5 1.3 2.3 \n", - "2 3.2 0.8 0.5 0.3 0.8 2.2 \n", - "3 1.8 1.7 0.6 0.1 1.1 1.6 \n", - "4 4.1 1.2 0.9 0.6 1.4 2.3 \n", - "5 2.2 2.3 0.7 0.1 1.3 1.8 \n", - "6 2.5 1.1 0.7 0.1 1.1 2.3 \n", - "7 1.6 1.1 0.3 0.1 0.4 1.6 \n", - "8 1.9 2.1 0.8 0.2 1.1 2.1 \n", - "9 3.1 1.2 0.9 0.2 1.6 1.8 \n", - "10 5.4 1.2 0.3 0.6 1.8 3.1 \n", - "11 0.7 1.3 0.5 0.0 0.5 1.2 \n", - "12 2.9 0.3 0.3 0.1 0.8 1.3 \n", - "13 5.0 0.3 0.3 0.0 2.2 2.5 \n", - "14 1.0 1.0 0.2 0.0 0.9 1.5 \n", - "15 3.7 0.0 0.7 1.0 3.0 3.7 \n", - "16 0.8 0.8 0.3 0.3 1.2 1.5 \n", - "17 3.0 3.0 1.0 0.0 2.0 1.0 \n", - "18 0.0 0.0 0.5 0.0 1.5 0.5 \n", - "19 2.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pts_per_g player_name \n", - "0 11.6 Tyrese Rice \n", - "1 12.7 Ante Tomic \n", - "2 9.0 Aleksandar Vezenkov \n", - "3 7.0 Brad Oleson \n", - "4 5.0 Victor Claver \n", - "5 8.7 Petteri Koponen \n", - "6 7.8 Stratos Perperoglou \n", - "7 6.7 Marcus Eriksson \n", - "8 5.4 Alex Renfroe \n", - "9 12.6 Justin Doellman \n", - "10 3.7 Joey Dorsey \n", - "11 7.3 Juan Carlos Navarro \n", - "12 2.7 Moussa Diagne \n", - "13 9.2 Vitor Faverani \n", - "14 1.1 Stefan Peno \n", - "15 7.7 Jonathan Holmes \n", - "16 2.0 Xavier Munford \n", - "17 11.0 Pau Ribas \n", - "18 0.0 Pol Figueras \n", - "19 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per_game(2017, level='C')" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -2059,7 +1166,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 50, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -2077,297 +1184,16 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", - "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", - "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", - "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", - "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", - "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", - "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", - "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", - "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", - "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", - "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", - "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", - "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", - "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", - "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", - "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", - "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", - "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", - "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", - "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", - "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", - "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", - "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", - "1 36.0 99.0 135.0 661.0 Ante Tomic \n", - "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", - "3 24.0 74.0 111.0 309.0 Victor Claver \n", - "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", - "5 9.0 51.0 87.0 330.0 Brad Oleson \n", - "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", - "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", - "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", - "9 4.0 33.0 44.0 268.0 Justin Doellman \n", - "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", - "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", - "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", - "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", - "14 1.0 17.0 28.0 24.0 Stefan Peno \n", - "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", - "16 2.0 16.0 11.0 17.0 Xavier Munford \n", - "17 0.0 3.0 3.0 20.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", - "20 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", - "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", - "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", - "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", - "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", - "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", - "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk tov \\\n", - "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", - "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", - "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", - "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", - "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", - "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", - "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", - "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", - "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", - "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", - "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", - "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", - "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", - "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", - "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", - "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", - "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", - "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", - "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf pts player_name \n", - "0 63.0 389.0 Tyrese Rice \n", - "1 62.0 256.0 Ante Tomic \n", - "2 52.0 274.0 Petteri Koponen \n", - "3 45.0 163.0 Victor Claver \n", - "4 46.0 226.0 Aleksandar Vezenkov \n", - "5 40.0 128.0 Brad Oleson \n", - "6 33.0 140.0 Stratos Perperoglou \n", - "7 34.0 67.0 Alex Renfroe \n", - "8 23.0 117.0 Justin Doellman \n", - "9 41.0 93.0 Joey Dorsey \n", - "10 20.0 91.0 Juan Carlos Navarro \n", - "11 26.0 44.0 Marcus Eriksson \n", - "12 17.0 69.0 Vitor Faverani \n", - "13 19.0 36.0 Jonathan Holmes \n", - "14 18.0 21.0 Moussa Diagne \n", - "15 10.0 11.0 Stefan Peno \n", - "16 2.0 5.0 Xavier Munford \n", - "17 2.0 9.0 Pau Ribas \n", - "18 0.0 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", - "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", - "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", - "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", - "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", - "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", - "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", - "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", - "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", - "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", - "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", - "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", - "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", - "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", - "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", - "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", - "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", - "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", - "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", - "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", - "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", - "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", - "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", - "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", - "1 16.0 43.0 73.0 405.0 Ante Tomic \n", - "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", - "3 4.0 31.0 47.0 202.0 Brad Oleson \n", - "4 16.0 41.0 66.0 146.0 Victor Claver \n", - "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", - "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", - "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", - "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", - "9 2.0 19.0 21.0 151.0 Justin Doellman \n", - "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", - "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", - "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", - "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", - "14 0.0 11.0 18.0 13.0 Stefan Peno \n", - "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", - "16 2.0 7.0 9.0 12.0 Xavier Munford \n", - "17 0.0 2.0 1.0 11.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'B'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", - "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", - "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", - "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", - "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", - "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", - "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", - "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", - "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", - "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", - "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", - "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", - "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", - "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", - "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", - "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", - "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", - "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", - "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", - "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", - "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", - "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", - "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", - "1 36.0 99.0 135.0 661.0 Ante Tomic \n", - "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", - "3 24.0 74.0 111.0 309.0 Victor Claver \n", - "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", - "5 9.0 51.0 87.0 330.0 Brad Oleson \n", - "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", - "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", - "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", - "9 4.0 33.0 44.0 268.0 Justin Doellman \n", - "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", - "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", - "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", - "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", - "14 1.0 17.0 28.0 24.0 Stefan Peno \n", - "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", - "16 2.0 16.0 11.0 17.0 Xavier Munford \n", - "17 0.0 3.0 3.0 20.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", - "20 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_totals(2017, level='B')" ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -2565,7 +1391,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 52, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -2576,291 +1402,16 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", - "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", - "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", - "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", - "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", - "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", - "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", - "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", - "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", - "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", - "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", - "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", - "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", - "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", - "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", - "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", - "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", - "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", - "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", - "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", - "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", - "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", - "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", - "1 36.0 99.0 135.0 661.0 Ante Tomic \n", - "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", - "3 24.0 74.0 111.0 309.0 Victor Claver \n", - "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", - "5 9.0 51.0 87.0 330.0 Brad Oleson \n", - "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", - "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", - "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", - "9 4.0 33.0 44.0 268.0 Justin Doellman \n", - "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", - "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", - "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", - "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", - "14 1.0 17.0 28.0 24.0 Stefan Peno \n", - "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", - "16 2.0 16.0 11.0 17.0 Xavier Munford \n", - "17 0.0 3.0 3.0 20.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", - "20 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", - "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", - "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", - "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", - "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", - "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", - "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk tov \\\n", - "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", - "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", - "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", - "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", - "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", - "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", - "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", - "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", - "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", - "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", - "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", - "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", - "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", - "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", - "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", - "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", - "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", - "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", - "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf pts player_name \n", - "0 63.0 389.0 Tyrese Rice \n", - "1 62.0 256.0 Ante Tomic \n", - "2 52.0 274.0 Petteri Koponen \n", - "3 45.0 163.0 Victor Claver \n", - "4 46.0 226.0 Aleksandar Vezenkov \n", - "5 40.0 128.0 Brad Oleson \n", - "6 33.0 140.0 Stratos Perperoglou \n", - "7 34.0 67.0 Alex Renfroe \n", - "8 23.0 117.0 Justin Doellman \n", - "9 41.0 93.0 Joey Dorsey \n", - "10 20.0 91.0 Juan Carlos Navarro \n", - "11 26.0 44.0 Marcus Eriksson \n", - "12 17.0 69.0 Vitor Faverani \n", - "13 19.0 36.0 Jonathan Holmes \n", - "14 18.0 21.0 Moussa Diagne \n", - "15 10.0 11.0 Stefan Peno \n", - "16 2.0 5.0 Xavier Munford \n", - "17 2.0 9.0 Pau Ribas \n", - "18 0.0 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", - "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", - "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", - "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", - "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", - "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", - "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", - "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", - "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", - "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", - "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", - "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", - "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", - "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", - "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", - "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", - "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", - "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", - "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", - "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", - "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", - "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", - "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", - "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", - "1 16.0 43.0 73.0 405.0 Ante Tomic \n", - "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", - "3 4.0 31.0 47.0 202.0 Brad Oleson \n", - "4 16.0 41.0 66.0 146.0 Victor Claver \n", - "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", - "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", - "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", - "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", - "9 2.0 19.0 21.0 151.0 Justin Doellman \n", - "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", - "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", - "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", - "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", - "14 0.0 11.0 18.0 13.0 Stefan Peno \n", - "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", - "16 2.0 7.0 9.0 12.0 Xavier Munford \n", - "17 0.0 2.0 1.0 11.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'E'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", - "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", - "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", - "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", - "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", - "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", - "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk tov \\\n", - "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", - "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", - "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", - "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", - "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", - "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", - "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", - "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", - "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", - "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", - "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", - "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", - "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", - "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", - "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", - "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", - "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", - "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", - "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf pts player_name \n", - "0 63.0 389.0 Tyrese Rice \n", - "1 62.0 256.0 Ante Tomic \n", - "2 52.0 274.0 Petteri Koponen \n", - "3 45.0 163.0 Victor Claver \n", - "4 46.0 226.0 Aleksandar Vezenkov \n", - "5 40.0 128.0 Brad Oleson \n", - "6 33.0 140.0 Stratos Perperoglou \n", - "7 34.0 67.0 Alex Renfroe \n", - "8 23.0 117.0 Justin Doellman \n", - "9 41.0 93.0 Joey Dorsey \n", - "10 20.0 91.0 Juan Carlos Navarro \n", - "11 26.0 44.0 Marcus Eriksson \n", - "12 17.0 69.0 Vitor Faverani \n", - "13 19.0 36.0 Jonathan Holmes \n", - "14 18.0 21.0 Moussa Diagne \n", - "15 10.0 11.0 Stefan Peno \n", - "16 2.0 5.0 Xavier Munford \n", - "17 2.0 9.0 Pau Ribas \n", - "18 0.0 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_totals(2017, level='E')" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -3058,7 +1609,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 54, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -3069,294 +1620,16 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 \n", - "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 120.0 230.0 0.522 54.0 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 130.0 320.0 0.406 42.0 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 87.0 189.0 0.460 54.0 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 64.0 138.0 0.464 25.0 \n", - "9 justin-doellman-1 27.0 NaN 572.0 96.0 195.0 0.492 29.0 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 58.0 97.0 0.598 0.0 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 72.0 185.0 0.389 32.0 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 44.0 77.0 0.571 2.0 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 18.0 43.0 0.419 0.0 \n", - "14 stefan-peno-1 22.0 NaN 143.0 8.0 28.0 0.286 2.0 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 20.0 38.0 0.526 9.0 \n", - "16 xavier-munford-1 11.0 NaN 77.0 7.0 18.0 0.389 3.0 \n", - "17 pau-ribas-1 3.0 NaN 43.0 6.0 15.0 0.400 5.0 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN 0.0 \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 319.0 0.307 ... 15.0 80.0 95.0 252.0 58.0 \n", - "1 3.0 0.333 ... 128.0 295.0 423.0 124.0 35.0 \n", - "2 204.0 0.417 ... 15.0 90.0 105.0 112.0 39.0 \n", - "3 124.0 0.395 ... 46.0 192.0 238.0 69.0 51.0 \n", - "4 169.0 0.420 ... 55.0 143.0 198.0 61.0 37.0 \n", - "5 133.0 0.406 ... 28.0 69.0 97.0 96.0 32.0 \n", - "6 136.0 0.309 ... 17.0 117.0 134.0 62.0 33.0 \n", - "7 128.0 0.422 ... 16.0 58.0 74.0 40.0 18.0 \n", - "8 62.0 0.403 ... 21.0 52.0 73.0 69.0 33.0 \n", - "9 55.0 0.527 ... 18.0 66.0 84.0 32.0 24.0 \n", - "10 0.0 NaN ... 70.0 124.0 194.0 33.0 14.0 \n", - "11 104.0 0.308 ... 3.0 25.0 28.0 48.0 15.0 \n", - "12 10.0 0.200 ... 17.0 51.0 68.0 7.0 5.0 \n", - "13 0.0 NaN ... 30.0 41.0 71.0 7.0 7.0 \n", - "14 15.0 0.133 ... 4.0 14.0 18.0 17.0 5.0 \n", - "15 20.0 0.450 ... 8.0 22.0 30.0 2.0 4.0 \n", - "16 9.0 0.333 ... 2.0 8.0 10.0 7.0 3.0 \n", - "17 12.0 0.417 ... 0.0 4.0 4.0 4.0 2.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 1.0 0.000 ... 0.0 0.0 0.0 0.0 0.0 \n", - "20 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 4.0 151.0 142.0 750.0 Tyrese Rice \n", - "1 36.0 99.0 135.0 661.0 Ante Tomic \n", - "2 3.0 71.0 100.0 509.0 Petteri Koponen \n", - "3 24.0 74.0 111.0 309.0 Victor Claver \n", - "4 15.0 45.0 115.0 513.0 Aleksandar Vezenkov \n", - "5 9.0 51.0 87.0 330.0 Brad Oleson \n", - "6 7.0 51.0 93.0 343.0 Stratos Perperoglou \n", - "7 7.0 24.0 73.0 245.0 Marcus Eriksson \n", - "8 3.0 46.0 75.0 175.0 Alex Renfroe \n", - "9 4.0 33.0 44.0 268.0 Justin Doellman \n", - "10 14.0 58.0 91.0 152.0 Joey Dorsey \n", - "11 0.0 36.0 39.0 208.0 Juan Carlos Navarro \n", - "12 2.0 28.0 32.0 124.0 Vitor Faverani \n", - "13 2.0 19.0 37.0 62.0 Moussa Diagne \n", - "14 1.0 17.0 28.0 24.0 Stefan Peno \n", - "15 4.0 20.0 30.0 59.0 Jonathan Holmes \n", - "16 2.0 16.0 11.0 17.0 Xavier Munford \n", - "17 0.0 3.0 3.0 20.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 2.0 Rodions Kurucs \n", - "20 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", - "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", - "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", - "5 brad-oleson-1 24.0 NaN 519.0 50.0 102.0 0.490 20.0 58.0 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 53.0 139.0 0.381 19.0 53.0 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 24.0 58.0 0.414 12.0 31.0 \n", - "8 justin-doellman-1 15.0 NaN 299.0 42.0 94.0 0.447 15.0 28.0 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 34.0 62.0 0.548 0.0 0.0 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 30.0 94.0 0.319 16.0 56.0 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 16.0 50.0 0.320 12.0 34.0 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 25.0 45.0 0.556 1.0 7.0 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 11.0 23.0 0.478 4.0 12.0 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 5.0 13.0 0.385 0.0 0.0 \n", - "15 stefan-peno-1 10.0 NaN 48.0 3.0 8.0 0.375 1.0 3.0 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.0 9.0 0.222 1.0 3.0 \n", - "17 pau-ribas-1 2.0 NaN 20.0 3.0 7.0 0.429 3.0 6.0 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 1.0 2.0 0.500 0.0 1.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk tov \\\n", - "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", - "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", - "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", - "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", - "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", - "5 0.345 ... 11.0 33.0 44.0 47.0 14.0 5.0 20.0 \n", - "6 0.358 ... 8.0 61.0 69.0 34.0 16.0 4.0 23.0 \n", - "7 0.387 ... 10.0 26.0 36.0 28.0 17.0 0.0 24.0 \n", - "8 0.536 ... 10.0 37.0 47.0 18.0 13.0 2.0 14.0 \n", - "9 NaN ... 46.0 61.0 107.0 14.0 9.0 5.0 30.0 \n", - "10 0.286 ... 1.0 16.0 17.0 28.0 7.0 0.0 28.0 \n", - "11 0.353 ... 7.0 20.0 27.0 7.0 8.0 3.0 11.0 \n", - "12 0.143 ... 8.0 30.0 38.0 5.0 3.0 2.0 15.0 \n", - "13 0.333 ... 8.0 11.0 19.0 2.0 2.0 1.0 11.0 \n", - "14 NaN ... 8.0 20.0 28.0 3.0 2.0 1.0 7.0 \n", - "15 0.333 ... 2.0 4.0 6.0 5.0 3.0 1.0 6.0 \n", - "16 0.333 ... 2.0 3.0 5.0 2.0 1.0 0.0 9.0 \n", - "17 0.500 ... 0.0 1.0 1.0 1.0 1.0 0.0 1.0 \n", - "18 0.000 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf pts player_name \n", - "0 63.0 389.0 Tyrese Rice \n", - "1 62.0 256.0 Ante Tomic \n", - "2 52.0 274.0 Petteri Koponen \n", - "3 45.0 163.0 Victor Claver \n", - "4 46.0 226.0 Aleksandar Vezenkov \n", - "5 40.0 128.0 Brad Oleson \n", - "6 33.0 140.0 Stratos Perperoglou \n", - "7 34.0 67.0 Alex Renfroe \n", - "8 23.0 117.0 Justin Doellman \n", - "9 41.0 93.0 Joey Dorsey \n", - "10 20.0 91.0 Juan Carlos Navarro \n", - "11 26.0 44.0 Marcus Eriksson \n", - "12 17.0 69.0 Vitor Faverani \n", - "13 19.0 36.0 Jonathan Holmes \n", - "14 18.0 21.0 Moussa Diagne \n", - "15 10.0 11.0 Stefan Peno \n", - "16 2.0 5.0 Xavier Munford \n", - "17 2.0 9.0 Pau Ribas \n", - "18 0.0 2.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", - "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", - "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", - "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", - "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", - "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", - "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", - "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", - "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", - "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", - "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", - "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", - "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", - "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", - "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", - "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", - "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", - "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", - "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", - "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", - "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", - "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", - "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", - "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", - "1 16.0 43.0 73.0 405.0 Ante Tomic \n", - "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", - "3 4.0 31.0 47.0 202.0 Brad Oleson \n", - "4 16.0 41.0 66.0 146.0 Victor Claver \n", - "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", - "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", - "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", - "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", - "9 2.0 19.0 21.0 151.0 Justin Doellman \n", - "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", - "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", - "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", - "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", - "14 0.0 11.0 18.0 13.0 Stefan Peno \n", - "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", - "16 2.0 7.0 9.0 12.0 Xavier Munford \n", - "17 0.0 2.0 1.0 11.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'C'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", - "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", - "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", - "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 81.0 183.0 0.443 30.0 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 77.0 181.0 0.425 23.0 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 71.0 139.0 0.511 42.0 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 40.0 80.0 0.500 13.0 \n", - "9 justin-doellman-1 12.0 8.0 273.0 54.0 101.0 0.535 14.0 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 24.0 35.0 0.686 0.0 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 42.0 91.0 0.462 16.0 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 13.0 30.0 0.433 0.0 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 19.0 32.0 0.594 1.0 \n", - "14 stefan-peno-1 12.0 0.0 95.0 5.0 20.0 0.250 1.0 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 9.0 15.0 0.600 5.0 \n", - "16 xavier-munford-1 6.0 0.0 43.0 5.0 9.0 0.556 2.0 \n", - "17 pau-ribas-1 1.0 0.0 23.0 3.0 8.0 0.375 2.0 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN 0.0 \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 1.0 0.000 0.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl \\\n", - "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 \n", - "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 \n", - "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 \n", - "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 \n", - "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 \n", - "5 85.0 0.353 ... 10.0 49.0 59.0 61.0 19.0 \n", - "6 83.0 0.277 ... 9.0 56.0 65.0 28.0 17.0 \n", - "7 94.0 0.447 ... 9.0 38.0 47.0 33.0 10.0 \n", - "8 31.0 0.419 ... 11.0 26.0 37.0 41.0 16.0 \n", - "9 27.0 0.519 ... 8.0 29.0 37.0 14.0 11.0 \n", - "10 0.0 NaN ... 24.0 63.0 87.0 19.0 5.0 \n", - "11 48.0 0.333 ... 2.0 9.0 11.0 20.0 8.0 \n", - "12 0.0 NaN ... 22.0 21.0 43.0 4.0 5.0 \n", - "13 3.0 0.333 ... 9.0 21.0 30.0 2.0 2.0 \n", - "14 12.0 0.083 ... 2.0 10.0 12.0 12.0 2.0 \n", - "15 8.0 0.625 ... 0.0 11.0 11.0 0.0 2.0 \n", - "16 6.0 0.333 ... 0.0 5.0 5.0 5.0 2.0 \n", - "17 6.0 0.333 ... 0.0 3.0 3.0 3.0 1.0 \n", - "18 0.0 NaN ... 0.0 0.0 0.0 0.0 1.0 \n", - "19 0.0 NaN ... 1.0 1.0 2.0 0.0 0.0 \n", - "\n", - " blk tov pf pts player_name \n", - "0 1.0 74.0 79.0 361.0 Tyrese Rice \n", - "1 16.0 43.0 73.0 405.0 Ante Tomic \n", - "2 9.0 26.0 69.0 287.0 Aleksandar Vezenkov \n", - "3 4.0 31.0 47.0 202.0 Brad Oleson \n", - "4 16.0 41.0 66.0 146.0 Victor Claver \n", - "5 3.0 35.0 48.0 235.0 Petteri Koponen \n", - "6 3.0 28.0 60.0 203.0 Stratos Perperoglou \n", - "7 4.0 13.0 47.0 201.0 Marcus Eriksson \n", - "8 3.0 22.0 41.0 108.0 Alex Renfroe \n", - "9 2.0 19.0 21.0 151.0 Justin Doellman \n", - "10 9.0 28.0 50.0 59.0 Joey Dorsey \n", - "11 0.0 8.0 19.0 117.0 Juan Carlos Navarro \n", - "12 1.0 12.0 19.0 41.0 Moussa Diagne \n", - "13 0.0 13.0 15.0 55.0 Vitor Faverani \n", - "14 0.0 11.0 18.0 13.0 Stefan Peno \n", - "15 3.0 9.0 11.0 23.0 Jonathan Holmes \n", - "16 2.0 7.0 9.0 12.0 Xavier Munford \n", - "17 0.0 2.0 1.0 11.0 Pau Ribas \n", - "18 0.0 3.0 1.0 0.0 Pol Figueras \n", - "19 0.0 0.0 0.0 1.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_totals(2017, level='C')" ] }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -3554,7 +1827,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 56, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -3572,386 +1845,16 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", - "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", - "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", - "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", - "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", - "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.1 6.8 0.307 ... 0.3 \n", - "1 0.0 0.1 0.333 ... 3.4 \n", - "2 2.6 6.1 0.417 ... 0.5 \n", - "3 1.5 3.8 0.395 ... 1.4 \n", - "4 2.2 5.3 0.420 ... 1.7 \n", - "5 1.7 4.3 0.406 ... 0.9 \n", - "6 1.5 5.0 0.309 ... 0.6 \n", - "7 2.9 6.9 0.422 ... 0.9 \n", - "8 1.3 3.3 0.403 ... 1.1 \n", - "9 1.8 3.5 0.527 ... 1.1 \n", - "10 0.0 0.0 NaN ... 4.5 \n", - "11 2.5 8.0 0.308 ... 0.2 \n", - "12 0.3 1.5 0.200 ... 2.5 \n", - "13 0.0 0.0 NaN ... 5.4 \n", - "14 0.5 3.8 0.133 ... 1.0 \n", - "15 2.3 5.0 0.450 ... 2.0 \n", - "16 1.4 4.2 0.333 ... 0.9 \n", - "17 4.2 10.0 0.417 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 12.0 0.000 ... 0.0 \n", - "20 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", - "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", - "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", - "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", - "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", - "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", - "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", - "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", - "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", - "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", - "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", - "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", - "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", - "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", - "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", - "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", - "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.0 16.1 Tyrese Rice \n", - "1 3.6 17.4 Ante Tomic \n", - "2 3.0 15.3 Petteri Koponen \n", - "3 3.4 9.4 Victor Claver \n", - "4 3.6 16.0 Aleksandar Vezenkov \n", - "5 2.8 10.6 Brad Oleson \n", - "6 3.4 12.5 Stratos Perperoglou \n", - "7 3.9 13.1 Marcus Eriksson \n", - "8 4.0 9.4 Alex Renfroe \n", - "9 2.8 16.9 Justin Doellman \n", - "10 5.9 9.8 Joey Dorsey \n", - "11 3.0 16.0 Juan Carlos Navarro \n", - "12 4.8 18.6 Vitor Faverani \n", - "13 6.6 11.1 Moussa Diagne \n", - "14 7.0 6.0 Stefan Peno \n", - "15 7.6 14.9 Jonathan Holmes \n", - "16 5.1 7.9 Xavier Munford \n", - "17 2.5 16.7 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 24.0 Rodions Kurucs \n", - "20 0.0 12.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", - "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", - "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", - "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", - "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", - "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", - "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.2 7.0 0.320 ... 0.3 \n", - "1 0.0 0.1 0.000 ... 3.6 \n", - "2 3.2 7.0 0.462 ... 0.3 \n", - "3 1.4 3.7 0.377 ... 1.4 \n", - "4 2.2 4.6 0.479 ... 1.6 \n", - "5 1.4 4.0 0.345 ... 0.8 \n", - "6 1.5 4.1 0.358 ... 0.6 \n", - "7 1.4 3.7 0.387 ... 1.2 \n", - "8 1.8 3.4 0.536 ... 1.2 \n", - "9 0.0 0.0 NaN ... 5.7 \n", - "10 2.3 8.2 0.286 ... 0.1 \n", - "11 2.0 5.6 0.353 ... 1.2 \n", - "12 0.3 1.8 0.143 ... 2.1 \n", - "13 1.6 4.9 0.333 ... 3.2 \n", - "14 0.0 0.0 NaN ... 3.6 \n", - "15 0.7 2.3 0.333 ... 1.5 \n", - "16 1.1 3.2 0.333 ... 2.1 \n", - "17 5.4 10.8 0.500 ... 0.0 \n", - "18 0.0 12.0 0.000 ... 0.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", - "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", - "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", - "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", - "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", - "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", - "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", - "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", - "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", - "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", - "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", - "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", - "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", - "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", - "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", - "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", - "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 2.6 15.8 Tyrese Rice \n", - "1 3.5 14.6 Ante Tomic \n", - "2 3.1 16.2 Petteri Koponen \n", - "3 2.7 9.9 Victor Claver \n", - "4 3.0 14.7 Aleksandar Vezenkov \n", - "5 2.8 8.9 Brad Oleson \n", - "6 2.6 11.0 Stratos Perperoglou \n", - "7 4.1 8.0 Alex Renfroe \n", - "8 2.8 14.1 Justin Doellman \n", - "9 5.1 11.5 Joey Dorsey \n", - "10 2.9 13.3 Juan Carlos Navarro \n", - "11 4.3 7.3 Marcus Eriksson \n", - "12 4.4 17.9 Vitor Faverani \n", - "13 7.7 14.6 Jonathan Holmes \n", - "14 8.2 9.6 Moussa Diagne \n", - "15 7.5 8.2 Stefan Peno \n", - "16 2.1 5.3 Xavier Munford \n", - "17 3.6 16.2 Pau Ribas \n", - "18 0.0 24.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", - "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", - "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", - "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", - "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", - "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.0 6.7 0.293 ... 0.3 \n", - "1 0.0 0.1 0.500 ... 3.2 \n", - "2 2.2 5.8 0.378 ... 1.8 \n", - "3 2.0 4.5 0.453 ... 1.0 \n", - "4 1.6 3.8 0.413 ... 1.4 \n", - "5 1.8 5.2 0.353 ... 0.6 \n", - "6 1.6 5.6 0.277 ... 0.6 \n", - "7 3.3 7.5 0.447 ... 0.7 \n", - "8 1.3 3.0 0.419 ... 1.1 \n", - "9 1.8 3.6 0.519 ... 1.1 \n", - "10 0.0 0.0 NaN ... 3.3 \n", - "11 2.6 7.8 0.333 ... 0.3 \n", - "12 0.0 0.0 NaN ... 6.5 \n", - "13 0.4 1.1 0.333 ... 3.2 \n", - "14 0.4 4.5 0.083 ... 0.8 \n", - "15 3.3 5.3 0.625 ... 0.0 \n", - "16 1.7 5.0 0.333 ... 0.0 \n", - "17 3.1 9.4 0.333 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", - "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", - "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", - "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", - "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", - "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", - "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", - "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", - "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", - "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", - "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", - "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", - "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", - "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", - "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", - "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", - "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", - "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.6 16.4 Tyrese Rice \n", - "1 3.6 19.9 Ante Tomic \n", - "2 4.1 17.1 Aleksandar Vezenkov \n", - "3 2.8 12.1 Brad Oleson \n", - "4 4.0 8.9 Victor Claver \n", - "5 2.9 14.4 Petteri Koponen \n", - "6 4.1 13.8 Stratos Perperoglou \n", - "7 3.7 15.9 Marcus Eriksson \n", - "8 4.0 10.6 Alex Renfroe \n", - "9 2.8 19.9 Justin Doellman \n", - "10 6.8 8.0 Joey Dorsey \n", - "11 3.1 19.0 Juan Carlos Navarro \n", - "12 5.6 12.1 Moussa Diagne \n", - "13 5.3 19.6 Vitor Faverani \n", - "14 6.8 4.9 Stefan Peno \n", - "15 7.3 15.3 Jonathan Holmes \n", - "16 7.5 10.0 Xavier Munford \n", - "17 1.6 17.2 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 12.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'B'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", - "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", - "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", - "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", - "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", - "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.1 6.8 0.307 ... 0.3 \n", - "1 0.0 0.1 0.333 ... 3.4 \n", - "2 2.6 6.1 0.417 ... 0.5 \n", - "3 1.5 3.8 0.395 ... 1.4 \n", - "4 2.2 5.3 0.420 ... 1.7 \n", - "5 1.7 4.3 0.406 ... 0.9 \n", - "6 1.5 5.0 0.309 ... 0.6 \n", - "7 2.9 6.9 0.422 ... 0.9 \n", - "8 1.3 3.3 0.403 ... 1.1 \n", - "9 1.8 3.5 0.527 ... 1.1 \n", - "10 0.0 0.0 NaN ... 4.5 \n", - "11 2.5 8.0 0.308 ... 0.2 \n", - "12 0.3 1.5 0.200 ... 2.5 \n", - "13 0.0 0.0 NaN ... 5.4 \n", - "14 0.5 3.8 0.133 ... 1.0 \n", - "15 2.3 5.0 0.450 ... 2.0 \n", - "16 1.4 4.2 0.333 ... 0.9 \n", - "17 4.2 10.0 0.417 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 12.0 0.000 ... 0.0 \n", - "20 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", - "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", - "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", - "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", - "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", - "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", - "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", - "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", - "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", - "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", - "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", - "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", - "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", - "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", - "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", - "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", - "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.0 16.1 Tyrese Rice \n", - "1 3.6 17.4 Ante Tomic \n", - "2 3.0 15.3 Petteri Koponen \n", - "3 3.4 9.4 Victor Claver \n", - "4 3.6 16.0 Aleksandar Vezenkov \n", - "5 2.8 10.6 Brad Oleson \n", - "6 3.4 12.5 Stratos Perperoglou \n", - "7 3.9 13.1 Marcus Eriksson \n", - "8 4.0 9.4 Alex Renfroe \n", - "9 2.8 16.9 Justin Doellman \n", - "10 5.9 9.8 Joey Dorsey \n", - "11 3.0 16.0 Juan Carlos Navarro \n", - "12 4.8 18.6 Vitor Faverani \n", - "13 6.6 11.1 Moussa Diagne \n", - "14 7.0 6.0 Stefan Peno \n", - "15 7.6 14.9 Jonathan Holmes \n", - "16 5.1 7.9 Xavier Munford \n", - "17 2.5 16.7 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 24.0 Rodions Kurucs \n", - "20 0.0 12.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per36(2017, level='B')" ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -4156,7 +2059,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 58, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -4167,378 +2070,16 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", - "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", - "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", - "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", - "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", - "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.1 6.8 0.307 ... 0.3 \n", - "1 0.0 0.1 0.333 ... 3.4 \n", - "2 2.6 6.1 0.417 ... 0.5 \n", - "3 1.5 3.8 0.395 ... 1.4 \n", - "4 2.2 5.3 0.420 ... 1.7 \n", - "5 1.7 4.3 0.406 ... 0.9 \n", - "6 1.5 5.0 0.309 ... 0.6 \n", - "7 2.9 6.9 0.422 ... 0.9 \n", - "8 1.3 3.3 0.403 ... 1.1 \n", - "9 1.8 3.5 0.527 ... 1.1 \n", - "10 0.0 0.0 NaN ... 4.5 \n", - "11 2.5 8.0 0.308 ... 0.2 \n", - "12 0.3 1.5 0.200 ... 2.5 \n", - "13 0.0 0.0 NaN ... 5.4 \n", - "14 0.5 3.8 0.133 ... 1.0 \n", - "15 2.3 5.0 0.450 ... 2.0 \n", - "16 1.4 4.2 0.333 ... 0.9 \n", - "17 4.2 10.0 0.417 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 12.0 0.000 ... 0.0 \n", - "20 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", - "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", - "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", - "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", - "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", - "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", - "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", - "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", - "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", - "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", - "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", - "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", - "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", - "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", - "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", - "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", - "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.0 16.1 Tyrese Rice \n", - "1 3.6 17.4 Ante Tomic \n", - "2 3.0 15.3 Petteri Koponen \n", - "3 3.4 9.4 Victor Claver \n", - "4 3.6 16.0 Aleksandar Vezenkov \n", - "5 2.8 10.6 Brad Oleson \n", - "6 3.4 12.5 Stratos Perperoglou \n", - "7 3.9 13.1 Marcus Eriksson \n", - "8 4.0 9.4 Alex Renfroe \n", - "9 2.8 16.9 Justin Doellman \n", - "10 5.9 9.8 Joey Dorsey \n", - "11 3.0 16.0 Juan Carlos Navarro \n", - "12 4.8 18.6 Vitor Faverani \n", - "13 6.6 11.1 Moussa Diagne \n", - "14 7.0 6.0 Stefan Peno \n", - "15 7.6 14.9 Jonathan Holmes \n", - "16 5.1 7.9 Xavier Munford \n", - "17 2.5 16.7 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 24.0 Rodions Kurucs \n", - "20 0.0 12.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", - "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", - "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", - "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", - "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", - "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", - "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.2 7.0 0.320 ... 0.3 \n", - "1 0.0 0.1 0.000 ... 3.6 \n", - "2 3.2 7.0 0.462 ... 0.3 \n", - "3 1.4 3.7 0.377 ... 1.4 \n", - "4 2.2 4.6 0.479 ... 1.6 \n", - "5 1.4 4.0 0.345 ... 0.8 \n", - "6 1.5 4.1 0.358 ... 0.6 \n", - "7 1.4 3.7 0.387 ... 1.2 \n", - "8 1.8 3.4 0.536 ... 1.2 \n", - "9 0.0 0.0 NaN ... 5.7 \n", - "10 2.3 8.2 0.286 ... 0.1 \n", - "11 2.0 5.6 0.353 ... 1.2 \n", - "12 0.3 1.8 0.143 ... 2.1 \n", - "13 1.6 4.9 0.333 ... 3.2 \n", - "14 0.0 0.0 NaN ... 3.6 \n", - "15 0.7 2.3 0.333 ... 1.5 \n", - "16 1.1 3.2 0.333 ... 2.1 \n", - "17 5.4 10.8 0.500 ... 0.0 \n", - "18 0.0 12.0 0.000 ... 0.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", - "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", - "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", - "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", - "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", - "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", - "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", - "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", - "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", - "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", - "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", - "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", - "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", - "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", - "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", - "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", - "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 2.6 15.8 Tyrese Rice \n", - "1 3.5 14.6 Ante Tomic \n", - "2 3.1 16.2 Petteri Koponen \n", - "3 2.7 9.9 Victor Claver \n", - "4 3.0 14.7 Aleksandar Vezenkov \n", - "5 2.8 8.9 Brad Oleson \n", - "6 2.6 11.0 Stratos Perperoglou \n", - "7 4.1 8.0 Alex Renfroe \n", - "8 2.8 14.1 Justin Doellman \n", - "9 5.1 11.5 Joey Dorsey \n", - "10 2.9 13.3 Juan Carlos Navarro \n", - "11 4.3 7.3 Marcus Eriksson \n", - "12 4.4 17.9 Vitor Faverani \n", - "13 7.7 14.6 Jonathan Holmes \n", - "14 8.2 9.6 Moussa Diagne \n", - "15 7.5 8.2 Stefan Peno \n", - "16 2.1 5.3 Xavier Munford \n", - "17 3.6 16.2 Pau Ribas \n", - "18 0.0 24.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", - "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", - "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", - "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", - "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", - "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.0 6.7 0.293 ... 0.3 \n", - "1 0.0 0.1 0.500 ... 3.2 \n", - "2 2.2 5.8 0.378 ... 1.8 \n", - "3 2.0 4.5 0.453 ... 1.0 \n", - "4 1.6 3.8 0.413 ... 1.4 \n", - "5 1.8 5.2 0.353 ... 0.6 \n", - "6 1.6 5.6 0.277 ... 0.6 \n", - "7 3.3 7.5 0.447 ... 0.7 \n", - "8 1.3 3.0 0.419 ... 1.1 \n", - "9 1.8 3.6 0.519 ... 1.1 \n", - "10 0.0 0.0 NaN ... 3.3 \n", - "11 2.6 7.8 0.333 ... 0.3 \n", - "12 0.0 0.0 NaN ... 6.5 \n", - "13 0.4 1.1 0.333 ... 3.2 \n", - "14 0.4 4.5 0.083 ... 0.8 \n", - "15 3.3 5.3 0.625 ... 0.0 \n", - "16 1.7 5.0 0.333 ... 0.0 \n", - "17 3.1 9.4 0.333 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", - "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", - "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", - "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", - "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", - "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", - "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", - "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", - "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", - "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", - "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", - "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", - "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", - "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", - "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", - "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", - "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", - "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.6 16.4 Tyrese Rice \n", - "1 3.6 19.9 Ante Tomic \n", - "2 4.1 17.1 Aleksandar Vezenkov \n", - "3 2.8 12.1 Brad Oleson \n", - "4 4.0 8.9 Victor Claver \n", - "5 2.9 14.4 Petteri Koponen \n", - "6 4.1 13.8 Stratos Perperoglou \n", - "7 3.7 15.9 Marcus Eriksson \n", - "8 4.0 10.6 Alex Renfroe \n", - "9 2.8 19.9 Justin Doellman \n", - "10 6.8 8.0 Joey Dorsey \n", - "11 3.1 19.0 Juan Carlos Navarro \n", - "12 5.6 12.1 Moussa Diagne \n", - "13 5.3 19.6 Vitor Faverani \n", - "14 6.8 4.9 Stefan Peno \n", - "15 7.3 15.3 Jonathan Holmes \n", - "16 7.5 10.0 Xavier Munford \n", - "17 1.6 17.2 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 12.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'E'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", - "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", - "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", - "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", - "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", - "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", - "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.2 7.0 0.320 ... 0.3 \n", - "1 0.0 0.1 0.000 ... 3.6 \n", - "2 3.2 7.0 0.462 ... 0.3 \n", - "3 1.4 3.7 0.377 ... 1.4 \n", - "4 2.2 4.6 0.479 ... 1.6 \n", - "5 1.4 4.0 0.345 ... 0.8 \n", - "6 1.5 4.1 0.358 ... 0.6 \n", - "7 1.4 3.7 0.387 ... 1.2 \n", - "8 1.8 3.4 0.536 ... 1.2 \n", - "9 0.0 0.0 NaN ... 5.7 \n", - "10 2.3 8.2 0.286 ... 0.1 \n", - "11 2.0 5.6 0.353 ... 1.2 \n", - "12 0.3 1.8 0.143 ... 2.1 \n", - "13 1.6 4.9 0.333 ... 3.2 \n", - "14 0.0 0.0 NaN ... 3.6 \n", - "15 0.7 2.3 0.333 ... 1.5 \n", - "16 1.1 3.2 0.333 ... 2.1 \n", - "17 5.4 10.8 0.500 ... 0.0 \n", - "18 0.0 12.0 0.000 ... 0.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", - "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", - "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", - "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", - "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", - "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", - "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", - "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", - "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", - "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", - "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", - "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", - "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", - "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", - "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", - "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", - "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 2.6 15.8 Tyrese Rice \n", - "1 3.5 14.6 Ante Tomic \n", - "2 3.1 16.2 Petteri Koponen \n", - "3 2.7 9.9 Victor Claver \n", - "4 3.0 14.7 Aleksandar Vezenkov \n", - "5 2.8 8.9 Brad Oleson \n", - "6 2.6 11.0 Stratos Perperoglou \n", - "7 4.1 8.0 Alex Renfroe \n", - "8 2.8 14.1 Justin Doellman \n", - "9 5.1 11.5 Joey Dorsey \n", - "10 2.9 13.3 Juan Carlos Navarro \n", - "11 4.3 7.3 Marcus Eriksson \n", - "12 4.4 17.9 Vitor Faverani \n", - "13 7.7 14.6 Jonathan Holmes \n", - "14 8.2 9.6 Moussa Diagne \n", - "15 7.5 8.2 Stefan Peno \n", - "16 2.1 5.3 Xavier Munford \n", - "17 3.6 16.2 Pau Ribas \n", - "18 0.0 24.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per36(2017, level='E')" ] }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -4743,7 +2284,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 60, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -4754,382 +2295,16 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", - "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", - "5 brad-oleson-1 53.0 NaN 1122.0 3.9 7.4 0.522 \n", - "6 stratos-perperoglou-1 48.0 NaN 989.0 4.7 11.6 0.406 \n", - "7 marcus-eriksson-1 52.0 NaN 671.0 4.7 10.1 0.460 \n", - "8 alex-renfroe-1 37.0 NaN 669.0 3.4 7.4 0.464 \n", - "9 justin-doellman-1 27.0 NaN 572.0 6.0 12.3 0.492 \n", - "10 joey-dorsey-1 33.0 NaN 556.0 3.8 6.3 0.598 \n", - "11 juan-carlos-navarro-1 32.0 NaN 469.0 5.5 14.2 0.389 \n", - "12 vitor-faverani-1 15.0 NaN 240.0 6.6 11.5 0.571 \n", - "13 moussa-diagne-1 23.0 NaN 201.0 3.2 7.7 0.419 \n", - "14 stefan-peno-1 22.0 NaN 143.0 2.0 7.0 0.286 \n", - "15 jonathan-holmes-1 10.0 NaN 143.0 5.0 9.6 0.526 \n", - "16 xavier-munford-1 11.0 NaN 77.0 3.3 8.4 0.389 \n", - "17 pau-ribas-1 3.0 NaN 43.0 5.0 12.6 0.400 \n", - "18 pol-figueras-1 2.0 NaN 12.0 0.0 0.0 NaN \n", - "19 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "20 wesley-sena-1 1.0 NaN 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.1 6.8 0.307 ... 0.3 \n", - "1 0.0 0.1 0.333 ... 3.4 \n", - "2 2.6 6.1 0.417 ... 0.5 \n", - "3 1.5 3.8 0.395 ... 1.4 \n", - "4 2.2 5.3 0.420 ... 1.7 \n", - "5 1.7 4.3 0.406 ... 0.9 \n", - "6 1.5 5.0 0.309 ... 0.6 \n", - "7 2.9 6.9 0.422 ... 0.9 \n", - "8 1.3 3.3 0.403 ... 1.1 \n", - "9 1.8 3.5 0.527 ... 1.1 \n", - "10 0.0 0.0 NaN ... 4.5 \n", - "11 2.5 8.0 0.308 ... 0.2 \n", - "12 0.3 1.5 0.200 ... 2.5 \n", - "13 0.0 0.0 NaN ... 5.4 \n", - "14 0.5 3.8 0.133 ... 1.0 \n", - "15 2.3 5.0 0.450 ... 2.0 \n", - "16 1.4 4.2 0.333 ... 0.9 \n", - "17 4.2 10.0 0.417 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 12.0 0.000 ... 0.0 \n", - "20 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", - "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", - "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", - "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", - "5 2.2 3.1 3.1 1.0 0.3 1.6 \n", - "6 4.3 4.9 2.3 1.2 0.3 1.9 \n", - "7 3.1 4.0 2.1 1.0 0.4 1.3 \n", - "8 2.8 3.9 3.7 1.8 0.2 2.5 \n", - "9 4.2 5.3 2.0 1.5 0.3 2.1 \n", - "10 8.0 12.6 2.1 0.9 0.9 3.8 \n", - "11 1.9 2.1 3.7 1.2 0.0 2.8 \n", - "12 7.7 10.2 1.0 0.7 0.3 4.2 \n", - "13 7.3 12.7 1.3 1.3 0.4 3.4 \n", - "14 3.5 4.5 4.3 1.3 0.3 4.3 \n", - "15 5.5 7.6 0.5 1.0 1.0 5.0 \n", - "16 3.7 4.7 3.3 1.4 0.9 7.5 \n", - "17 3.3 3.3 3.3 1.7 0.0 2.5 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "20 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.0 16.1 Tyrese Rice \n", - "1 3.6 17.4 Ante Tomic \n", - "2 3.0 15.3 Petteri Koponen \n", - "3 3.4 9.4 Victor Claver \n", - "4 3.6 16.0 Aleksandar Vezenkov \n", - "5 2.8 10.6 Brad Oleson \n", - "6 3.4 12.5 Stratos Perperoglou \n", - "7 3.9 13.1 Marcus Eriksson \n", - "8 4.0 9.4 Alex Renfroe \n", - "9 2.8 16.9 Justin Doellman \n", - "10 5.9 9.8 Joey Dorsey \n", - "11 3.0 16.0 Juan Carlos Navarro \n", - "12 4.8 18.6 Vitor Faverani \n", - "13 6.6 11.1 Moussa Diagne \n", - "14 7.0 6.0 Stefan Peno \n", - "15 7.6 14.9 Jonathan Holmes \n", - "16 5.1 7.9 Xavier Munford \n", - "17 2.5 16.7 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 24.0 Rodions Kurucs \n", - "20 0.0 12.0 Wesley Sena \n", - "\n", - "[21 rows x 26 columns], ((, 2017, 'E'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", - "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", - "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", - "5 brad-oleson-1 24.0 NaN 519.0 3.5 7.1 0.490 \n", - "6 stratos-perperoglou-1 22.0 NaN 460.0 4.1 10.9 0.381 \n", - "7 alex-renfroe-1 17.0 NaN 301.0 2.9 6.9 0.414 \n", - "8 justin-doellman-1 15.0 NaN 299.0 5.1 11.3 0.447 \n", - "9 joey-dorsey-1 17.0 NaN 292.0 4.2 7.6 0.548 \n", - "10 juan-carlos-navarro-1 16.0 NaN 247.0 4.4 13.7 0.319 \n", - "11 marcus-eriksson-1 22.0 NaN 217.0 2.7 8.3 0.320 \n", - "12 vitor-faverani-1 9.0 NaN 139.0 6.5 11.7 0.556 \n", - "13 jonathan-holmes-1 7.0 NaN 89.0 4.4 9.3 0.478 \n", - "14 moussa-diagne-1 8.0 NaN 79.0 2.3 5.9 0.385 \n", - "15 stefan-peno-1 10.0 NaN 48.0 2.3 6.0 0.375 \n", - "16 xavier-munford-1 5.0 NaN 34.0 2.1 9.5 0.222 \n", - "17 pau-ribas-1 2.0 NaN 20.0 5.4 12.6 0.429 \n", - "18 rodions-kurucs-1 1.0 NaN 3.0 12.0 24.0 0.500 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.2 7.0 0.320 ... 0.3 \n", - "1 0.0 0.1 0.000 ... 3.6 \n", - "2 3.2 7.0 0.462 ... 0.3 \n", - "3 1.4 3.7 0.377 ... 1.4 \n", - "4 2.2 4.6 0.479 ... 1.6 \n", - "5 1.4 4.0 0.345 ... 0.8 \n", - "6 1.5 4.1 0.358 ... 0.6 \n", - "7 1.4 3.7 0.387 ... 1.2 \n", - "8 1.8 3.4 0.536 ... 1.2 \n", - "9 0.0 0.0 NaN ... 5.7 \n", - "10 2.3 8.2 0.286 ... 0.1 \n", - "11 2.0 5.6 0.353 ... 1.2 \n", - "12 0.3 1.8 0.143 ... 2.1 \n", - "13 1.6 4.9 0.333 ... 3.2 \n", - "14 0.0 0.0 NaN ... 3.6 \n", - "15 0.7 2.3 0.333 ... 1.5 \n", - "16 1.1 3.2 0.333 ... 2.1 \n", - "17 5.4 10.8 0.500 ... 0.0 \n", - "18 0.0 12.0 0.000 ... 0.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", - "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", - "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", - "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", - "5 2.3 3.1 3.3 1.0 0.3 1.4 \n", - "6 4.8 5.4 2.7 1.3 0.3 1.8 \n", - "7 3.1 4.3 3.3 2.0 0.0 2.9 \n", - "8 4.5 5.7 2.2 1.6 0.2 1.7 \n", - "9 7.5 13.2 1.7 1.1 0.6 3.7 \n", - "10 2.3 2.5 4.1 1.0 0.0 4.1 \n", - "11 3.3 4.5 1.2 1.3 0.5 1.8 \n", - "12 7.8 9.8 1.3 0.8 0.5 3.9 \n", - "13 4.4 7.7 0.8 0.8 0.4 4.4 \n", - "14 9.1 12.8 1.4 0.9 0.5 3.2 \n", - "15 3.0 4.5 3.7 2.3 0.7 4.5 \n", - "16 3.2 5.3 2.1 1.1 0.0 9.5 \n", - "17 1.8 1.8 1.8 1.8 0.0 1.8 \n", - "18 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 2.6 15.8 Tyrese Rice \n", - "1 3.5 14.6 Ante Tomic \n", - "2 3.1 16.2 Petteri Koponen \n", - "3 2.7 9.9 Victor Claver \n", - "4 3.0 14.7 Aleksandar Vezenkov \n", - "5 2.8 8.9 Brad Oleson \n", - "6 2.6 11.0 Stratos Perperoglou \n", - "7 4.1 8.0 Alex Renfroe \n", - "8 2.8 14.1 Justin Doellman \n", - "9 5.1 11.5 Joey Dorsey \n", - "10 2.9 13.3 Juan Carlos Navarro \n", - "11 4.3 7.3 Marcus Eriksson \n", - "12 4.4 17.9 Vitor Faverani \n", - "13 7.7 14.6 Jonathan Holmes \n", - "14 8.2 9.6 Moussa Diagne \n", - "15 7.5 8.2 Stefan Peno \n", - "16 2.1 5.3 Xavier Munford \n", - "17 3.6 16.2 Pau Ribas \n", - "18 0.0 24.0 Rodions Kurucs \n", - "\n", - "[19 rows x 26 columns], ((, 2017, 'C'), frozenset()): player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", - "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", - "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", - "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", - "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", - "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.0 6.7 0.293 ... 0.3 \n", - "1 0.0 0.1 0.500 ... 3.2 \n", - "2 2.2 5.8 0.378 ... 1.8 \n", - "3 2.0 4.5 0.453 ... 1.0 \n", - "4 1.6 3.8 0.413 ... 1.4 \n", - "5 1.8 5.2 0.353 ... 0.6 \n", - "6 1.6 5.6 0.277 ... 0.6 \n", - "7 3.3 7.5 0.447 ... 0.7 \n", - "8 1.3 3.0 0.419 ... 1.1 \n", - "9 1.8 3.6 0.519 ... 1.1 \n", - "10 0.0 0.0 NaN ... 3.3 \n", - "11 2.6 7.8 0.333 ... 0.3 \n", - "12 0.0 0.0 NaN ... 6.5 \n", - "13 0.4 1.1 0.333 ... 3.2 \n", - "14 0.4 4.5 0.083 ... 0.8 \n", - "15 3.3 5.3 0.625 ... 0.0 \n", - "16 1.7 5.0 0.333 ... 0.0 \n", - "17 3.1 9.4 0.333 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", - "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", - "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", - "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", - "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", - "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", - "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", - "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", - "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", - "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", - "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", - "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", - "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", - "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", - "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", - "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", - "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", - "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.6 16.4 Tyrese Rice \n", - "1 3.6 19.9 Ante Tomic \n", - "2 4.1 17.1 Aleksandar Vezenkov \n", - "3 2.8 12.1 Brad Oleson \n", - "4 4.0 8.9 Victor Claver \n", - "5 2.9 14.4 Petteri Koponen \n", - "6 4.1 13.8 Stratos Perperoglou \n", - "7 3.7 15.9 Marcus Eriksson \n", - "8 4.0 10.6 Alex Renfroe \n", - "9 2.8 19.9 Justin Doellman \n", - "10 6.8 8.0 Joey Dorsey \n", - "11 3.1 19.0 Juan Carlos Navarro \n", - "12 5.6 12.1 Moussa Diagne \n", - "13 5.3 19.6 Vitor Faverani \n", - "14 6.8 4.9 Stefan Peno \n", - "15 7.3 15.3 Jonathan Holmes \n", - "16 7.5 10.0 Xavier Munford \n", - "17 1.6 17.2 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 12.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]}\n", - "KEY in wrapper\n", - "((, 2017, 'C'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", - "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", - "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", - "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", - "5 petteri-koponen-1 27.0 6.0 586.0 5.0 11.2 0.443 \n", - "6 stratos-perperoglou-1 26.0 18.0 529.0 5.2 12.3 0.425 \n", - "7 marcus-eriksson-1 30.0 3.0 454.0 5.6 11.0 0.511 \n", - "8 alex-renfroe-1 20.0 1.0 368.0 3.9 7.8 0.500 \n", - "9 justin-doellman-1 12.0 8.0 273.0 7.1 13.3 0.535 \n", - "10 joey-dorsey-1 16.0 1.0 264.0 3.3 4.8 0.686 \n", - "11 juan-carlos-navarro-1 16.0 3.0 222.0 6.8 14.8 0.462 \n", - "12 moussa-diagne-1 15.0 0.0 122.0 3.8 8.9 0.433 \n", - "13 vitor-faverani-1 6.0 2.0 101.0 6.8 11.4 0.594 \n", - "14 stefan-peno-1 12.0 0.0 95.0 1.9 7.6 0.250 \n", - "15 jonathan-holmes-1 3.0 2.0 54.0 6.0 10.0 0.600 \n", - "16 xavier-munford-1 6.0 0.0 43.0 4.2 7.5 0.556 \n", - "17 pau-ribas-1 1.0 0.0 23.0 4.7 12.5 0.375 \n", - "18 pol-figueras-1 2.0 0.0 12.0 0.0 0.0 NaN \n", - "19 wesley-sena-1 1.0 0.0 3.0 0.0 12.0 0.000 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.0 6.7 0.293 ... 0.3 \n", - "1 0.0 0.1 0.500 ... 3.2 \n", - "2 2.2 5.8 0.378 ... 1.8 \n", - "3 2.0 4.5 0.453 ... 1.0 \n", - "4 1.6 3.8 0.413 ... 1.4 \n", - "5 1.8 5.2 0.353 ... 0.6 \n", - "6 1.6 5.6 0.277 ... 0.6 \n", - "7 3.3 7.5 0.447 ... 0.7 \n", - "8 1.3 3.0 0.419 ... 1.1 \n", - "9 1.8 3.6 0.519 ... 1.1 \n", - "10 0.0 0.0 NaN ... 3.3 \n", - "11 2.6 7.8 0.333 ... 0.3 \n", - "12 0.0 0.0 NaN ... 6.5 \n", - "13 0.4 1.1 0.333 ... 3.2 \n", - "14 0.4 4.5 0.083 ... 0.8 \n", - "15 3.3 5.3 0.625 ... 0.0 \n", - "16 1.7 5.0 0.333 ... 0.0 \n", - "17 3.1 9.4 0.333 ... 0.0 \n", - "18 0.0 0.0 NaN ... 0.0 \n", - "19 0.0 0.0 NaN ... 12.0 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", - "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", - "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", - "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", - "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", - "5 3.0 3.6 3.7 1.2 0.2 2.2 \n", - "6 3.8 4.4 1.9 1.2 0.2 1.9 \n", - "7 3.0 3.7 2.6 0.8 0.3 1.0 \n", - "8 2.5 3.6 4.0 1.6 0.3 2.2 \n", - "9 3.8 4.9 1.8 1.5 0.3 2.5 \n", - "10 8.6 11.9 2.6 0.7 1.2 3.8 \n", - "11 1.5 1.8 3.2 1.3 0.0 1.3 \n", - "12 6.2 12.7 1.2 1.5 0.3 3.5 \n", - "13 7.5 10.7 0.7 0.7 0.0 4.6 \n", - "14 3.8 4.5 4.5 0.8 0.0 4.2 \n", - "15 7.3 7.3 0.0 1.3 2.0 6.0 \n", - "16 4.2 4.2 4.2 1.7 1.7 5.9 \n", - "17 4.7 4.7 4.7 1.6 0.0 3.1 \n", - "18 0.0 0.0 0.0 3.0 0.0 9.0 \n", - "19 12.0 24.0 0.0 0.0 0.0 0.0 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.6 16.4 Tyrese Rice \n", - "1 3.6 19.9 Ante Tomic \n", - "2 4.1 17.1 Aleksandar Vezenkov \n", - "3 2.8 12.1 Brad Oleson \n", - "4 4.0 8.9 Victor Claver \n", - "5 2.9 14.4 Petteri Koponen \n", - "6 4.1 13.8 Stratos Perperoglou \n", - "7 3.7 15.9 Marcus Eriksson \n", - "8 4.0 10.6 Alex Renfroe \n", - "9 2.8 19.9 Justin Doellman \n", - "10 6.8 8.0 Joey Dorsey \n", - "11 3.1 19.0 Juan Carlos Navarro \n", - "12 5.6 12.1 Moussa Diagne \n", - "13 5.3 19.6 Vitor Faverani \n", - "14 6.8 4.9 Stefan Peno \n", - "15 7.3 15.3 Jonathan Holmes \n", - "16 7.5 10.0 Xavier Munford \n", - "17 1.6 17.2 Pau Ribas \n", - "18 3.0 0.0 Pol Figueras \n", - "19 0.0 12.0 Wesley Sena \n", - "\n", - "[20 rows x 26 columns]\n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_per36(2017, level='C')" ] }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -5334,7 +2509,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 62, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -5352,200 +2527,16 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", - "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", - "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", - "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", - "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", - "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", - "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", - "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", - "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", - "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", - "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", - "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", - "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", - "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", - "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", - "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", - "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", - "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", - "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", - "1 0.525 20.4 15.3 24.1 Ante Tomic \n", - "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", - "3 0.210 10.7 22.2 14.4 Victor Claver \n", - "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", - "5 0.183 16.1 17.0 13.6 Brad Oleson \n", - "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", - "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", - "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", - "9 0.267 11.9 13.2 22.4 Justin Doellman \n", - "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", - "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", - "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", - "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", - "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", - "15 0.357 20.5 34.4 17.6 Stefan Peno \n", - "16 0.000 17.0 47.1 22.5 Xavier Munford \n", - "17 0.267 18.6 15.2 23.5 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", - "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", - "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", - "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", - "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", - "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", - "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", - "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", - "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", - "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", - "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", - "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", - "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", - "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", - "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", - "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", - "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", - "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", - "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", - "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", - "1 0.465 19.5 18.9 24.0 Ante Tomic \n", - "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", - "3 0.295 10.6 19.3 14.7 Victor Claver \n", - "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", - "5 0.098 16.8 15.8 12.4 Brad Oleson \n", - "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", - "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", - "8 0.202 12.1 12.0 19.9 Justin Doellman \n", - "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", - "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", - "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", - "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", - "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", - "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", - "15 0.500 18.1 38.1 16.8 Stefan Peno \n", - "16 0.000 10.2 50.0 27.0 Xavier Munford \n", - "17 0.000 10.3 12.5 20.4 Pau Ribas \n", - "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", - "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", - "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", - "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", - "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", - "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", - "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", - "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", - "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", - "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", - "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", - "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", - "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", - "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", - "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", - "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", - "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", - "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", - "1 0.574 21.3 12.3 24.3 Ante Tomic \n", - "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", - "3 0.250 15.6 17.9 14.7 Brad Oleson \n", - "4 0.121 10.9 25.1 14.1 Victor Claver \n", - "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", - "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", - "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", - "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", - "9 0.327 11.7 14.1 25.2 Justin Doellman \n", - "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", - "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", - "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", - "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", - "14 0.300 21.6 32.7 18.1 Stefan Peno \n", - "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", - "16 0.000 22.4 43.8 19.0 Xavier Munford \n", - "17 0.500 25.8 17.0 26.1 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", - "KEY in wrapper\n", - "((, 2017, 'B'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", - "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", - "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", - "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", - "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", - "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", - "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", - "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", - "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", - "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", - "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", - "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", - "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", - "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", - "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", - "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", - "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", - "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", - "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", - "1 0.525 20.4 15.3 24.1 Ante Tomic \n", - "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", - "3 0.210 10.7 22.2 14.4 Victor Claver \n", - "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", - "5 0.183 16.1 17.0 13.6 Brad Oleson \n", - "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", - "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", - "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", - "9 0.267 11.9 13.2 22.4 Justin Doellman \n", - "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", - "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", - "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", - "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", - "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", - "15 0.357 20.5 34.4 17.6 Stefan Peno \n", - "16 0.000 17.0 47.1 22.5 Xavier Munford \n", - "17 0.267 18.6 15.2 23.5 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", - "20 2.000 0.0 0.0 32.0 Wesley Sena \n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_advanced(2017, level='B')" ] }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -5673,7 +2664,7 @@ "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov " ] }, - "execution_count": 64, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -5684,196 +2675,16 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", - "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", - "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", - "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", - "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", - "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", - "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", - "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", - "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", - "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", - "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", - "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", - "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", - "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", - "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", - "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", - "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", - "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", - "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", - "1 0.525 20.4 15.3 24.1 Ante Tomic \n", - "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", - "3 0.210 10.7 22.2 14.4 Victor Claver \n", - "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", - "5 0.183 16.1 17.0 13.6 Brad Oleson \n", - "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", - "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", - "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", - "9 0.267 11.9 13.2 22.4 Justin Doellman \n", - "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", - "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", - "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", - "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", - "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", - "15 0.357 20.5 34.4 17.6 Stefan Peno \n", - "16 0.000 17.0 47.1 22.5 Xavier Munford \n", - "17 0.267 18.6 15.2 23.5 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", - "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", - "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", - "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", - "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", - "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", - "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", - "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", - "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", - "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", - "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", - "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", - "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", - "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", - "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", - "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", - "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", - "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", - "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", - "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", - "1 0.465 19.5 18.9 24.0 Ante Tomic \n", - "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", - "3 0.295 10.6 19.3 14.7 Victor Claver \n", - "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", - "5 0.098 16.8 15.8 12.4 Brad Oleson \n", - "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", - "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", - "8 0.202 12.1 12.0 19.9 Justin Doellman \n", - "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", - "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", - "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", - "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", - "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", - "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", - "15 0.500 18.1 38.1 16.8 Stefan Peno \n", - "16 0.000 10.2 50.0 27.0 Xavier Munford \n", - "17 0.000 10.3 12.5 20.4 Pau Ribas \n", - "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", - "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", - "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", - "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", - "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", - "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", - "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", - "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", - "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", - "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", - "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", - "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", - "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", - "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", - "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", - "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", - "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", - "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", - "1 0.574 21.3 12.3 24.3 Ante Tomic \n", - "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", - "3 0.250 15.6 17.9 14.7 Brad Oleson \n", - "4 0.121 10.9 25.1 14.1 Victor Claver \n", - "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", - "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", - "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", - "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", - "9 0.327 11.7 14.1 25.2 Justin Doellman \n", - "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", - "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", - "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", - "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", - "14 0.300 21.6 32.7 18.1 Stefan Peno \n", - "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", - "16 0.000 22.4 43.8 19.0 Xavier Munford \n", - "17 0.500 25.8 17.0 26.1 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", - "KEY in wrapper\n", - "((, 2017, 'E'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", - "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", - "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", - "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", - "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", - "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", - "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", - "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", - "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", - "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", - "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", - "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", - "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", - "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", - "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", - "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", - "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", - "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", - "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", - "1 0.465 19.5 18.9 24.0 Ante Tomic \n", - "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", - "3 0.295 10.6 19.3 14.7 Victor Claver \n", - "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", - "5 0.098 16.8 15.8 12.4 Brad Oleson \n", - "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", - "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", - "8 0.202 12.1 12.0 19.9 Justin Doellman \n", - "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", - "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", - "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", - "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", - "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", - "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", - "15 0.500 18.1 38.1 16.8 Stefan Peno \n", - "16 0.000 10.2 50.0 27.0 Xavier Munford \n", - "17 0.000 10.3 12.5 20.4 Pau Ribas \n", - "18 0.000 0.0 0.0 34.0 Rodions Kurucs \n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_advanced(2017, level='E')" ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 32, "metadata": { "scrolled": true }, @@ -6003,7 +2814,7 @@ "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov " ] }, - "execution_count": 66, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -6014,198 +2825,16 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CACHE BEFORE\n", - "{((, 2017, 'B'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", - "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", - "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", - "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", - "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", - "5 brad-oleson-1 53.0 1122.0 0.664 NaN 0.578 \n", - "6 stratos-perperoglou-1 48.0 989.0 0.493 NaN 0.425 \n", - "7 marcus-eriksson-1 52.0 671.0 0.621 NaN 0.677 \n", - "8 alex-renfroe-1 37.0 669.0 0.586 NaN 0.449 \n", - "9 justin-doellman-1 27.0 572.0 0.615 NaN 0.282 \n", - "10 joey-dorsey-1 33.0 556.0 0.599 NaN 0.000 \n", - "11 juan-carlos-navarro-1 32.0 469.0 0.520 NaN 0.562 \n", - "12 vitor-faverani-1 15.0 240.0 0.640 NaN 0.130 \n", - "13 moussa-diagne-1 23.0 201.0 0.519 NaN 0.000 \n", - "14 jonathan-holmes-1 10.0 143.0 0.682 NaN 0.526 \n", - "15 stefan-peno-1 22.0 143.0 0.370 NaN 0.536 \n", - "16 xavier-munford-1 11.0 77.0 0.472 NaN 0.500 \n", - "17 pau-ribas-1 3.0 43.0 0.597 NaN 0.800 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 rodions-kurucs-1 1.0 3.0 0.500 NaN 0.500 \n", - "20 wesley-sena-1 1.0 3.0 0.266 NaN 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", - "1 0.525 20.4 15.3 24.1 Ante Tomic \n", - "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", - "3 0.210 10.7 22.2 14.4 Victor Claver \n", - "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov \n", - "5 0.183 16.1 17.0 13.6 Brad Oleson \n", - "6 0.197 12.4 12.8 20.6 Stratos Perperoglou \n", - "7 0.101 12.1 10.8 16.8 Marcus Eriksson \n", - "8 0.188 19.1 23.5 14.9 Alex Renfroe \n", - "9 0.267 11.9 13.2 22.4 Justin Doellman \n", - "10 0.701 11.1 31.4 17.0 Joey Dorsey \n", - "11 0.184 21.1 15.3 25.7 Juan Carlos Navarro \n", - "12 0.584 6.4 22.4 26.6 Vitor Faverani \n", - "13 0.884 6.4 24.1 20.0 Moussa Diagne \n", - "14 0.316 2.7 31.6 22.6 Jonathan Holmes \n", - "15 0.357 20.5 34.4 17.6 Stefan Peno \n", - "16 0.000 17.0 47.1 22.5 Xavier Munford \n", - "17 0.267 18.6 15.2 23.5 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 0.000 0.0 0.0 34.0 Rodions Kurucs \n", - "20 2.000 0.0 0.0 32.0 Wesley Sena , ((, 2017, 'E'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", - "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", - "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", - "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", - "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", - "5 brad-oleson-1 24.0 519.0 0.602 0.588 0.569 \n", - "6 stratos-perperoglou-1 22.0 460.0 0.471 0.450 0.381 \n", - "7 alex-renfroe-1 17.0 301.0 0.548 0.517 0.534 \n", - "8 justin-doellman-1 15.0 299.0 0.572 0.527 0.298 \n", - "9 joey-dorsey-1 17.0 292.0 0.572 0.548 0.000 \n", - "10 juan-carlos-navarro-1 16.0 247.0 0.450 0.404 0.596 \n", - "11 marcus-eriksson-1 22.0 217.0 0.440 0.440 0.680 \n", - "12 vitor-faverani-1 9.0 139.0 0.631 0.567 0.156 \n", - "13 jonathan-holmes-1 7.0 89.0 0.636 0.565 0.522 \n", - "14 moussa-diagne-1 8.0 79.0 0.502 0.385 0.000 \n", - "15 stefan-peno-1 10.0 48.0 0.564 0.438 0.375 \n", - "16 xavier-munford-1 5.0 34.0 0.278 0.278 0.333 \n", - "17 pau-ribas-1 2.0 20.0 0.643 0.643 0.857 \n", - "18 rodions-kurucs-1 1.0 3.0 0.500 0.500 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", - "1 0.465 19.5 18.9 24.0 Ante Tomic \n", - "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", - "3 0.295 10.6 19.3 14.7 Victor Claver \n", - "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov \n", - "5 0.098 16.8 15.8 12.4 Brad Oleson \n", - "6 0.158 14.2 13.4 19.1 Stratos Perperoglou \n", - "7 0.121 16.7 28.2 14.4 Alex Renfroe \n", - "8 0.202 12.1 12.0 19.9 Justin Doellman \n", - "9 0.710 9.2 26.9 19.5 Joey Dorsey \n", - "10 0.170 22.0 21.7 26.7 Juan Carlos Navarro \n", - "11 0.000 5.7 18.0 14.4 Marcus Eriksson \n", - "12 0.489 7.9 21.5 25.6 Vitor Faverani \n", - "13 0.522 4.4 28.0 22.5 Jonathan Holmes \n", - "14 1.385 6.6 25.1 18.0 Moussa Diagne \n", - "15 0.500 18.1 38.1 16.8 Stefan Peno \n", - "16 0.000 10.2 50.0 27.0 Xavier Munford \n", - "17 0.000 10.3 12.5 20.4 Pau Ribas \n", - "18 0.000 0.0 0.0 34.0 Rodions Kurucs , ((, 2017, 'C'), frozenset()): player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", - "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", - "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", - "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", - "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", - "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", - "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", - "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", - "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", - "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", - "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", - "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", - "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", - "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", - "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", - "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", - "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", - "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", - "1 0.574 21.3 12.3 24.3 Ante Tomic \n", - "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", - "3 0.250 15.6 17.9 14.7 Brad Oleson \n", - "4 0.121 10.9 25.1 14.1 Victor Claver \n", - "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", - "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", - "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", - "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", - "9 0.327 11.7 14.1 25.2 Justin Doellman \n", - "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", - "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", - "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", - "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", - "14 0.300 21.6 32.7 18.1 Stefan Peno \n", - "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", - "16 0.000 22.4 43.8 19.0 Xavier Munford \n", - "17 0.500 25.8 17.0 26.1 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 2.000 0.0 0.0 32.0 Wesley Sena }\n", - "KEY in wrapper\n", - "((, 2017, 'C'), frozenset())\n", - "COPY\n", - "RET worked\n", - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", - "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", - "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", - "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", - "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", - "5 petteri-koponen-1 27.0 586.0 0.577 0.525 0.464 \n", - "6 stratos-perperoglou-1 26.0 529.0 0.510 0.489 0.459 \n", - "7 marcus-eriksson-1 30.0 454.0 0.682 0.662 0.676 \n", - "8 alex-renfroe-1 20.0 368.0 0.611 0.581 0.388 \n", - "9 justin-doellman-1 12.0 273.0 0.654 0.604 0.267 \n", - "10 joey-dorsey-1 16.0 264.0 0.647 0.686 0.000 \n", - "11 juan-carlos-navarro-1 16.0 222.0 0.591 0.549 0.527 \n", - "12 moussa-diagne-1 15.0 122.0 0.528 0.433 0.000 \n", - "13 vitor-faverani-1 6.0 101.0 0.653 0.609 0.094 \n", - "14 stefan-peno-1 12.0 95.0 0.287 0.275 0.600 \n", - "15 jonathan-holmes-1 3.0 54.0 0.767 0.767 0.533 \n", - "16 xavier-munford-1 6.0 43.0 0.667 0.667 0.667 \n", - "17 pau-ribas-1 1.0 23.0 0.564 0.500 0.750 \n", - "18 pol-figueras-1 2.0 12.0 NaN NaN NaN \n", - "19 wesley-sena-1 1.0 3.0 0.266 0.000 0.000 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", - "1 0.574 21.3 12.3 24.3 Ante Tomic \n", - "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", - "3 0.250 15.6 17.9 14.7 Brad Oleson \n", - "4 0.121 10.9 25.1 14.1 Victor Claver \n", - "5 0.257 20.9 14.7 20.8 Petteri Koponen \n", - "6 0.227 10.8 12.3 21.9 Stratos Perperoglou \n", - "7 0.137 15.1 8.1 18.0 Marcus Eriksson \n", - "8 0.238 21.1 19.9 15.3 Alex Renfroe \n", - "9 0.327 11.7 14.1 25.2 Justin Doellman \n", - "10 0.686 13.2 38.1 14.2 Joey Dorsey \n", - "11 0.198 20.1 7.5 24.6 Juan Carlos Navarro \n", - "12 0.667 6.2 23.6 21.3 Moussa Diagne \n", - "13 0.719 4.4 23.6 27.9 Vitor Faverani \n", - "14 0.300 21.6 32.7 18.1 Stefan Peno \n", - "15 0.000 0.0 37.5 22.7 Jonathan Holmes \n", - "16 0.000 22.4 43.8 19.0 Xavier Munford \n", - "17 0.500 25.8 17.0 26.1 Pau Ribas \n", - "18 NaN 0.0 100.0 12.8 Pol Figueras \n", - "19 2.000 0.0 0.0 32.0 Wesley Sena \n" - ] - } - ], + "outputs": [], "source": [ "df = t.stats_advanced(2017, level='C')" ] }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 34, "metadata": { "scrolled": true }, @@ -6335,7 +2964,7 @@ "4 0.121 10.9 25.1 14.1 Victor Claver " ] }, - "execution_count": 68, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } From 8bc8abfd5ee21b8b8e17864e0b92387f7c7be99c Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Fri, 2 Feb 2018 20:04:29 -0500 Subject: [PATCH 34/57] todo update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1def3ae..ac9d2f6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Develop Todo: -### Figure out why teams/all_teams_opp_stats table isn't parsing +### DONE Figure out why teams/all_teams_opp_stats table isn't parsing ### comment teams -> merge to master +### check euro/players comments ### euro/seasons From 42cfa27f885b54cfb506b760c489989f023ece31 Mon Sep 17 00:00:00 2001 From: Matt Goldberg Date: Sat, 3 Feb 2018 18:08:52 -0800 Subject: [PATCH 35/57] preparing for 0.10.0 --- requirements.txt | 152 +++++++++++++++++------------------------------ setup.py | 2 +- 2 files changed, 55 insertions(+), 99 deletions(-) diff --git a/requirements.txt b/requirements.txt index 6f726ff..c8c86ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,105 +1,61 @@ appdirs==1.4.3 appnope==0.1.0 -argh==0.26.2 -backports-abc==0.5 -backports.shutil-get-terminal-size==1.0.0 -bleach==1.5.0 -boltons==17.0.0 -boto3==1.4.3 -botocore==1.4.93 -certifi==2016.9.26 -click==6.7 -cloudpickle==0.2.2 -configparser==3.5.0 -cssselect==1.0.0 -cycler==0.10.0 -dask==0.13.0 -decorator==4.0.10 -distributed==1.15.0 -docutils==0.13.1 -entrypoints==0.2.2 -enum34==1.1.6 -functools32==3.2.3.post2 +bleach==2.1.2 +boltons==17.2.0 +certifi==2018.1.18 +chardet==3.0.4 +cssselect==1.0.3 +decorator==4.2.1 +entrypoints==0.2.3 future==0.16.0 -futures==3.0.5 -graphviz==0.5.2 -HeapDict==1.0.0 -html5lib==0.9999999 -invoke==0.14.0 -ipdb==0.10.1 -ipykernel==4.5.2 -ipython==5.1.0 -ipython-genutils==0.1.0 -ipywidgets==5.2.2 -Jinja2==2.8.1 -jmespath==0.9.0 -jsonschema==2.5.1 +html5lib==1.0.1 +idna==2.6 +ipdb==0.10.3 +ipykernel==4.8.0 +ipython==6.2.1 +ipython-genutils==0.2.0 +ipywidgets==7.1.1 +jedi==0.11.1 +Jinja2==2.10 +jsonschema==2.6.0 jupyter==1.0.0 -jupyter-client==4.4.0 -jupyter-console==5.0.0 -jupyter-core==4.2.1 -livereload==2.5.0 -locket==0.2.0 -lxml==3.7.1 -MarkupSafe==0.23 -matplotlib==2.0.0 -mementos==1.2.6 -mistune==0.7.3 -msgpack-python==0.4.8 -nbconvert==5.0.0 -nbformat==4.2.0 -notebook==4.3.1 -numexpr==2.6.2 -numpy==1.12.0 -packaging==16.8 -pandas==0.19.2 -pandocfilters==1.4.1 -partd==0.3.7 -pathlib2==2.1.0 -pathtools==0.1.2 -patsy==0.4.1 -pexpect==4.2.1 +jupyter-client==5.2.2 +jupyter-console==5.2.0 +jupyter-core==4.4.0 +lxml==4.1.1 +MarkupSafe==1.0 +mementos==1.2.8 +mistune==0.8.3 +nbconvert==5.3.1 +nbformat==4.4.0 +notebook==5.4.0 +numexpr==2.6.4 +numpy==1.14.0 +pandas==0.22.0 +pandocfilters==1.4.2 +parso==0.1.1 +pexpect==4.3.1 pickleshare==0.7.4 -pluggy==0.4.0 -port-for==0.3.1 -prompt-toolkit==1.0.9 -psutil==5.0.1 -ptyprocess==0.5.1 -Pweave==0.25 -py==1.4.32 -Pygments==2.1.3 -pyparsing==2.1.10 -pyquery==1.2.17 -pytest==3.0.5 -python-dateutil==2.6.0 -pytz==2016.10 -PyYAML==3.12 -pyzmq==16.0.2 -qtconsole==4.2.1 -requests==2.13.0 -s3fs==0.0.8 -s3transfer==0.1.10 -scikit-learn==0.18.1 -scipy==0.18.1 +prompt-toolkit==1.0.15 +ptyprocess==0.5.2 +Pygments==2.2.0 +pyquery==1.4.0 +python-dateutil==2.6.1 +pytz==2017.3 +pyzmq==16.0.4 +qtconsole==4.3.1 +requests==2.18.4 +scipy==1.0.0 +Send2Trash==1.4.2 simplegeneric==0.8.1 -singledispatch==3.4.0.3 -six==1.10.0 -sklearn==0.0 -sortedcollections==0.4.2 -sortedcontainers==1.5.7 -sphinx-autobuild==0.6.0 --e git+git@github.com:mdgoldberg/sportsref.git@cfb9edb89da9eeb99ef54d149d32f4e99b7e2087#egg=sportsref -statsmodels==0.6.1 -subprocess32==3.2.7 -tblib==1.3.0 -terminado==0.6 -testpath==0.3 -toolz==0.8.2 -tornado==4.4.2 -tox==2.5.0 -traitlets==4.3.1 -virtualenv==15.1.0 -watchdog==0.8.3 +six==1.11.0 +sportsref==0.9.1 +terminado==0.8.1 +testpath==0.3.1 +tornado==4.5.3 +traitlets==4.3.2 +urllib3==1.22 wcwidth==0.1.7 -widgetsnbextension==1.2.6 -zict==0.1.1 +webencodings==0.5.1 +widgetsnbextension==3.1.3 +yapf==0.20.1 diff --git a/setup.py b/setup.py index b64432a..5226a46 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup(name='sportsref', - version='0.9.1', + version='0.10.0', description='Scraping data from sports-reference.com and related sites', url='https://github.com/mdgoldberg/sportsref', author='Matt Goldberg', From 68255161331a1caca821131755a41f37f0a5368b Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 13:13:45 -0500 Subject: [PATCH 36/57] begin work on boxscores.py --- sportsref/euro/boxscores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index 20f3a8e..c3d798e 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -30,7 +30,7 @@ def __repr__(self): @sportsref.decorators.memoize def get_main_doc(self): url = ('{}/boxscores/{}.html' - .format(sportsref.nba.BASE_URL, self.boxscore_id)) + .format(sportsref.euro.BASE_URL, self.boxscore_id)) doc = pq(sportsref.utils.get_html(url)) return doc From 9abe5beb9292880d70d539bb223292a1feb73b69 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 13:55:02 -0500 Subject: [PATCH 37/57] fix ids --- sportsref/euro/boxscores.py | 324 ++---------------------------------- 1 file changed, 18 insertions(+), 306 deletions(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index c3d798e..7f70e0b 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -47,7 +47,7 @@ def date(self): for more. :returns: A datetime.date object with year, month, and day attributes. """ - match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) + match = re.match(r'(\d{4})-(\d{2})-(\d{2})', self.boxscore_id) year, month, day = list(map(int, match.groups())) return datetime.date(year=year, month=month, day=day) @@ -60,37 +60,38 @@ def weekday(self): return days[wd] @sportsref.decorators.memoize - def linescore(self): - """Returns the linescore for the game as a DataFrame.""" + def get_id(self, home): + """Returns home team ID. + :returns: 3-character string representing home team's ID. + """ doc = self.get_main_doc() - table = doc('table#line_score') + div = doc('.scorebox') - columns = [th.text() for th in table('tr.thead').items('th')] - columns[0] = 'team_id' + a_list = [] + for a in div('a').items(): + href = a.attr('href') + if 'teams' in href: + a_list.append(href) - data = [ - [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] - for tr in list(table('tr.thead').next_all('tr').items()) - ] - - return pd.DataFrame(data, index=['away', 'home'], - columns=columns, dtype='float') + if home: + return a_list[1] + return a_list[0] @sportsref.decorators.memoize def home(self): """Returns home team ID. :returns: 3-character string representing home team's ID. """ - linescore = self.linescore() - return linescore.loc['home', 'team_id'] + + return self.get_id(True) @sportsref.decorators.memoize def away(self): """Returns away team ID. :returns: 3-character string representing away team's ID. """ - linescore = self.linescore() - return linescore.loc['away', 'team_id'] + + return self.get_id(False) @sportsref.decorators.memoize def home_score(self): @@ -167,292 +168,3 @@ def basic_stats(self): """Returns a DataFrame of basic player stats from the game.""" return self._get_player_stats('box_{}_basic') - @sportsref.decorators.memoize - def advanced_stats(self): - """Returns a DataFrame of advanced player stats from the game.""" - return self._get_player_stats('box_{}_advanced') - - @sportsref.decorators.memoize - def pbp(self, dense_lineups=False, sparse_lineups=False): - """Returns a dataframe of the play-by-play data from the game. - - :param dense_lineups: If True, adds 10 columns containing the names of - the players on the court. Defaults to False. - :param sparse_lineups: If True, adds binary columns denoting whether a - given player is in the game at the time of a pass. Defaults to - False. - :returns: pandas DataFrame of play-by-play. Similar to GPF. - """ - try: - doc = self.get_subpage_doc('pbp') - except: - raise ValueError( - 'Error fetching PBP subpage for boxscore {}' - .format(self.boxscore_id) - ) - table = doc('table#pbp') - trs = [ - tr for tr in list(table('tr').items()) - if (not tr.attr['class'] or # regular data rows - tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds - ] - rows = [tr.children('td') for tr in trs] - n_rows = len(trs) - data = [] - cur_qtr = 0 - bsid = self.boxscore_id - - for i in range(n_rows): - tr = trs[i] - row = rows[i] - p = {} - - # increment cur_qtr when we hit a new quarter - if tr.attr['id'] and tr.attr['id'].startswith('q'): - assert int(tr.attr['id'][1:]) == cur_qtr + 1 - cur_qtr += 1 - continue - - # add time of play to entry - t_str = row.eq(0).text() - t_regex = r'(\d+):(\d+)\.(\d+)' - mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) - endQ = (12 * 60 * min(cur_qtr, 4) + - 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) - secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) - p['secs_elapsed'] = secsElapsed - p['clock_time'] = t_str - p['quarter'] = cur_qtr - - # handle single play description - # ex: beginning/end of quarter, jump ball - if row.length == 2: - desc = row.eq(1) - # handle jump balls - if desc.text().lower().startswith('jump ball: '): - p['is_jump_ball'] = True - jb_str = sportsref.utils.flatten_links(desc) - p.update( - sportsref.nba.pbp.parse_play(bsid, jb_str, None) - ) - # ignore rows marking beginning/end of quarters - elif ( - desc.text().lower().startswith('start of ') or - desc.text().lower().startswith('end of ') - ): - continue - # if another case, log and continue - else: - if not desc.text().lower().startswith('end of '): - print(( - '{}, Q{}, {} other case: {}' - .format(self.boxscore_id, cur_qtr, - t_str, desc.text()) - )) - continue - - # handle team play description - # ex: shot, turnover, rebound, foul, sub, etc. - elif row.length == 6: - aw_desc, hm_desc = row.eq(1), row.eq(5) - is_hm_play = bool(hm_desc.text()) - desc = hm_desc if is_hm_play else aw_desc - desc = sportsref.utils.flatten_links(desc) - # parse the play - new_p = sportsref.nba.pbp.parse_play(bsid, desc, is_hm_play) - if not new_p: - continue - elif isinstance(new_p, list): - # this happens when a row needs to be expanded to 2 rows; - # ex: double personal foul -> two PF rows - - # first, update and append the first row - orig_p = dict(p) - p.update(new_p[0]) - data.append(p) - # second, set up the second row to be appended below - p = orig_p - new_p = new_p[1] - elif new_p.get('is_error'): - print(("can't parse: {}, boxscore: {}" - .format(desc, self.boxscore_id))) - # import pdb; pdb.set_trace() - p.update(new_p) - - # otherwise, I don't know what this was - else: - raise Exception(("don't know how to handle row of length {}" - .format(row.length))) - - data.append(p) - - # convert to DataFrame and clean columns - df = pd.DataFrame.from_records(data) - df.sort_values('secs_elapsed', inplace=True, kind='mergesort') - df = sportsref.nba.pbp.clean_features(df) - - # add columns for home team, away team, boxscore_id, date - away, home = self.away(), self.home() - df['home'] = home - df['away'] = away - df['boxscore_id'] = self.boxscore_id - df['season'] = self.season() - date = self.date() - df['year'] = date.year - df['month'] = date.month - df['day'] = date.day - - def _clean_rebs(df): - df.reset_index(drop=True, inplace=True) - no_reb_after = ( - (df.fta_num < df.tot_fta) | df.is_ftm | - df.get('is_tech_fta', False) - ).shift(1).fillna(False) - no_reb_before = ( - (df.fta_num == df.tot_fta) - ).shift(-1).fillna(False) - se_end_qtr = df.loc[ - df.clock_time == '0:00.0', 'secs_elapsed' - ].unique() - no_reb_when = df.secs_elapsed.isin(se_end_qtr) - drop_mask = ( - (df.rebounder == 'Team') & - (no_reb_after | no_reb_before | no_reb_when) - ).nonzero()[0] - df.drop(drop_mask, axis=0, inplace=True) - df.reset_index(drop=True, inplace=True) - return df - - # get rid of 'rebounds' after FTM, non-final FTA, or tech FTA - df = _clean_rebs(df) - - # track possession number for each possession - # TODO: see 201604130PHO, secs_elapsed == 2756 - # things that end a poss: - # FGM, dreb, TO, end of Q, made last FT, lost jump ball, - # def goaltending, shot clock violation - new_poss = (df.off_team == df.home).diff().fillna(False) - # def rebound considered part of the new possession - df['poss_id'] = np.cumsum(new_poss) + df.is_dreb - # create poss_id with rebs -> new possessions for granular groupbys - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # make sure plays with the same clock time are in the right order - # TODO: make sort_cols depend on what cols are in the play? - # or combine related plays, like and-1 shot and foul - # issues come up with FGA after timeout in 201604130LAL - # issues come up with PF between FGA and DREB in 201604120SAS - sort_cols = [col for col in - ['is_reb', 'is_fga', 'is_pf', 'is_tech_foul', - 'is_ejection', 'is_tech_fta', 'is_timeout', 'is_pf_fta', - 'fta_num', 'is_viol', 'is_to', 'is_jump_ball', 'is_sub'] - if col in df.columns] - asc_true = ['fta_num'] - ascend = [(col in asc_true) for col in sort_cols] - for label, group in df.groupby([df.secs_elapsed, poss_id_reb]): - if len(group) > 1: - df.loc[group.index, :] = group.sort_values( - sort_cols, ascending=ascend, kind='mergesort' - ).values - - # 2nd pass: get rid of 'rebounds' after FTM, non-final FTA, etc. - df = _clean_rebs(df) - - # makes sure off/def and poss_id are correct for subs after rearranging - # some possessions above - df.loc[df['is_sub'], ['off_team', 'def_team', 'poss_id']] = np.nan - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.poss_id.fillna(method='bfill', inplace=True) - # make off_team and def_team NaN for jump balls - if 'is_jump_ball' in df.columns: - df.loc[df['is_jump_ball'], ['off_team', 'def_team']] = np.nan - - # make sure 'off_team' is always the team shooting FTs, even on techs - # (impt for keeping track of the score) - if 'is_tech_fta' in df.columns: - tech_fta = df['is_tech_fta'] - df.loc[tech_fta, 'off_team'] = df.loc[tech_fta, 'fta_team'] - df.loc[tech_fta, 'def_team'] = np.where( - df.loc[tech_fta, 'off_team'] == home, away, home - ) - df.drop('fta_team', axis=1, inplace=True) - # redefine poss_id_reb - new_poss = (df.off_team == df.home).diff().fillna(False) - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # get rid of redundant subs - for (se, tm, pnum), group in df[df.is_sub].groupby( - [df.secs_elapsed, df.sub_team, poss_id_reb] - ): - if len(group) > 1: - sub_in = set() - sub_out = set() - # first, figure out who's in and who's out after subs - for i, row in group.iterrows(): - if row['sub_in'] in sub_out: - sub_out.remove(row['sub_in']) - else: - sub_in.add(row['sub_in']) - if row['sub_out'] in sub_in: - sub_in.remove(row['sub_out']) - else: - sub_out.add(row['sub_out']) - assert len(sub_in) == len(sub_out) - # second, add those subs - n_subs = len(sub_in) - for idx, p_in, p_out in zip( - group.index[:n_subs], sub_in, sub_out - ): - assert df.loc[idx, 'is_sub'] - df.loc[idx, 'sub_in'] = p_in - df.loc[idx, 'sub_out'] = p_out - df.loc[idx, 'sub_team'] = tm - df.loc[idx, 'detail'] = ( - '{} enters the game for {}'.format(p_in, p_out) - ) - # third, if applicable, remove old sub entries when there are - # redundant subs - n_extra = len(group) - len(sub_in) - if n_extra: - extra_idxs = group.index[-n_extra:] - df.drop(extra_idxs, axis=0, inplace=True) - - df.reset_index(drop=True, inplace=True) - - # add column for pts and score - df['pts'] = (df['is_ftm'] + 2 * df['is_fgm'] + - (df['is_fgm'] & df['is_three'])) - df['hm_pts'] = np.where(df.off_team == df.home, df.pts, 0) - df['aw_pts'] = np.where(df.off_team == df.away, df.pts, 0) - df['hm_score'] = np.cumsum(df['hm_pts']) - df['aw_score'] = np.cumsum(df['aw_pts']) - - # more helpful columns - # "play" is differentiated from "poss" by counting OReb as new play - # "plays" end with non-and1 FGA, TO, last non-tech FTA, or end of qtr - # (or double lane viol) - new_qtr = df.quarter.diff().shift(-1).fillna(False).astype(bool) - and1 = (df.is_fgm & df.is_pf.shift(-1).fillna(False) & - df.is_fta.shift(-2).fillna(False) & - ~df.secs_elapsed.diff().shift(-1).fillna(False).astype(bool)) - double_lane = (df.get('viol_type') == 'double lane') - new_play = df.eval('(is_fga & ~(@and1)) | is_to | @new_qtr |' - '(is_fta & ~is_tech_fta & fta_num == tot_fta) |' - '@double_lane') - df['play_id'] = np.cumsum(new_play).shift(1).fillna(0) - df['hm_off'] = df.off_team == df.home - - # get lineup data - if dense_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_dense_lineups(df)), axis=1 - ) - if sparse_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_sparse_lineups(df)), axis=1 - ) - - # TODO: add shot clock as a feature - - return df From 6ddbbed8f04f9f762ca69d007099a50de608480d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 14:18:03 -0500 Subject: [PATCH 38/57] table stats id changed --- sportsref/euro/boxscores.py | 56 +++++++++++++------------------------ 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index 7f70e0b..f5a0998 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -60,7 +60,7 @@ def weekday(self): return days[wd] @sportsref.decorators.memoize - def get_id(self, home): + def get_raw_id(self, home): """Returns home team ID. :returns: 3-character string representing home team's ID. """ @@ -83,7 +83,8 @@ def home(self): :returns: 3-character string representing home team's ID. """ - return self.get_id(True) + l = self.get_raw_id(True) + return l.split('/')[2] @sportsref.decorators.memoize def away(self): @@ -91,7 +92,8 @@ def away(self): :returns: 3-character string representing away team's ID. """ - return self.get_id(False) + l = self.get_raw_id(False) + return l.split('/')[2] @sportsref.decorators.memoize def home_score(self): @@ -128,43 +130,23 @@ def season(self): :returns: An int representing the year of the season. """ - d = self.date() - if d.month >= 9: - return d.year + 1 - else: - return d.year + l = self.get_raw_id(True) + return l.split('/')[3].replace('.html','') - def _get_player_stats(self, table_id_fmt): - """Returns a DataFrame of player stats from the game (either basic or - advanced, depending on the argument. + @sportsref.decorators.memoize + def get_home_stats(self): + doc = self.get_main_doc() + table = doc('table#{}'.format('box-score-home')) + df = sportsref.utils.parse_table(table) - :param table_id_fmt: Format string for str.format with a placeholder - for the team ID (e.g. 'box_{}_basic') - :returns: DataFrame of player stats - """ + return df - # get data + @sportsref.decorators.memoize + def get_visitor_stats(self): doc = self.get_main_doc() - tms = self.away(), self.home() - tm_ids = [table_id_fmt.format(tm) for tm in tms] - tables = [doc('table#{}'.format(tm_id).lower()) for tm_id in tm_ids] - dfs = [sportsref.utils.parse_table(table) for table in tables] - - # clean data and add features - for i, (tm, df) in enumerate(zip(tms, dfs)): - no_time = df['mp'] == 0 - stat_cols = [col for col, dtype in df.dtypes.items() - if dtype != 'object'] - df.loc[no_time, stat_cols] = 0 - df['team_id'] = tm - df['is_home'] = i == 1 - df['is_starter'] = [p < 5 for p in range(df.shape[0])] - df.drop_duplicates(subset='player_id', keep='first', inplace=True) - - return pd.concat(dfs) + table = doc('table#{}'.format('box-score-visitor')) + df = sportsref.utils.parse_table(table) + + return df - @sportsref.decorators.memoize - def basic_stats(self): - """Returns a DataFrame of basic player stats from the game.""" - return self._get_player_stats('box_{}_basic') From dbd63a06a86ea8d5bc92983643353707571d885e Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 15:24:24 -0500 Subject: [PATCH 39/57] get scores --- sportsref/euro/boxscores.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index f5a0998..dbcd887 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -77,14 +77,31 @@ def get_raw_id(self, home): return a_list[1] return a_list[0] + @sportsref.decorators.memoize + def get_score(self, home): + """Returns home team ID. + :returns: 3-character string representing home team's ID. + """ + doc = self.get_main_doc() + div = doc('.scorebox') + + scores = [] + for d in div('.score').items(): + score.append(int(d.text())) + + if home: + return scores[1] + return scores[0] + + @sportsref.decorators.memoize def home(self): """Returns home team ID. :returns: 3-character string representing home team's ID. """ - l = self.get_raw_id(True) - return l.split('/')[2] + l = self.get_raw_id(home=True) + return l.split('/')[3] @sportsref.decorators.memoize def away(self): @@ -92,24 +109,22 @@ def away(self): :returns: 3-character string representing away team's ID. """ - l = self.get_raw_id(False) - return l.split('/')[2] + l = self.get_raw_id(home=False) + return l.split('/')[3] @sportsref.decorators.memoize def home_score(self): """Returns score of the home team. :returns: int of the home score. """ - linescore = self.linescore() - return linescore.loc['home', 'T'] + return self.get_score(home=True) @sportsref.decorators.memoize def away_score(self): """Returns score of the away team. :returns: int of the away score. """ - linescore = self.linescore() - return linescore.loc['away', 'T'] + return self.get_score(home=False) @sportsref.decorators.memoize def winner(self): @@ -130,8 +145,8 @@ def season(self): :returns: An int representing the year of the season. """ - l = self.get_raw_id(True) - return l.split('/')[3].replace('.html','') + l = self.get_raw_id(home=True) + return l.split('/')[4].replace('.html','') @sportsref.decorators.memoize def get_home_stats(self): @@ -142,7 +157,7 @@ def get_home_stats(self): return df @sportsref.decorators.memoize - def get_visitor_stats(self): + def get_away_stats(self): doc = self.get_main_doc() table = doc('table#{}'.format('box-score-visitor')) df = sportsref.utils.parse_table(table) From 7823f0c8aa78647ab3a9e8a8d53d00aa33d46c0a Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 15:26:52 -0500 Subject: [PATCH 40/57] fix --- sportsref/euro/boxscores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index dbcd887..b6d01ab 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -87,7 +87,7 @@ def get_score(self, home): scores = [] for d in div('.score').items(): - score.append(int(d.text())) + scores.append(int(d.text())) if home: return scores[1] From 320cf17ff73964a734bb601f4dad7a8667df3a90 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 15:32:30 -0500 Subject: [PATCH 41/57] remove pbp (not available for euro) --- sportsref/euro/pbp.py | 671 ------------------------------------------ 1 file changed, 671 deletions(-) delete mode 100644 sportsref/euro/pbp.py diff --git a/sportsref/euro/pbp.py b/sportsref/euro/pbp.py deleted file mode 100644 index a67eebd..0000000 --- a/sportsref/euro/pbp.py +++ /dev/null @@ -1,671 +0,0 @@ -from builtins import enumerate, int, list, range, zip - -import operator -import re - -import numpy as np -import pandas as pd - -import sportsref - -PLAYER_RE = r'\w{0,7}\d{2}' - -HM_LINEUP_COLS = ['hm_player{}'.format(i) for i in range(1, 6)] -AW_LINEUP_COLS = ['aw_player{}'.format(i) for i in range(1, 6)] -ALL_LINEUP_COLS = AW_LINEUP_COLS + HM_LINEUP_COLS - - -def sparse_lineup_cols(df): - regex = '{}_in'.format(PLAYER_RE) - return [c for c in df.columns if re.match(regex, c)] - - -def parse_play(boxscore_id, details, is_hm): - """Parse play details from a play-by-play string describing a play. - - Assuming valid input, this function returns structured data in a dictionary - describing the play. If the play detail string was invalid, this function - returns None. - - :param boxscore_id: the boxscore ID of the play - :param details: detail string for the play - :param is_hm: bool indicating whether the offense is at home - :param returns: dictionary of play attributes or None if invalid - :rtype: dictionary or None - """ - # if input isn't a string, return None - if not details or not isinstance(details, str): - return None - - bs = sportsref.nba.BoxScore(boxscore_id) - aw, hm = bs.away(), bs.home() - season = sportsref.nba.Season(bs.season()) - hm_roster = set(bs.basic_stats().query('is_home == True').player_id.values) - - p = {} - p['detail'] = details - p['home'] = hm - p['away'] = aw - p['is_home_play'] = is_hm - - # parsing field goal attempts - shotRE = (r'(?P{0}) (?Pmakes|misses) ' - '(?P2|3)\-pt shot').format(PLAYER_RE) - distRE = r' (?:from (?P\d+) ft|at rim)' - assistRE = r' \(assist by (?P{0})\)'.format(PLAYER_RE) - blockRE = r' \(block by (?P{0})\)'.format(PLAYER_RE) - shotRE = r'{0}{1}(?:{2}|{3})?'.format(shotRE, distRE, assistRE, blockRE) - m = re.match(shotRE, details, re.IGNORECASE) - if m: - p['is_fga'] = True - p.update(m.groupdict()) - p['shot_dist'] = p['shot_dist'] if p['shot_dist'] is not None else 0 - p['shot_dist'] = int(p['shot_dist']) - p['is_fgm'] = p['is_fgm'] == 'makes' - p['is_three'] = p['is_three'] == '3' - p['is_assist'] = pd.notnull(p.get('assister')) - p['is_block'] = pd.notnull(p.get('blocker')) - shooter_home = p['shooter'] in hm_roster - p['off_team'] = hm if shooter_home else aw - p['def_team'] = aw if shooter_home else hm - return p - - # parsing jump balls - jumpRE = ((r'Jump ball: (?P{0}) vs\. (?P{0})' - r'(?: \((?P{0}) gains possession\))?') - .format(PLAYER_RE)) - m = re.match(jumpRE, details, re.IGNORECASE) - if m: - p['is_jump_ball'] = True - p.update(m.groupdict()) - return p - - # parsing rebounds - rebRE = (r'(?POffensive|Defensive) rebound' - r' by (?P{0}|Team)').format(PLAYER_RE) - m = re.match(rebRE, details, re.I) - if m: - p['is_reb'] = True - p.update(m.groupdict()) - p['is_oreb'] = p['is_oreb'].lower() == 'offensive' - p['is_dreb'] = not p['is_oreb'] - if p['rebounder'] == 'Team': - p['reb_team'], other = (hm, aw) if is_hm else (aw, hm) - else: - reb_home = p['rebounder'] in hm_roster - p['reb_team'], other = (hm, aw) if reb_home else (aw, hm) - p['off_team'] = p['reb_team'] if p['is_oreb'] else other - p['def_team'] = p['reb_team'] if p['is_dreb'] else other - return p - - # parsing free throws - ftRE = (r'(?P{}) (?Pmakes|misses) ' - r'(?Ptechnical )?(?Pflagrant )?' - r'(?Pclear path )?free throw' - r'(?: (?P\d+) of (?P\d+))?').format(PLAYER_RE) - m = re.match(ftRE, details, re.I) - if m: - p['is_fta'] = True - p.update(m.groupdict()) - p['is_ftm'] = p['is_ftm'] == 'makes' - p['is_tech_fta'] = bool(p['is_tech_fta']) - p['is_flag_fta'] = bool(p['is_flag_fta']) - p['is_clearpath_fta'] = bool(p['is_clearpath_fta']) - p['is_pf_fta'] = not p['is_tech_fta'] - if p['tot_fta']: - p['tot_fta'] = int(p['tot_fta']) - if p['fta_num']: - p['fta_num'] = int(p['fta_num']) - ft_home = p['ft_shooter'] in hm_roster - p['fta_team'] = hm if ft_home else aw - if not p['is_tech_fta']: - p['off_team'] = hm if ft_home else aw - p['def_team'] = aw if ft_home else hm - return p - - # parsing substitutions - subRE = (r'(?P{0}) enters the game for ' - r'(?P{0})').format(PLAYER_RE) - m = re.match(subRE, details, re.I) - if m: - p['is_sub'] = True - p.update(m.groupdict()) - sub_home = p['sub_in'] in hm_roster or p['sub_out'] in hm_roster - p['sub_team'] = hm if sub_home else aw - return p - - # parsing turnovers - toReasons = (r'(?P[^;]+)(?:; steal by ' - r'(?P{0}))?').format(PLAYER_RE) - toRE = (r'Turnover by (?P{}|Team) ' - r'\((?:{})\)').format(PLAYER_RE, toReasons) - m = re.match(toRE, details, re.I) - if m: - p['is_to'] = True - p.update(m.groupdict()) - p['to_type'] = p['to_type'].lower() - if p['to_type'] == 'offensive foul': - return None - p['is_steal'] = pd.notnull(p['stealer']) - p['is_travel'] = p['to_type'] == 'traveling' - p['is_shot_clock_viol'] = p['to_type'] == 'shot clock' - p['is_oob'] = p['to_type'] == 'step out of bounds' - p['is_three_sec_viol'] = p['to_type'] == '3 sec' - p['is_backcourt_viol'] = p['to_type'] == 'back court' - p['is_off_goaltend'] = p['to_type'] == 'offensive goaltending' - p['is_double_dribble'] = p['to_type'] == 'dbl dribble' - p['is_discont_dribble'] = p['to_type'] == 'discontinued dribble' - p['is_carry'] = p['to_type'] == 'palming' - if p['to_by'] == 'Team': - p['off_team'] = hm if is_hm else aw - p['def_team'] = aw if is_hm else hm - else: - to_home = p['to_by'] in hm_roster - p['off_team'] = hm if to_home else aw - p['def_team'] = aw if to_home else hm - return p - - # parsing shooting fouls - shotFoulRE = (r'Shooting(?P block)? foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(shotFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_shot_foul'] = True - p.update(m.groupdict()) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing offensive fouls - offFoulRE = (r'Offensive(?P charge)? foul ' - r'by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(offFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_off_foul'] = True - p['is_to'] = True - p['to_type'] = 'offensive foul' - p.update(m.groupdict()) - p['is_charge'] = bool(p['is_charge']) - p['fouler'] = p['to_by'] - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = hm if foul_on_home else aw - p['def_team'] = aw if foul_on_home else hm - p['foul_team'] = p['off_team'] - return p - - # parsing personal fouls - foulRE = (r'Personal (?Ptake )?(?Pblock )?' - r'foul by (?P{0})(?: \(drawn by ' - r'(?P{0})\))?').format(PLAYER_RE) - m = re.match(foulRE, details, re.I) - if m: - p['is_pf'] = True - p.update(m.groupdict()) - p['is_take_foul'] = bool(p['is_take_foul']) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # TODO: parsing double personal fouls - # double_foul_re = (r'Double personal foul by (?P{0}) and ' - # r'(?P{0})').format(PLAYER_RE) - # m = re.match(double_Foul_re, details, re.I) - # if m: - # p['is_pf'] = True - # p.update(m.groupdict()) - # p['off_team'] = - - # parsing loose ball fouls - looseBallRE = (r'Loose ball foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(looseBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_loose_ball_foul'] = True - p.update(m.groupdict()) - foul_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_home else aw - return p - - # parsing punching fouls - # TODO - - # parsing away from play fouls - awayFromBallRE = ((r'Away from play foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?') - .format(PLAYER_RE)) - m = re.match(awayFromBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_away_from_play_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - # TODO: figure out who had the ball based on previous play - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing inbound fouls - inboundRE = (r'Inbound foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(inboundRE, details, re.I) - if m: - p['is_pf'] = True - p['is_inbound_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing flagrant fouls - flagrantRE = (r'Flagrant foul type (?P1|2) by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(flagrantRE, details, re.I) - if m: - p['is_pf'] = True - p['is_flagrant'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing clear path fouls - clearPathRE = (r'Clear path foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(clearPathRE, details, re.I) - if m: - p['is_pf'] = True - p['is_clear_path_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing timeouts - timeoutRE = r'(?P.*?) (?:full )?timeout' - m = re.match(timeoutRE, details, re.I) - if m: - p['is_timeout'] = True - p.update(m.groupdict()) - isOfficialTO = p['timeout_team'].lower() == 'official' - name_to_id = season.team_names_to_ids() - p['timeout_team'] = ( - 'Official' if isOfficialTO else - name_to_id.get(hm, name_to_id.get(aw, p['timeout_team'])) - ) - return p - - # parsing technical fouls - techRE = (r'(?PHanging )?' - r'(?PTaunting )?' - r'(?PIll def )?' - r'(?PDelay )?' - r'(?PNon unsport )?' - r'tech(?:nical)? foul by ' - r'(?P{0}|Team)').format(PLAYER_RE) - m = re.match(techRE, details, re.I) - if m: - p['is_tech_foul'] = True - p.update(m.groupdict()) - p['is_hanging'] = bool(p['is_hanging']) - p['is_taunting'] = bool(p['is_taunting']) - p['is_ill_def'] = bool(p['is_ill_def']) - p['is_delay'] = bool(p['is_delay']) - p['is_unsport'] = bool(p['is_unsport']) - foul_on_home = p['tech_fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing ejections - ejectRE = r'(?P{0}|Team) ejected from game'.format(PLAYER_RE) - m = re.match(ejectRE, details, re.I) - if m: - p['is_ejection'] = True - p.update(m.groupdict()) - if p['ejectee'] == 'Team': - p['ejectee_team'] = hm if is_hm else aw - else: - eject_home = p['ejectee'] in hm_roster - p['ejectee_team'] = hm if eject_home else aw - return p - - # parsing defensive 3 seconds techs - def3TechRE = (r'(?:Def 3 sec tech foul|Defensive three seconds)' - r' by (?P{})').format(PLAYER_RE) - m = re.match(def3TechRE, details, re.I) - if m: - p['is_tech_foul'] = True - p['is_def_three_secs'] = True - p.update(m.groupdict()) - foul_on_home = p['tech_fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing violations - violRE = (r'Violation by (?P{0}|Team) ' - r'\((?P.*)\)').format(PLAYER_RE) - m = re.match(violRE, details, re.I) - if m: - p['is_viol'] = True - p.update(m.groupdict()) - if p['viol_type'] == 'kicked_ball': - p['is_to'] = True - p['to_by'] = p['violator'] - if p['violator'] == 'Team': - p['viol_team'] = hm if is_hm else aw - else: - viol_home = p['violator'] in hm_roster - p['viol_team'] = hm if viol_home else aw - return p - - p['is_error'] = True - return p - - -def clean_features(df): - """Fixes up columns of the passed DataFrame, such as casting T/F columns to - boolean and filling in NaNs for team and opp. - - :param df: DataFrame of play-by-play data. - :returns: Dataframe with cleaned columns. - """ - df = pd.DataFrame(df) - - bool_vals = set([True, False, None, np.nan]) - sparse_cols = sparse_lineup_cols(df) - for col in df: - - # make indicator columns boolean type (and fill in NaNs) - if set(df[col].unique()[:5]) <= bool_vals: - df[col] = (df[col] == True) - - # fill NaN's in sparse lineup columns to 0 - elif col in sparse_cols: - df[col] = df[col].fillna(0) - - # fix free throw columns on technicals - df.loc[df.is_tech_fta, ['fta_num', 'tot_fta']] = 1 - - # fill in NaN's/fix off_team and def_team columns - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.off_team.fillna(method='ffill', inplace=True) - df.def_team.fillna(method='ffill', inplace=True) - - return df - - -def clean_multigame_features(df): - """TODO: Docstring for clean_multigame_features. - - :df: TODO - :returns: TODO - """ - df = pd.DataFrame(df) - if df.index.value_counts().max() > 1: - df.reset_index(drop=True, inplace=True) - - df = clean_features(df) - - # if it's many games in one DataFrame, make poss_id and play_id unique - for col in ('play_id', 'poss_id'): - diffs = df[col].diff().fillna(0) - if (diffs < 0).any(): - new_col = np.cumsum(diffs.astype(bool)) - df.eval('{} = @new_col'.format(col), inplace=True) - - return df - - -def get_period_starters(df): - """TODO - """ - - def players_from_play(play): - """Figures out what players are in the game based on the players - mentioned in a play. Returns away and home players as two sets. - - :param play: A dictionary representing a parsed play. - :returns: (aw_players, hm_players) - :rtype: tuple of lists - """ - # if it's a tech FT from between periods, don't count this play - if ( - play['clock_time'] == '12:00.0' and - (play.get('is_tech_foul') or play.get('is_tech_fta')) - ): - return [], [] - - stats = sportsref.nba.BoxScore(play['boxscore_id']).basic_stats() - home_grouped = stats.groupby('is_home') - hm_roster = set(home_grouped.player_id.get_group(True).values) - aw_roster = set(home_grouped.player_id.get_group(False).values) - player_keys = [ - 'assister', 'away_jumper', 'blocker', 'drew_foul', 'fouler', - 'ft_shooter', 'gains_poss', 'home_jumper', 'rebounder', 'shooter', - 'stealer', 'sub_in', 'sub_out', 'to_by' - ] - players = [p for p in play[player_keys] if pd.notnull(p)] - - aw_players = [p for p in players if p in aw_roster] - hm_players = [p for p in players if p in hm_roster] - return aw_players, hm_players - - # create a mapping { quarter => (away_starters, home_starters) } - n_periods = df.quarter.nunique() - period_starters = [(set(), set()) for _ in range(n_periods)] - - # fill out this mapping quarter by quarter - for qtr, qtr_grp in df.groupby(df.quarter): - aw_starters, hm_starters = period_starters[qtr-1] - exclude = set() - # loop through sets of plays that happen at the "same time" - for label, time_grp in qtr_grp.groupby(qtr_grp.secs_elapsed): - # first, if they sub in and weren't already starters, exclude them - sub_ins = set(time_grp.sub_in.dropna().values) - exclude.update(sub_ins - aw_starters - hm_starters) - # second, figure out new starters from each play at this time - for i, row in time_grp.iterrows(): - aw_players, hm_players = players_from_play(row) - # update overall sets for the quarter - aw_starters.update(aw_players) - hm_starters.update(hm_players) - # remove excluded (subbed-in) players - hm_starters -= exclude - aw_starters -= exclude - # check whether we have found all starters - if len(hm_starters) > 5 or len(aw_starters) > 5: - import ipdb - ipdb.set_trace() - if len(hm_starters) >= 5 and len(aw_starters) >= 5: - break - - if len(hm_starters) != 5 or len(aw_starters) != 5: - print(('WARNING: wrong number of starters for a team in Q{} of {}' - .format(qtr, df.boxscore_id.iloc[0]))) - - return period_starters - - -def get_sparse_lineups(df): - """TODO: Docstring for get_sparse_lineups. - - :param df: TODO - :returns: TODO - """ - - # get the lineup data using get_dense_lineups if necessary - if (set(ALL_LINEUP_COLS) - set(df.columns)): - lineup_df = get_dense_lineups(df) - else: - lineup_df = df[ALL_LINEUP_COLS] - - # create the sparse representation - hm_lineups = lineup_df[HM_LINEUP_COLS].values - aw_lineups = lineup_df[AW_LINEUP_COLS].values - # +1 for home, -1 for away - hm_df = pd.DataFrame([ - {'{}_in'.format(player_id): 1 for player_id in lineup} - for lineup in hm_lineups - ], dtype=int) - aw_df = pd.DataFrame([ - {'{}_in'.format(player_id): -1 for player_id in lineup} - for lineup in aw_lineups - ], dtype=int) - sparse_df = pd.concat((hm_df, aw_df), axis=1).fillna(0) - return sparse_df - - -def get_dense_lineups(df): - """Returns a new DataFrame based on the one it is passed. Specifically, it - adds five columns for each team (ten total), where each column has the ID - of a player on the court during the play. - - This information is figured out sequentially from the game's substitution - data in the passed DataFrame, so the DataFrame passed as an argument must - be from a specific BoxScore (rather than a DataFrame of non-consecutive - plays). That is, the DataFrame must be of the form returned by - :func:`nba.BoxScore.pbp `. - - .. note:: Note that the lineups reflect the teams in the game when the play - happened, not after the play. For example, if a play is a substitution, - the lineups for that play will be the lineups before the substituion - occurs. - - :param df: A DataFrame of a game's play-by-play data. - :returns: A DataFrame with additional lineup columns. - - """ - # TODO: add this precondition to documentation - assert df['boxscore_id'].nunique() == 1 - - def lineup_dict(aw_lineup, hm_lineup): - """Returns a dictionary of lineups to be converted to columns. - Specifically, the columns are 'aw_player1' through 'aw_player5' and - 'hm_player1' through 'hm_player5'. - - :param aw_lineup: The away team's current lineup. - :param hm_lineup: The home team's current lineup. - :returns: A dictionary of lineups. - """ - return { - '{}_player{}'.format(tm, i+1): player - for tm, lineup in zip(['aw', 'hm'], [aw_lineup, hm_lineup]) - for i, player in enumerate(lineup) - } - - def handle_sub(row, aw_lineup, hm_lineup): - """Modifies the aw_lineup and hm_lineup lists based on the substitution - that takes place in the given row.""" - assert row['is_sub'] - sub_lineup = hm_lineup if row['sub_team'] == row['home'] else aw_lineup - try: - # make the sub - idx = sub_lineup.index(row['sub_out']) - sub_lineup[idx] = row['sub_in'] - except ValueError: - # if the sub was double-entered and it's already been executed... - if ( - row['sub_in'] in sub_lineup - and row['sub_out'] not in sub_lineup - ): - return aw_lineup, hm_lineup - # otherwise, let's print and pretend this never happened - print(('ERROR IN SUB IN {}, Q{}, {}: {}' - .format(row['boxscore_id'], row['quarter'], - row['clock_time'], row['detail']))) - raise - return aw_lineup, hm_lineup - - per_starters = get_period_starters(df) - cur_qtr = 0 - aw_lineup, hm_lineup = [], [] - df = df.reset_index(drop=True) - lineups = [{} for _ in range(df.shape[0])] - - # loop through select plays to determine lineups - sub_or_per_start = df.is_sub | df.quarter.diff().astype(bool) - for i, row in df.loc[sub_or_per_start].iterrows(): - if row['quarter'] > cur_qtr: - # first row in a quarter - assert row['quarter'] == cur_qtr + 1 - # first, finish up the last quarter's lineups - if cur_qtr > 0 and not df.loc[i-1, 'is_sub']: - lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) - # then, move on to the quarter, and enter the starting lineups - cur_qtr += 1 - aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - # if the first play in the quarter is a sub, handle that - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - else: - # during the quarter - # update lineups first then change lineups based on subs - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - - # create and clean DataFrame - lineup_df = pd.DataFrame(lineups) - if lineup_df.iloc[-1].isnull().all(): - lineup_df.iloc[-1] = lineup_dict(aw_lineup, hm_lineup) - lineup_df = lineup_df.groupby(df.quarter).fillna(method='bfill') - - # fill in NaN's based on minutes played - bool_mat = lineup_df.isnull() - mask = bool_mat.any(axis=1) - if mask.any(): - bs = sportsref.nba.BoxScore(df.boxscore_id[0]) - # first, get the true minutes played from the box score - stats = sportsref.nba.BoxScore(df.boxscore_id.iloc[0]).basic_stats() - true_mp = pd.Series( - stats.query('mp > 0')[['player_id', 'mp']] - .set_index('player_id').to_dict()['mp'] - ) * 60 - # next, calculate minutes played based on the lineup data - calc_mp = pd.Series( - {p: (df.secs_elapsed.diff() * - [p in row for row in lineup_df.values]).sum() - for p in stats.query('mp > 0').player_id.values}) - # finally, figure which players are missing minutes - diff = true_mp - calc_mp - players_missing = diff.loc[diff.abs() >= 150] - hm_roster = bs.basic_stats().query('is_home == True').player_id.values - missing_df = pd.DataFrame( - {'secs': players_missing.values, - 'is_home': players_missing.index.isin(hm_roster)}, - index=players_missing.index - ) - - if missing_df.empty: - # TODO: log this as a warning (or error?) - print('There are NaNs in the lineup data, but no players were ' - 'found to be missing significant minutes') - else: - # import ipdb - # ipdb.set_trace() - for is_home, group in missing_df.groupby('is_home'): - player_id = group.index.item() - tm_cols = (sportsref.nba.pbp.HM_LINEUP_COLS if is_home else - sportsref.nba.pbp.AW_LINEUP_COLS) - row_mask = lineup_df[tm_cols].isnull().any(axis=1) - lineup_df.loc[row_mask, tm_cols] = ( - lineup_df.loc[row_mask, tm_cols].fillna(player_id).values - ) - - return lineup_df From d7e323732adef58d586b254d2da367840a8a742d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 6 Feb 2018 21:00:31 -0500 Subject: [PATCH 42/57] season nearly finished --- sportsref/euro/__init__.py | 4 +- sportsref/euro/seasons.py | 147 ++++++++----------------------------- 2 files changed, 34 insertions(+), 117 deletions(-) diff --git a/sportsref/euro/__init__.py b/sportsref/euro/__init__.py index 4aa4a16..b9ff399 100644 --- a/sportsref/euro/__init__.py +++ b/sportsref/euro/__init__.py @@ -10,10 +10,12 @@ BASE_URL = 'http://www.basketball-reference.com/euro' +LEAGUE_IDS = ['greek-basket-league','eurocup','spain-liga-acb','italy-basket-serie-a','france-lnb-pro-a','euroleague'] + __all__ = [ + 'LEAGUE_IDS', 'BASE_URL', 'boxscores', 'BoxScore', - 'pbp', 'seasons', 'Season', 'teams', 'Team', 'players', 'Player', diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py index 5be3575..94698d9 100644 --- a/sportsref/euro/seasons.py +++ b/sportsref/euro/seasons.py @@ -11,15 +11,16 @@ class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): """Object representing a given NBA season.""" - def __init__(self, year): + def __init__(self, year, league_id): """Initializes a Season object for an NBA season. :year: The year of the season we want. """ self.yr = int(year) + self.lg_id = league_id def __eq__(self, other): - return (self.yr == other.yr) + return (self.yr == other.yr and self.lg_id == other.lg_id) def __hash__(self): return hash(self.yr) @@ -27,26 +28,26 @@ def __hash__(self): def __repr__(self): return 'Season({})'.format(self.yr) - def _subpage_url(self, page): - return (sportsref.nba.BASE_URL + - '/leagues/NBA_{}_{}.html'.format(self.yr, page)) + def _schedule_url(self): + return (sportsref.euro.BASE_URL + + '/{}/{}-schedule.html'.format(self.lg_id, self.yr)) @sportsref.decorators.memoize def get_main_doc(self): """Returns PyQuery object for the main season URL. :returns: PyQuery object. """ - url = (sportsref.nba.BASE_URL + - '/leagues/NBA_{}.html'.format(self.yr)) + url = (sportsref.euro.BASE_URL + + '/{}/{}.html'.format(self.lg_id, self.yr)) return pq(sportsref.utils.get_html(url)) @sportsref.decorators.memoize - def get_sub_doc(self, subpage): + def get_schedule_doc(self): """Returns PyQuery object for a given subpage URL. :subpage: The subpage of the season, e.g. 'per_game'. :returns: PyQuery object. """ - html = sportsref.utils.get_html(self._subpage_url(subpage)) + html = sportsref.utils.get_html(self._schedule_url()) return pq(html) @sportsref.decorators.memoize @@ -96,53 +97,15 @@ def schedule(self, kind='R'): :returns: DataFrame of schedule information. :rtype: pd.DataFrame """ - kind = kind.upper()[0] - dfs = [] - - # get games from each month - for month in ('october', 'november', 'december', 'january', 'february', - 'march', 'april', 'may', 'june'): - try: - doc = self.get_sub_doc('games-{}'.format(month)) - except ValueError: - continue - table = doc('table#schedule') - df = sportsref.utils.parse_table(table) - dfs.append(df) - df = pd.concat(dfs).reset_index(drop=True) - - # figure out how many regular season games - try: - sportsref.utils.get_html('{}/playoffs/NBA_{}.html'.format( - sportsref.nba.BASE_URL, self.yr) - ) - is_past_season = True - except ValueError: - is_past_season = False - - if is_past_season: - team_per_game = self.team_stats_per_game() - n_reg_games = int(team_per_game.g.sum() / 2) - else: - n_reg_games = len(df) - - # subset appropriately based on `kind` + doc = self.get_schedule_doc() + table_id = 'table#games' if kind == 'P': - return df.iloc[n_reg_games:] - else: - return df.iloc[:n_reg_games] - - def finals_winner(self): - """Returns the team ID for the winner of that year's NBA Finals. - :returns: 3-letter team ID for champ. - """ - raise NotImplementedError('nba.Season.finals_winner') - - def finals_loser(self): - """Returns the team ID for the loser of that year's NBA Finals. - :returns: 3-letter team ID for runner-up. - """ - raise NotImplementedError('nba.Season.finals_loser') + table_id += '_playoffs' + + table = doc(table_id) + df = sportsref.utils.parse_table(table) + return df + @sportsref.decorators.memoize def _get_team_stats_table(self, selector): @@ -151,72 +114,24 @@ def _get_team_stats_table(self, selector): doc = self.get_main_doc() table = doc(selector) df = sportsref.utils.parse_table(table) - df.set_index('team_id', inplace=True) + #df.set_index('team_id', inplace=True) return df - def team_stats_per_game(self): + def standings(self): """Returns a Pandas DataFrame of each team's basic per-game stats for the season.""" - return self._get_team_stats_table('table#team-stats-per_game') - def opp_stats_per_game(self): - """Returns a Pandas DataFrame of each team's opponent's basic per-game - stats for the season.""" - return self._get_team_stats_table('table#opponent-stats-per_game') + if self.lg_id == 'eurocup' or self.lg_id == 'euroleague': + return self._get_team_stats_table('table#tournament_standings') + else: + return self._get_team_stats_table('table#league_standings') def team_stats_totals(self): - """Returns a Pandas DataFrame of each team's basic stat totals for the - season.""" - return self._get_team_stats_table('table#team-stats-base') - - def opp_stats_totals(self): - """Returns a Pandas DataFrame of each team's opponent's basic stat - totals for the season.""" - return self._get_team_stats_table('table#opponent-stats-base') - - def misc_stats(self): - """Returns a Pandas DataFrame of miscellaneous stats about each team's - season.""" - return self._get_team_stats_table('table#misc_stats') - - def team_stats_shooting(self): - """Returns a Pandas DataFrame of each team's shooting stats for the - season.""" - return self._get_team_stats_table('table#team_shooting') - - def opp_stats_shooting(self): - """Returns a Pandas DataFrame of each team's opponent's shooting stats - for the season.""" - return self._get_team_stats_table('table#opponent_shooting') - - @sportsref.decorators.memoize - def _get_player_stats_table(self, identifier): - """Helper function for player season stats. - - :identifier: string identifying the type of stat, e.g. 'per_game'. - :returns: A DataFrame of stats. - """ - doc = self.get_sub_doc(identifier) - table = doc('table#{}_stats'.format(identifier)) - df = sportsref.utils.parse_table(table) - return df - - def player_stats_per_game(self): - """Returns a DataFrame of per-game player stats for a season.""" - return self._get_player_stats_table('per_game') - - def player_stats_totals(self): - """Returns a DataFrame of player stat totals for a season.""" - return self._get_player_stats_table('totals') - - def player_stats_per36(self): - """Returns a DataFrame of player per-36 min stats for a season.""" - return self._get_player_stats_table('per_minute') - - def player_stats_per100(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('per_poss') + """Returns a Pandas DataFrame of each team's basic per-game stats for + the season.""" + return self._get_team_stats_table('table#team_stats_per_game') - def player_stats_advanced(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('advanced') + def team_stats_per_game(self): + """Returns a Pandas DataFrame of each team's basic per-game stats for + the season.""" + return self._get_team_stats_table('table#team_stats_totals') From e7eca399fd5302e5066350cd52eca7be4c88c1cb Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 15:50:25 -0500 Subject: [PATCH 43/57] parse urls -> team_ids --- sportsref/euro/seasons.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py index 94698d9..e85fd93 100644 --- a/sportsref/euro/seasons.py +++ b/sportsref/euro/seasons.py @@ -114,7 +114,9 @@ def _get_team_stats_table(self, selector): doc = self.get_main_doc() table = doc(selector) df = sportsref.utils.parse_table(table) - #df.set_index('team_id', inplace=True) + df['team_name_season'] = df['team_name_season'].apply(lambda x: x.split('/')[3]) + df.rename(columns={'team_name_season' : 'team_id'}, inplace=True) + df.set_index('team_id', inplace=True) return df def standings(self): From a5847ae80ee708d7ea66ee870503985d93fa4db7 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 16:07:22 -0500 Subject: [PATCH 44/57] team ids -> names and vice versa now working --- sportsref/euro/seasons.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py index e85fd93..b93ce67 100644 --- a/sportsref/euro/seasons.py +++ b/sportsref/euro/seasons.py @@ -69,11 +69,15 @@ def team_ids_to_names(self): values. """ doc = self.get_main_doc() - table = doc('table#team-stats-per_game') - flattened = sportsref.utils.parse_table(table, flatten=True) - unflattened = sportsref.utils.parse_table(table, flatten=False) - team_ids = flattened['team_id'] - team_names = unflattened['team_name'] + table = doc('table#team_stats_per_game') + for a in table('a').items(): + a.removeAttr('href') + + name_table = sportsref.utils.parse_table(table) + id_table = self.team_stats_per_game() + + team_ids = id_table.index.values + team_names = name_table['team_name_season'] if len(team_names) != len(team_ids): raise Exception("team names and team IDs don't align") return dict(list(zip(team_ids, team_names))) @@ -131,9 +135,9 @@ def standings(self): def team_stats_totals(self): """Returns a Pandas DataFrame of each team's basic per-game stats for the season.""" - return self._get_team_stats_table('table#team_stats_per_game') + return self._get_team_stats_table('table#team_stats_totals') def team_stats_per_game(self): """Returns a Pandas DataFrame of each team's basic per-game stats for the season.""" - return self._get_team_stats_table('table#team_stats_totals') + return self._get_team_stats_table('table#team_stats_per_game') From f89c89992cf5f4e4d3e2afb37ca9b4b3057fba4a Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 16:41:34 -0500 Subject: [PATCH 45/57] first pass at teams.schedule --- sportsref/euro/teams.py | 29 +++++++++++++++++++++++++++++ sportsref/nba/teams.py | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 9e4542e..970c847 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -29,6 +29,10 @@ def team_year_url(self, year, level='B'): return (sportsref.euro.BASE_URL + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) + @sportsref.decorators.memoize + def schedule_url(self, year): + return (sportsref.euro.BASE_URL + '/schedules/{}/{}.html'.format(self.team_id, year)) + @sportsref.decorators.memoize def get_main_doc(self): relURL = '/teams/{}'.format(self.team_id) @@ -40,6 +44,10 @@ def get_main_doc(self): def get_year_doc(self, yr_str, level='B'): return pq(sportsref.utils.get_html(self.team_year_url(yr_str, level=level))) + @sportsref.decorators.memoize + def get_schedule_doc(self, year): + return pq(sportsref.utils.get_html(self.schedule_url(year))) + @sportsref.decorators.memoize def get_league_id(self, year=2018): """ Year parameter here in case team switched club-play leagues - also makes it easier to find in doc""" @@ -75,6 +83,27 @@ def get_stats_table(self, table_id, year, level='B'): return df + @sportsref.decorators.memoize + def schedule(self, year, level='B'): + doc = self.get_schedule_doc(year) + for t in doc('table').items(): + if self.team_id in t.attr('id'): + if 'Euroleague' in t.attr('id'): + e_id = t.attr('id') + else: + c_id = t.attr('id') + + if level == 'C': + table_id = c_id + + else: + table_id = e_id + + table = doc('table#{}'.format(table_id)) + df = sportsref.utils.parse_table(table) + return df + + @sportsref.decorators.memoize def all_team_opp_stats(self, year, level='B'): return self.get_stats_table('team_and_opp', year, level=level) diff --git a/sportsref/nba/teams.py b/sportsref/nba/teams.py index 86d56f9..a2adff5 100644 --- a/sportsref/nba/teams.py +++ b/sportsref/nba/teams.py @@ -61,8 +61,8 @@ def roster(self, year): df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) return df - # TODO: kind_rpb @sportsref.decorators.memoize + @sportsref.decorators.kind_rpb(include_type=True) def schedule(self, year): """Gets schedule information for a team-season. From 9891286a9f0c12b29e84ff6b276e7840aead47c4 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 20:17:34 -0500 Subject: [PATCH 46/57] schedule fix --- sportsref/euro/players.py | 3 ++- sportsref/euro/teams.py | 43 ++++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index ceabbb6..a6067f2 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -98,7 +98,8 @@ def position(self): """TODO: Docstring for position. :returns: TODO """ - raise Exception('not yet implemented - euro.Player.position') + doc = self.get_main_doc() + raw = @sportsref.decorators.memoize def height(self): diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 970c847..5afae65 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -19,11 +19,11 @@ def __hash__(self): return hash(self.team_id) @sportsref.decorators.memoize - def team_year_url(self, year, level='B'): + def team_year_url(self, year, kind='B'): yr_str = str(year) - if level == 'C': + if kind == 'C': yr_str += '_' + self.get_league_id(year=year) - elif level == 'E': + else: yr_str += '_euroleague' return (sportsref.euro.BASE_URL + @@ -41,8 +41,8 @@ def get_main_doc(self): return mainDoc @sportsref.decorators.memoize - def get_year_doc(self, yr_str, level='B'): - return pq(sportsref.utils.get_html(self.team_year_url(yr_str, level=level))) + def get_year_doc(self, yr_str, kind='B'): + return pq(sportsref.utils.get_html(self.team_year_url(yr_str, kind=kind))) @sportsref.decorators.memoize def get_schedule_doc(self, year): @@ -75,8 +75,8 @@ def name(self): name = doc('title').text().replace(' Seasons | Basketball-Reference.com', '') return name - def get_stats_table(self, table_id, year, level='B'): - doc = self.get_year_doc(year, level=level) + def get_stats_table(self, table_id, year, kind='B'): + doc = self.get_year_doc(year, kind=kind) table = doc('table#{}'.format(table_id)) print(table_id) df = sportsref.utils.parse_table(table) @@ -84,7 +84,8 @@ def get_stats_table(self, table_id, year, level='B'): return df @sportsref.decorators.memoize - def schedule(self, year, level='B'): + @sportsref.decorators.kind_rpb(include_type=True) + def schedule(self, year, kind='B'): doc = self.get_schedule_doc(year) for t in doc('table').items(): if self.team_id in t.attr('id'): @@ -92,35 +93,35 @@ def schedule(self, year, level='B'): e_id = t.attr('id') else: c_id = t.attr('id') - - if level == 'C': + if kind == 'R': table_id = c_id else: table_id = e_id - table = doc('table#{}'.format(table_id)) + table = doc("table[id='{}']".format(table_id)) df = sportsref.utils.parse_table(table) + df.rename(columns={'date_game_full' : 'boxscore_id'}, inplace=True) return df @sportsref.decorators.memoize - def all_team_opp_stats(self, year, level='B'): - return self.get_stats_table('team_and_opp', year, level=level) + def all_team_opp_stats(self, year, kind='B'): + return self.get_stats_table('team_and_opp', year, kind=kind) @sportsref.decorators.memoize - def stats_per_game(self, year, level='B'): - return self.get_stats_table('per_game', year, level=level) + def stats_per_game(self, year, kind='B'): + return self.get_stats_table('per_game', year, kind=kind) @sportsref.decorators.memoize - def stats_totals(self, year, level='B'): - return self.get_stats_table('totals', year, level=level) + def stats_totals(self, year, kind='B'): + return self.get_stats_table('totals', year, kind=kind) @sportsref.decorators.memoize - def stats_per36(self, year, level='B'): - return self.get_stats_table('per_minute', year, level=level) + def stats_per36(self, year, kind='B'): + return self.get_stats_table('per_minute', year, kind=kind) @sportsref.decorators.memoize - def stats_advanced(self, year, level='B'): - return self.get_stats_table('advanced', year, level=level) + def stats_advanced(self, year, kind='B'): + return self.get_stats_table('advanced', year, kind=kind) From 17966a687b30c588e69821b43996e0b692870dcf Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 20:56:40 -0500 Subject: [PATCH 47/57] added position + euro -> nba_id --- sportsref/euro/players.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index a6067f2..18dfb0f 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -99,7 +99,24 @@ def position(self): :returns: TODO """ doc = self.get_main_doc() - raw = + raw = doc('p:contains("Position:")').text() + pos = raw.split()[1] + return pos + + @sportsref.decorators.memoize + def nba_id(self): + doc = self.get_main_doc() + p = doc('p:contains("NBA Career:")') + href = '' + for a in p('a').items(): + href = a.attr('href') + + if href == '': + return None + + nba_id = href.split('/')[3].replace('.html', '') + + return nba_id @sportsref.decorators.memoize def height(self): From 21731c0c7c5783255afed9883778f449c346ea5d Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 21:19:26 -0500 Subject: [PATCH 48/57] .html -> .htm --- sportsref/euro/boxscores.py | 4 ++-- sportsref/euro/seasons.py | 4 ++-- sportsref/euro/teams.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index b6d01ab..0c04f70 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -29,7 +29,7 @@ def __repr__(self): @sportsref.decorators.memoize def get_main_doc(self): - url = ('{}/boxscores/{}.html' + url = ('{}/boxscores/{}.htm' .format(sportsref.euro.BASE_URL, self.boxscore_id)) doc = pq(sportsref.utils.get_html(url)) return doc @@ -37,7 +37,7 @@ def get_main_doc(self): @sportsref.decorators.memoize def get_subpage_doc(self, page): url = (sportsref.nba.BASE_URL + - '/boxscores/{}/{}.html'.format(page, self.boxscore_id)) + '/boxscores/{}/{}.htm'.format(page, self.boxscore_id)) doc = pq(sportsref.utils.get_html(url)) return doc diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py index b93ce67..96beaad 100644 --- a/sportsref/euro/seasons.py +++ b/sportsref/euro/seasons.py @@ -30,7 +30,7 @@ def __repr__(self): def _schedule_url(self): return (sportsref.euro.BASE_URL + - '/{}/{}-schedule.html'.format(self.lg_id, self.yr)) + '/{}/{}-schedule.htm'.format(self.lg_id, self.yr)) @sportsref.decorators.memoize def get_main_doc(self): @@ -38,7 +38,7 @@ def get_main_doc(self): :returns: PyQuery object. """ url = (sportsref.euro.BASE_URL + - '/{}/{}.html'.format(self.lg_id, self.yr)) + '/{}/{}.htm'.format(self.lg_id, self.yr)) return pq(sportsref.utils.get_html(url)) @sportsref.decorators.memoize diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index 5afae65..f4386b2 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -31,7 +31,7 @@ def team_year_url(self, year, kind='B'): @sportsref.decorators.memoize def schedule_url(self, year): - return (sportsref.euro.BASE_URL + '/schedules/{}/{}.html'.format(self.team_id, year)) + return (sportsref.euro.BASE_URL + '/schedules/{}/{}.htm'.format(self.team_id, year)) @sportsref.decorators.memoize def get_main_doc(self): From 72d30327b879f375521af0d713ae93743714f522 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 22:14:32 -0500 Subject: [PATCH 49/57] commented euro season + restructured test notebooks --- euro_player_test.ipynb | 2419 ---------------- euro_teams_test.ipynb | 2998 -------------------- sportsref/euro/seasons.py | 14 +- test_notebooks/euro/euro_season_test.ipynb | 1255 ++++++++ 4 files changed, 1262 insertions(+), 5424 deletions(-) delete mode 100644 euro_player_test.ipynb delete mode 100644 euro_teams_test.ipynb create mode 100644 test_notebooks/euro/euro_season_test.ipynb diff --git a/euro_player_test.ipynb b/euro_player_test.ipynb deleted file mode 100644 index cc36f87..0000000 --- a/euro_player_test.ipynb +++ /dev/null @@ -1,2419 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Sportsref - Euro" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Regenerating PSFConstants file\n", - "Regenerating GPFConstants file\n" - ] - } - ], - "source": [ - "from sportsref import euro\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "p = euro.Player('luka-doncic-1')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## simple methods: Almost no changes\n", - "\n", - "#### only change: Milos Teodosic Europe Stats -> Milos Teodosic" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Luka Doncic\n", - "17.93972602739726\n", - "78\n" - ] - } - ], - "source": [ - "print(p.name())\n", - "print(p.age(2017))\n", - "print(p.height())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Gamelogs - different url style" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[(2015, 'SPA'), (2016, 'ELG'), (2016, 'SPA'), (2017, 'ELG'), (2017, 'SPA'), (2018, 'ELG'), (2018, 'SPA')]\n" - ] - } - ], - "source": [ - "# new method: to me, would be useful/necessary\n", - "# because gamelogs are split by league and year\n", - "\n", - "print(p.available_gamelogs())" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02015-04-30-real-madrid16-061Real-MadridTrueUnicaja-MalagaW1.4666671.01.01.000...0.00.00.00.00.00.00.00.03.02.7
12015-05-03-obradoiro16-064Real-MadridFalseObradoiroW1.7500000.02.00.000...0.00.00.00.00.00.00.01.01.0-1.2
22015-05-20-vitoria16-081Real-MadridFalseVitoriaL5.0000000.00.0NaN...1.01.02.00.00.00.00.00.02.03.0
32015-05-29-real-madrid16-090Real-MadridTrueGran-CanariaW10.8500001.03.00.333...0.03.03.00.00.00.01.00.02.00.2
42015-05-31-gran-canaria16-092Real-MadridFalseGran-CanariaW4.9833330.00.0NaN...0.01.01.00.00.00.00.00.00.00.3
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " boxscore_id age team_id is_home opp_id \\\n", - "0 2015-04-30-real-madrid 16-061 Real-Madrid True Unicaja-Malaga \n", - "1 2015-05-03-obradoiro 16-064 Real-Madrid False Obradoiro \n", - "2 2015-05-20-vitoria 16-081 Real-Madrid False Vitoria \n", - "3 2015-05-29-real-madrid 16-090 Real-Madrid True Gran-Canaria \n", - "4 2015-05-31-gran-canaria 16-092 Real-Madrid False Gran-Canaria \n", - "\n", - " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", - "0 W 1.466667 1.0 1.0 1.000 ... 0.0 0.0 0.0 0.0 \n", - "1 W 1.750000 0.0 2.0 0.000 ... 0.0 0.0 0.0 0.0 \n", - "2 L 5.000000 0.0 0.0 NaN ... 1.0 1.0 2.0 0.0 \n", - "3 W 10.850000 1.0 3.0 0.333 ... 0.0 3.0 3.0 0.0 \n", - "4 W 4.983333 0.0 0.0 NaN ... 0.0 1.0 1.0 0.0 \n", - "\n", - " stl blk tov pf pts game_score \n", - "0 0.0 0.0 0.0 0.0 3.0 2.7 \n", - "1 0.0 0.0 0.0 1.0 1.0 -1.2 \n", - "2 0.0 0.0 0.0 0.0 2.0 3.0 \n", - "3 0.0 0.0 1.0 0.0 2.0 0.2 \n", - "4 0.0 0.0 0.0 0.0 0.0 0.3 \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p.gamelog_basic(2015, 'SPA').head()" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02017-10-12-anadolu-efes18-226Real-MadridFalseAnadolu-EfesW26.6000009.014.00.643...2.02.04.04.00.00.02.01.027.022.8
12017-10-19-real-madrid18-233Real-MadridTrueCska-MoscowW26.0833332.08.00.250...1.05.06.02.02.01.02.02.014.011.9
22017-10-24-real-madrid18-238Real-MadridTrueMilanoW28.4166677.014.00.500...2.06.08.05.03.00.01.00.027.028.3
32017-10-26-zalgiris18-240Real-MadridFalseZalgirisW27.7500009.013.00.692...2.07.09.04.00.00.03.02.028.025.0
42017-11-02-real-madrid18-247Real-MadridTrueKhimkiL25.6000003.010.00.300...2.05.07.03.01.00.03.01.012.08.8
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " boxscore_id age team_id is_home opp_id \\\n", - "0 2017-10-12-anadolu-efes 18-226 Real-Madrid False Anadolu-Efes \n", - "1 2017-10-19-real-madrid 18-233 Real-Madrid True Cska-Moscow \n", - "2 2017-10-24-real-madrid 18-238 Real-Madrid True Milano \n", - "3 2017-10-26-zalgiris 18-240 Real-Madrid False Zalgiris \n", - "4 2017-11-02-real-madrid 18-247 Real-Madrid True Khimki \n", - "\n", - " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", - "0 W 26.600000 9.0 14.0 0.643 ... 2.0 2.0 4.0 4.0 \n", - "1 W 26.083333 2.0 8.0 0.250 ... 1.0 5.0 6.0 2.0 \n", - "2 W 28.416667 7.0 14.0 0.500 ... 2.0 6.0 8.0 5.0 \n", - "3 W 27.750000 9.0 13.0 0.692 ... 2.0 7.0 9.0 4.0 \n", - "4 L 25.600000 3.0 10.0 0.300 ... 2.0 5.0 7.0 3.0 \n", - "\n", - " stl blk tov pf pts game_score \n", - "0 0.0 0.0 2.0 1.0 27.0 22.8 \n", - "1 2.0 1.0 2.0 2.0 14.0 11.9 \n", - "2 3.0 0.0 1.0 0.0 27.0 28.3 \n", - "3 0.0 0.0 3.0 2.0 28.0 25.0 \n", - "4 1.0 0.0 3.0 1.0 12.0 8.8 \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p.gamelog_basic(2018, 'ELG').head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## stat_tables:\n", - "\n", - "\n", - "### took out stats_per100, stats_advanced, stats_shooting, stats_pbp (data not on bballref)\n", - "\n", - "### changed table_ids\n", - "\n", - "### parameters:\n", - "\n", - "### Kind (works the same)\n", - "\n", - "### Level (needed, because different docs are pulled from)\n", - "\n", - "#### -B (pulls from main milos-teodosic doc - default)\n", - "#### -C (pulls from milos-teodosic-club)\n", - "#### -E (pulls from milos-teodosic-tournament, which is Eurocup/Euroleague play)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test: level='B' - Both" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='R', level='B')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB3.0NaN2.70.31.00.3330.30.7...0.30.30.70.00.00.00.00.32.0False
12016Liga ACB, EuroLeague43.0NaN13.31.42.90.5000.51.3...0.52.22.72.00.30.31.41.54.5False
22017Liga ACB, EuroLeague67.0NaN19.92.65.70.4461.02.9...1.03.44.43.70.80.31.91.37.8False
32018EuroLeague, Liga ACB37.0NaN24.64.910.50.4731.64.9...1.14.55.64.61.10.32.11.315.8False
\n", - "

4 rows × 27 columns

\n", - "
" - ], - "text/plain": [ - " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", - "0 2015 Liga ACB 3.0 NaN 2.7 0.3 1.0 \n", - "1 2016 Liga ACB, EuroLeague 43.0 NaN 13.3 1.4 2.9 \n", - "2 2017 Liga ACB, EuroLeague 67.0 NaN 19.9 2.6 5.7 \n", - "3 2018 EuroLeague, Liga ACB 37.0 NaN 24.6 4.9 10.5 \n", - "\n", - " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", - "0 0.333 0.3 0.7 ... 0.3 0.3 \n", - "1 0.500 0.5 1.3 ... 0.5 2.2 \n", - "2 0.446 1.0 2.9 ... 1.0 3.4 \n", - "3 0.473 1.6 4.9 ... 1.1 4.5 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", - "1 2.7 2.0 0.3 0.3 1.4 1.5 4.5 \n", - "2 4.4 3.7 0.8 0.3 1.9 1.3 7.8 \n", - "3 5.6 4.6 1.1 0.3 2.1 1.3 15.8 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 False \n", - "\n", - "[4 rows x 27 columns]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='P', level='B')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB2.0NaN8.00.51.50.3330.00.5...0.02.02.00.00.00.00.50.01.0True
12016Liga ACB8.0NaN8.01.32.40.5260.31.1...0.31.41.60.90.30.10.91.63.1True
22017Liga ACB10.0NaN19.22.36.00.3830.52.4...0.93.84.72.70.30.01.31.16.5True
\n", - "

3 rows × 27 columns

\n", - "
" - ], - "text/plain": [ - " season lg_name g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 2015 Liga ACB 2.0 NaN 8.0 0.5 1.5 0.333 \n", - "1 2016 Liga ACB 8.0 NaN 8.0 1.3 2.4 0.526 \n", - "2 2017 Liga ACB 10.0 NaN 19.2 2.3 6.0 0.383 \n", - "\n", - " fg3_per_g fg3a_per_g ... orb_per_g drb_per_g trb_per_g \\\n", - "0 0.0 0.5 ... 0.0 2.0 2.0 \n", - "1 0.3 1.1 ... 0.3 1.4 1.6 \n", - "2 0.5 2.4 ... 0.9 3.8 4.7 \n", - "\n", - " ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 0.0 0.0 0.0 0.5 0.0 1.0 \n", - "1 0.9 0.3 0.1 0.9 1.6 3.1 \n", - "2 2.7 0.3 0.0 1.3 1.1 6.5 \n", - "\n", - " is_playoffs \n", - "0 True \n", - "1 True \n", - "2 True \n", - "\n", - "[3 rows x 27 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='B', level='B')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015Liga ACB3.0NaN2.70.31.00.3330.30.7...0.30.30.70.00.00.00.00.32.0False
12016Liga ACB, EuroLeague43.0NaN13.31.42.90.5000.51.3...0.52.22.72.00.30.31.41.54.5False
22017Liga ACB, EuroLeague67.0NaN19.92.65.70.4461.02.9...1.03.44.43.70.80.31.91.37.8False
32018EuroLeague, Liga ACB37.0NaN24.64.910.50.4731.64.9...1.14.55.64.61.10.32.11.315.8False
42015Liga ACB2.0NaN8.00.51.50.3330.00.5...0.02.02.00.00.00.00.50.01.0True
\n", - "

5 rows × 27 columns

\n", - "
" - ], - "text/plain": [ - " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", - "0 2015 Liga ACB 3.0 NaN 2.7 0.3 1.0 \n", - "1 2016 Liga ACB, EuroLeague 43.0 NaN 13.3 1.4 2.9 \n", - "2 2017 Liga ACB, EuroLeague 67.0 NaN 19.9 2.6 5.7 \n", - "3 2018 EuroLeague, Liga ACB 37.0 NaN 24.6 4.9 10.5 \n", - "4 2015 Liga ACB 2.0 NaN 8.0 0.5 1.5 \n", - "\n", - " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", - "0 0.333 0.3 0.7 ... 0.3 0.3 \n", - "1 0.500 0.5 1.3 ... 0.5 2.2 \n", - "2 0.446 1.0 2.9 ... 1.0 3.4 \n", - "3 0.473 1.6 4.9 ... 1.1 4.5 \n", - "4 0.333 0.0 0.5 ... 0.0 2.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", - "1 2.7 2.0 0.3 0.3 1.4 1.5 4.5 \n", - "2 4.4 3.7 0.8 0.3 1.9 1.3 7.8 \n", - "3 5.6 4.6 1.1 0.3 2.1 1.3 15.8 \n", - "4 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 False \n", - "4 True \n", - "\n", - "[5 rows x 27 columns]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test: level='C' - Club" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='R', level='C')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes3.0NaN2.70.31.00.333...0.30.30.70.00.00.00.00.32.0False
12016/euro/teams/real-madrid/2016.htmlLiga ACBes31.0NaN14.21.63.10.526...0.62.22.82.00.40.31.51.94.9False
22017/euro/teams/real-madrid/2017.htmlLiga ACBes32.0NaN19.92.75.80.460...1.03.34.33.10.70.42.01.37.8False
32018/euro/teams/real-madrid/2018.htmlLiga ACBes17.0NaN23.64.69.80.473...1.14.85.94.60.90.21.91.614.1False
\n", - "

4 rows × 29 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name lg_country g gs \\\n", - "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 3.0 NaN \n", - "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 31.0 NaN \n", - "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 32.0 NaN \n", - "3 2018 /euro/teams/real-madrid/2018.html Liga ACB es 17.0 NaN \n", - "\n", - " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", - "0 2.7 0.3 1.0 0.333 ... 0.3 0.3 \n", - "1 14.2 1.6 3.1 0.526 ... 0.6 2.2 \n", - "2 19.9 2.7 5.8 0.460 ... 1.0 3.3 \n", - "3 23.6 4.6 9.8 0.473 ... 1.1 4.8 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", - "1 2.8 2.0 0.4 0.3 1.5 1.9 4.9 \n", - "2 4.3 3.1 0.7 0.4 2.0 1.3 7.8 \n", - "3 5.9 4.6 0.9 0.2 1.9 1.6 14.1 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 False \n", - "\n", - "[4 rows x 29 columns]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='P', level='C')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes2.0NaN8.00.51.50.333...0.02.02.00.00.00.00.50.01.0True
12016/euro/teams/real-madrid/2016.htmlLiga ACBes8.0NaN8.01.32.40.526...0.31.41.60.90.30.10.91.63.1True
22017/euro/teams/real-madrid/2017.htmlLiga ACBes10.0NaN19.22.36.00.383...0.93.84.72.70.30.01.31.16.5True
\n", - "

3 rows × 29 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name lg_country g gs \\\n", - "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 2.0 NaN \n", - "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 8.0 NaN \n", - "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 10.0 NaN \n", - "\n", - " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", - "0 8.0 0.5 1.5 0.333 ... 0.0 2.0 \n", - "1 8.0 1.3 2.4 0.526 ... 0.3 1.4 \n", - "2 19.2 2.3 6.0 0.383 ... 0.9 3.8 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", - "1 1.6 0.9 0.3 0.1 0.9 1.6 3.1 \n", - "2 4.7 2.7 0.3 0.0 1.3 1.1 6.5 \n", - "\n", - " is_playoffs \n", - "0 True \n", - "1 True \n", - "2 True \n", - "\n", - "[3 rows x 29 columns]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='B', level='C')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02015/euro/teams/real-madrid/2015.htmlLiga ACBes3.0NaN2.70.31.00.333...0.30.30.70.00.00.00.00.32.0False
12016/euro/teams/real-madrid/2016.htmlLiga ACBes31.0NaN14.21.63.10.526...0.62.22.82.00.40.31.51.94.9False
22017/euro/teams/real-madrid/2017.htmlLiga ACBes32.0NaN19.92.75.80.460...1.03.34.33.10.70.42.01.37.8False
32018/euro/teams/real-madrid/2018.htmlLiga ACBes17.0NaN23.64.69.80.473...1.14.85.94.60.90.21.91.614.1False
42015/euro/teams/real-madrid/2015.htmlLiga ACBes2.0NaN8.00.51.50.333...0.02.02.00.00.00.00.50.01.0True
\n", - "

5 rows × 29 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name lg_country g gs \\\n", - "0 2015 /euro/teams/real-madrid/2015.html Liga ACB es 3.0 NaN \n", - "1 2016 /euro/teams/real-madrid/2016.html Liga ACB es 31.0 NaN \n", - "2 2017 /euro/teams/real-madrid/2017.html Liga ACB es 32.0 NaN \n", - "3 2018 /euro/teams/real-madrid/2018.html Liga ACB es 17.0 NaN \n", - "4 2015 /euro/teams/real-madrid/2015.html Liga ACB es 2.0 NaN \n", - "\n", - " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", - "0 2.7 0.3 1.0 0.333 ... 0.3 0.3 \n", - "1 14.2 1.6 3.1 0.526 ... 0.6 2.2 \n", - "2 19.9 2.7 5.8 0.460 ... 1.0 3.3 \n", - "3 23.6 4.6 9.8 0.473 ... 1.1 4.8 \n", - "4 8.0 0.5 1.5 0.333 ... 0.0 2.0 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 0.7 0.0 0.0 0.0 0.0 0.3 2.0 \n", - "1 2.8 2.0 0.4 0.3 1.5 1.9 4.9 \n", - "2 4.3 3.1 0.7 0.4 2.0 1.3 7.8 \n", - "3 5.9 4.6 0.9 0.2 1.9 1.6 14.1 \n", - "4 2.0 0.0 0.0 0.0 0.5 0.0 1.0 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 False \n", - "4 True \n", - "\n", - "[5 rows x 29 columns]" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test: level='E' - Eurocup/Euroleague (because Eurocup/Euroleague will never have sep playoffs, kind modifier does nothing) -> need to deal with duplicate when kind='B' " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "6\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='B', level='E')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5False
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8False
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3False
32016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5True
42017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8True
\n", - "

5 rows × 28 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name g gs mp_per_g \\\n", - "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", - "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", - "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", - "3 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", - "4 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", - "\n", - " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", - "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", - "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", - "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", - "3 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", - "4 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", - "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", - "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", - "3 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", - "4 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "3 True \n", - "4 True \n", - "\n", - "[5 rows x 28 columns]" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='R', level='E')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5False
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8False
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3False
\n", - "

3 rows × 28 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name g gs mp_per_g \\\n", - "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", - "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", - "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", - "\n", - " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", - "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", - "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", - "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", - "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", - "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", - "\n", - " is_playoffs \n", - "0 False \n", - "1 False \n", - "2 False \n", - "\n", - "[3 rows x 28 columns]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "df = p.stats_per_game(kind='P', level='E')\n", - "\n", - "print(len(df))" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02016/euro/teams/real-madrid/2016.htmlEuroLeague12.0NaN11.10.92.30.4070.4...0.32.12.32.00.20.31.20.63.5True
12017/euro/teams/real-madrid/2017.htmlEuroLeague35.0NaN19.92.45.60.4341.1...0.93.54.54.20.90.21.81.37.8True
22018/euro/teams/real-madrid/2018.htmlEuroLeague20.0NaN25.55.211.00.4731.9...1.14.45.44.61.20.42.21.117.3True
\n", - "

3 rows × 28 columns

\n", - "
" - ], - "text/plain": [ - " season team_name_season lg_name g gs mp_per_g \\\n", - "0 2016 /euro/teams/real-madrid/2016.html EuroLeague 12.0 NaN 11.1 \n", - "1 2017 /euro/teams/real-madrid/2017.html EuroLeague 35.0 NaN 19.9 \n", - "2 2018 /euro/teams/real-madrid/2018.html EuroLeague 20.0 NaN 25.5 \n", - "\n", - " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", - "0 0.9 2.3 0.407 0.4 ... 0.3 2.1 \n", - "1 2.4 5.6 0.434 1.1 ... 0.9 3.5 \n", - "2 5.2 11.0 0.473 1.9 ... 1.1 4.4 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 2.3 2.0 0.2 0.3 1.2 0.6 3.5 \n", - "1 4.5 4.2 0.9 0.2 1.8 1.3 7.8 \n", - "2 5.4 4.6 1.2 0.4 2.2 1.1 17.3 \n", - "\n", - " is_playoffs \n", - "0 True \n", - "1 True \n", - "2 True \n", - "\n", - "[3 rows x 28 columns]" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/euro_teams_test.ipynb b/euro_teams_test.ipynb deleted file mode 100644 index ad0b3a3..0000000 --- a/euro_teams_test.ipynb +++ /dev/null @@ -1,2998 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Regenerating PSFConstants file\n", - "Regenerating GPFConstants file\n" - ] - } - ], - "source": [ - "from sportsref import euro" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "t = euro.Team('barcelona')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "i = t.get_league_id()\n", - "name = t.name()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "spain-liga-acb\n", - "FC Barcelona\n" - ] - } - ], - "source": [ - "print(i)\n", - "print(name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tables are same as player: \n", - "\n", - "### 'E' = Euroleague\n", - "### 'C' = Club play\n", - "### 'B' = both (combined in 1 table, not concatenated together like playoff/reg season tables)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## all team and opp stats table:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "df = t.all_team_opp_stats(2017, level = 'B')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team62.013100.01795.03812.00.471586.01579.00.3711209.0...0.744515.01510.02025.01084.0437.0140.0884.01313.04988.0
1Opponent62.013100.01754.04013.00.437584.01623.00.3601170.0...0.763573.01368.01941.01039.0453.0109.0779.01318.04897.0
\n", - "

2 rows × 24 columns

\n", - "
" - ], - "text/plain": [ - " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", - "0 Team 62.0 13100.0 1795.0 3812.0 0.471 586.0 1579.0 0.371 \n", - "1 Opponent 62.0 13100.0 1754.0 4013.0 0.437 584.0 1623.0 0.360 \n", - "\n", - " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", - "0 1209.0 ... 0.744 515.0 1510.0 2025.0 1084.0 437.0 140.0 884.0 \n", - "1 1170.0 ... 0.763 573.0 1368.0 1941.0 1039.0 453.0 109.0 779.0 \n", - "\n", - " pf pts \n", - "0 1313.0 4988.0 \n", - "1 1318.0 4897.0 \n", - "\n", - "[2 rows x 24 columns]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.all_team_opp_stats(2017, level = 'E')" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team30.06025.0767.01739.00.441271.0716.00.378496.0...0.737245.0680.0925.0517.0212.061.0420.0553.02141.0
1Opponent30.06025.0834.01844.00.452263.0729.00.361571.0...0.748254.0659.0913.0510.0232.065.0357.0599.02242.0
\n", - "

2 rows × 24 columns

\n", - "
" - ], - "text/plain": [ - " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", - "0 Team 30.0 6025.0 767.0 1739.0 0.441 271.0 716.0 0.378 \n", - "1 Opponent 30.0 6025.0 834.0 1844.0 0.452 263.0 729.0 0.361 \n", - "\n", - " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", - "0 496.0 ... 0.737 245.0 680.0 925.0 517.0 212.0 61.0 420.0 \n", - "1 571.0 ... 0.748 254.0 659.0 913.0 510.0 232.0 65.0 357.0 \n", - "\n", - " pf pts \n", - "0 553.0 2141.0 \n", - "1 599.0 2242.0 \n", - "\n", - "[2 rows x 24 columns]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.all_team_opp_stats(2017, level = 'C')" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team32.07075.01028.02073.00.496315.0863.00.365713.0...0.748270.0830.01100.0567.0225.079.0464.0760.02847.0
1Opponent32.07075.0920.02169.00.424321.0894.00.359599.0...0.773319.0709.01028.0529.0221.044.0422.0719.02655.0
\n", - "

2 rows × 24 columns

\n", - "
" - ], - "text/plain": [ - " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", - "0 Team 32.0 7075.0 1028.0 2073.0 0.496 315.0 863.0 0.365 \n", - "1 Opponent 32.0 7075.0 920.0 2169.0 0.424 321.0 894.0 0.359 \n", - "\n", - " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", - "0 713.0 ... 0.748 270.0 830.0 1100.0 567.0 225.0 79.0 464.0 \n", - "1 599.0 ... 0.773 319.0 709.0 1028.0 529.0 221.0 44.0 422.0 \n", - "\n", - " pf pts \n", - "0 760.0 2847.0 \n", - "1 719.0 2655.0 \n", - "\n", - "[2 rows x 24 columns]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## per game table" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per_game(2017, level='B')" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-161.0NaN27.54.210.80.3901.65.20.307...0.21.31.64.11.00.12.52.312.3Tyrese Rice
1ante-tomic-161.0NaN22.44.37.30.5900.00.00.333...2.14.86.92.00.60.61.62.210.8Ante Tomic
2petteri-koponen-154.0NaN22.13.17.20.4361.63.80.417...0.31.71.92.10.70.11.31.99.4Petteri Koponen
3victor-claver-156.0NaN21.22.04.30.4710.92.20.395...0.83.44.31.20.90.41.32.05.5Victor Claver
4aleksandar-vezenkov-162.0NaN18.63.05.50.5531.12.70.420...0.92.33.21.00.60.20.71.98.3Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", - "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", - "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.6 5.2 0.307 ... 0.2 1.3 \n", - "1 0.0 0.0 0.333 ... 2.1 4.8 \n", - "2 1.6 3.8 0.417 ... 0.3 1.7 \n", - "3 0.9 2.2 0.395 ... 0.8 3.4 \n", - "4 1.1 2.7 0.420 ... 0.9 2.3 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 1.6 4.1 1.0 0.1 2.5 2.3 12.3 \n", - "1 6.9 2.0 0.6 0.6 1.6 2.2 10.8 \n", - "2 1.9 2.1 0.7 0.1 1.3 1.9 9.4 \n", - "3 4.3 1.2 0.9 0.4 1.3 2.0 5.5 \n", - "4 3.2 1.0 0.6 0.2 0.7 1.9 8.3 \n", - "\n", - " player_name \n", - "0 Tyrese Rice \n", - "1 Ante Tomic \n", - "2 Petteri Koponen \n", - "3 Victor Claver \n", - "4 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per_game(2017, level='E')" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-130.0NaN29.64.612.10.3761.85.70.320...0.31.41.64.91.10.12.62.113.0Tyrese Rice
1ante-tomic-129.0NaN21.83.66.90.5250.00.00.000...2.23.75.92.00.60.71.92.18.8Ante Tomic
2petteri-koponen-127.0NaN22.63.37.60.4292.04.40.462...0.21.51.71.90.70.01.31.910.1Petteri Koponen
3victor-claver-127.0NaN22.02.14.50.4590.92.30.377...0.93.54.41.30.90.31.21.76.0Victor Claver
4aleksandar-vezenkov-130.0NaN18.42.74.70.5771.12.40.479...0.82.43.21.10.70.20.61.57.5Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 29.6 4.6 12.1 0.376 \n", - "1 ante-tomic-1 29.0 NaN 21.8 3.6 6.9 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 22.6 3.3 7.6 0.429 \n", - "3 victor-claver-1 27.0 NaN 22.0 2.1 4.5 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 18.4 2.7 4.7 0.577 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.8 5.7 0.320 ... 0.3 1.4 \n", - "1 0.0 0.0 0.000 ... 2.2 3.7 \n", - "2 2.0 4.4 0.462 ... 0.2 1.5 \n", - "3 0.9 2.3 0.377 ... 0.9 3.5 \n", - "4 1.1 2.4 0.479 ... 0.8 2.4 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 1.6 4.9 1.1 0.1 2.6 2.1 13.0 \n", - "1 5.9 2.0 0.6 0.7 1.9 2.1 8.8 \n", - "2 1.7 1.9 0.7 0.0 1.3 1.9 10.1 \n", - "3 4.4 1.3 0.9 0.3 1.2 1.7 6.0 \n", - "4 3.2 1.1 0.7 0.2 0.6 1.5 7.5 \n", - "\n", - " player_name \n", - "0 Tyrese Rice \n", - "1 Ante Tomic \n", - "2 Petteri Koponen \n", - "3 Victor Claver \n", - "4 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per_game(2017, level='C')" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-131.030.025.53.89.50.4061.44.70.293...0.21.31.53.40.80.02.42.511.6Tyrese Rice
1ante-tomic-132.027.022.94.97.60.6430.00.10.500...2.05.87.92.10.60.51.32.312.7Ante Tomic
2aleksandar-vezenkov-132.06.018.93.36.10.5361.23.10.378...0.92.23.20.80.50.30.82.29.0Aleksandar Vezenkov
3brad-oleson-129.020.020.82.44.40.5471.22.60.453...0.61.21.81.70.60.11.11.67.0Brad Oleson
4victor-claver-129.023.020.41.94.00.4830.92.20.413...0.83.34.11.20.90.61.42.35.0Victor Claver
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 25.5 3.8 9.5 0.406 \n", - "1 ante-tomic-1 32.0 27.0 22.9 4.9 7.6 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 18.9 3.3 6.1 0.536 \n", - "3 brad-oleson-1 29.0 20.0 20.8 2.4 4.4 0.547 \n", - "4 victor-claver-1 29.0 23.0 20.4 1.9 4.0 0.483 \n", - "\n", - " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", - "0 1.4 4.7 0.293 ... 0.2 1.3 \n", - "1 0.0 0.1 0.500 ... 2.0 5.8 \n", - "2 1.2 3.1 0.378 ... 0.9 2.2 \n", - "3 1.2 2.6 0.453 ... 0.6 1.2 \n", - "4 0.9 2.2 0.413 ... 0.8 3.3 \n", - "\n", - " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", - "0 1.5 3.4 0.8 0.0 2.4 2.5 11.6 \n", - "1 7.9 2.1 0.6 0.5 1.3 2.3 12.7 \n", - "2 3.2 0.8 0.5 0.3 0.8 2.2 9.0 \n", - "3 1.8 1.7 0.6 0.1 1.1 1.6 7.0 \n", - "4 4.1 1.2 0.9 0.6 1.4 2.3 5.0 \n", - "\n", - " player_name \n", - "0 Tyrese Rice \n", - "1 Ante Tomic \n", - "2 Aleksandar Vezenkov \n", - "3 Brad Oleson \n", - "4 Victor Claver \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## totals table" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_totals(2017, level='B')" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-161.0NaN1680.0256.0657.00.39098.0319.00.307...15.080.095.0252.058.04.0151.0142.0750.0Tyrese Rice
1ante-tomic-161.0NaN1367.0262.0444.00.5901.03.00.333...128.0295.0423.0124.035.036.099.0135.0661.0Ante Tomic
2petteri-koponen-154.0NaN1196.0169.0388.00.43685.0204.00.417...15.090.0105.0112.039.03.071.0100.0509.0Petteri Koponen
3victor-claver-156.0NaN1187.0112.0238.00.47149.0124.00.395...46.0192.0238.069.051.024.074.0111.0309.0Victor Claver
4aleksandar-vezenkov-162.0NaN1156.0187.0338.00.55371.0169.00.420...55.0143.0198.061.037.015.045.0115.0513.0Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 319.0 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 3.0 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 204.0 \n", - "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 124.0 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 169.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk \\\n", - "0 0.307 ... 15.0 80.0 95.0 252.0 58.0 4.0 \n", - "1 0.333 ... 128.0 295.0 423.0 124.0 35.0 36.0 \n", - "2 0.417 ... 15.0 90.0 105.0 112.0 39.0 3.0 \n", - "3 0.395 ... 46.0 192.0 238.0 69.0 51.0 24.0 \n", - "4 0.420 ... 55.0 143.0 198.0 61.0 37.0 15.0 \n", - "\n", - " tov pf pts player_name \n", - "0 151.0 142.0 750.0 Tyrese Rice \n", - "1 99.0 135.0 661.0 Ante Tomic \n", - "2 71.0 100.0 509.0 Petteri Koponen \n", - "3 74.0 111.0 309.0 Victor Claver \n", - "4 45.0 115.0 513.0 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_totals(2017, level='E')" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-130.0NaN889.0137.0364.00.37655.0172.00.320...8.041.049.0146.034.03.077.063.0389.0Tyrese Rice
1ante-tomic-129.0NaN633.0105.0200.00.5250.01.00.000...63.0108.0171.058.017.020.056.062.0256.0Ante Tomic
2petteri-koponen-127.0NaN610.088.0205.00.42955.0119.00.462...5.041.046.051.020.00.036.052.0274.0Petteri Koponen
3victor-claver-127.0NaN594.056.0122.00.45923.061.00.377...23.095.0118.034.025.08.033.045.0163.0Victor Claver
4aleksandar-vezenkov-130.0NaN552.082.0142.00.57734.071.00.479...25.072.097.034.020.06.019.046.0226.0Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 137.0 364.0 0.376 55.0 172.0 \n", - "1 ante-tomic-1 29.0 NaN 633.0 105.0 200.0 0.525 0.0 1.0 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 88.0 205.0 0.429 55.0 119.0 \n", - "3 victor-claver-1 27.0 NaN 594.0 56.0 122.0 0.459 23.0 61.0 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 82.0 142.0 0.577 34.0 71.0 \n", - "\n", - " fg3_pct ... orb drb trb ast stl blk tov \\\n", - "0 0.320 ... 8.0 41.0 49.0 146.0 34.0 3.0 77.0 \n", - "1 0.000 ... 63.0 108.0 171.0 58.0 17.0 20.0 56.0 \n", - "2 0.462 ... 5.0 41.0 46.0 51.0 20.0 0.0 36.0 \n", - "3 0.377 ... 23.0 95.0 118.0 34.0 25.0 8.0 33.0 \n", - "4 0.479 ... 25.0 72.0 97.0 34.0 20.0 6.0 19.0 \n", - "\n", - " pf pts player_name \n", - "0 63.0 389.0 Tyrese Rice \n", - "1 62.0 256.0 Ante Tomic \n", - "2 52.0 274.0 Petteri Koponen \n", - "3 45.0 163.0 Victor Claver \n", - "4 46.0 226.0 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_totals(2017, level='C')" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-131.030.0791.0119.0293.00.40643.0147.00.293...7.039.046.0106.024.01.074.079.0361.0Tyrese Rice
1ante-tomic-132.027.0734.0157.0244.00.6431.02.00.500...65.0187.0252.066.018.016.043.073.0405.0Ante Tomic
2aleksandar-vezenkov-132.06.0604.0105.0196.00.53637.098.00.378...30.071.0101.027.017.09.026.069.0287.0Aleksandar Vezenkov
3brad-oleson-129.020.0603.070.0128.00.54734.075.00.453...17.036.053.049.018.04.031.047.0202.0Brad Oleson
4victor-claver-129.023.0593.056.0116.00.48326.063.00.413...23.097.0120.035.026.016.041.066.0146.0Victor Claver
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg fga fg_pct fg3 \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 119.0 293.0 0.406 43.0 \n", - "1 ante-tomic-1 32.0 27.0 734.0 157.0 244.0 0.643 1.0 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 105.0 196.0 0.536 37.0 \n", - "3 brad-oleson-1 29.0 20.0 603.0 70.0 128.0 0.547 34.0 \n", - "4 victor-claver-1 29.0 23.0 593.0 56.0 116.0 0.483 26.0 \n", - "\n", - " fg3a fg3_pct ... orb drb trb ast stl blk \\\n", - "0 147.0 0.293 ... 7.0 39.0 46.0 106.0 24.0 1.0 \n", - "1 2.0 0.500 ... 65.0 187.0 252.0 66.0 18.0 16.0 \n", - "2 98.0 0.378 ... 30.0 71.0 101.0 27.0 17.0 9.0 \n", - "3 75.0 0.453 ... 17.0 36.0 53.0 49.0 18.0 4.0 \n", - "4 63.0 0.413 ... 23.0 97.0 120.0 35.0 26.0 16.0 \n", - "\n", - " tov pf pts player_name \n", - "0 74.0 79.0 361.0 Tyrese Rice \n", - "1 43.0 73.0 405.0 Ante Tomic \n", - "2 26.0 69.0 287.0 Aleksandar Vezenkov \n", - "3 31.0 47.0 202.0 Brad Oleson \n", - "4 41.0 66.0 146.0 Victor Claver \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## per36 table" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per36(2017, level='B')" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-161.0NaN1680.05.514.10.3902.16.80.307...0.31.72.05.41.20.13.23.016.1Tyrese Rice
1ante-tomic-161.0NaN1367.06.911.70.5900.00.10.333...3.47.811.13.30.90.92.63.617.4Ante Tomic
2petteri-koponen-154.0NaN1196.05.111.70.4362.66.10.417...0.52.73.23.41.20.12.13.015.3Petteri Koponen
3victor-claver-156.0NaN1187.03.47.20.4711.53.80.395...1.45.87.22.11.50.72.23.49.4Victor Claver
4aleksandar-vezenkov-162.0NaN1156.05.810.50.5532.25.30.420...1.74.56.21.91.20.51.43.616.0Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", - "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", - "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", - "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", - "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.1 6.8 0.307 ... 0.3 \n", - "1 0.0 0.1 0.333 ... 3.4 \n", - "2 2.6 6.1 0.417 ... 0.5 \n", - "3 1.5 3.8 0.395 ... 1.4 \n", - "4 2.2 5.3 0.420 ... 1.7 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", - "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", - "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", - "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.0 16.1 Tyrese Rice \n", - "1 3.6 17.4 Ante Tomic \n", - "2 3.0 15.3 Petteri Koponen \n", - "3 3.4 9.4 Victor Claver \n", - "4 3.6 16.0 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per36(2017, level='E')" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-130.0NaN889.05.514.70.3762.27.00.320...0.31.72.05.91.40.13.12.615.8Tyrese Rice
1ante-tomic-129.0NaN633.06.011.40.5250.00.10.000...3.66.19.73.31.01.13.23.514.6Ante Tomic
2petteri-koponen-127.0NaN610.05.212.10.4293.27.00.462...0.32.42.73.01.20.02.13.116.2Petteri Koponen
3victor-claver-127.0NaN594.03.47.40.4591.43.70.377...1.45.87.22.11.50.52.02.79.9Victor Claver
4aleksandar-vezenkov-130.0NaN552.05.39.30.5772.24.60.479...1.64.76.32.21.30.41.23.014.7Aleksandar Vezenkov
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 30.0 NaN 889.0 5.5 14.7 0.376 \n", - "1 ante-tomic-1 29.0 NaN 633.0 6.0 11.4 0.525 \n", - "2 petteri-koponen-1 27.0 NaN 610.0 5.2 12.1 0.429 \n", - "3 victor-claver-1 27.0 NaN 594.0 3.4 7.4 0.459 \n", - "4 aleksandar-vezenkov-1 30.0 NaN 552.0 5.3 9.3 0.577 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.2 7.0 0.320 ... 0.3 \n", - "1 0.0 0.1 0.000 ... 3.6 \n", - "2 3.2 7.0 0.462 ... 0.3 \n", - "3 1.4 3.7 0.377 ... 1.4 \n", - "4 2.2 4.6 0.479 ... 1.6 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.7 2.0 5.9 1.4 0.1 3.1 \n", - "1 6.1 9.7 3.3 1.0 1.1 3.2 \n", - "2 2.4 2.7 3.0 1.2 0.0 2.1 \n", - "3 5.8 7.2 2.1 1.5 0.5 2.0 \n", - "4 4.7 6.3 2.2 1.3 0.4 1.2 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 2.6 15.8 Tyrese Rice \n", - "1 3.5 14.6 Ante Tomic \n", - "2 3.1 16.2 Petteri Koponen \n", - "3 2.7 9.9 Victor Claver \n", - "4 3.0 14.7 Aleksandar Vezenkov \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_per36(2017, level='C')" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-131.030.0791.05.413.30.4062.06.70.293...0.31.82.14.81.10.03.43.616.4Tyrese Rice
1ante-tomic-132.027.0734.07.712.00.6430.00.10.500...3.29.212.43.20.90.82.13.619.9Ante Tomic
2aleksandar-vezenkov-132.06.0604.06.311.70.5362.25.80.378...1.84.26.01.61.00.51.54.117.1Aleksandar Vezenkov
3brad-oleson-129.020.0603.04.27.60.5472.04.50.453...1.02.13.22.91.10.21.92.812.1Brad Oleson
4victor-claver-129.023.0593.03.47.00.4831.63.80.413...1.45.97.32.11.61.02.54.08.9Victor Claver
\n", - "

5 rows × 26 columns

\n", - "
" - ], - "text/plain": [ - " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", - "0 tyrese-rice-1 31.0 30.0 791.0 5.4 13.3 0.406 \n", - "1 ante-tomic-1 32.0 27.0 734.0 7.7 12.0 0.643 \n", - "2 aleksandar-vezenkov-1 32.0 6.0 604.0 6.3 11.7 0.536 \n", - "3 brad-oleson-1 29.0 20.0 603.0 4.2 7.6 0.547 \n", - "4 victor-claver-1 29.0 23.0 593.0 3.4 7.0 0.483 \n", - "\n", - " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", - "0 2.0 6.7 0.293 ... 0.3 \n", - "1 0.0 0.1 0.500 ... 3.2 \n", - "2 2.2 5.8 0.378 ... 1.8 \n", - "3 2.0 4.5 0.453 ... 1.0 \n", - "4 1.6 3.8 0.413 ... 1.4 \n", - "\n", - " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", - "0 1.8 2.1 4.8 1.1 0.0 3.4 \n", - "1 9.2 12.4 3.2 0.9 0.8 2.1 \n", - "2 4.2 6.0 1.6 1.0 0.5 1.5 \n", - "3 2.1 3.2 2.9 1.1 0.2 1.9 \n", - "4 5.9 7.3 2.1 1.6 1.0 2.5 \n", - "\n", - " pf_per_mp pts_per_mp player_name \n", - "0 3.6 16.4 Tyrese Rice \n", - "1 3.6 19.9 Ante Tomic \n", - "2 4.1 17.1 Aleksandar Vezenkov \n", - "3 2.8 12.1 Brad Oleson \n", - "4 4.0 8.9 Victor Claver \n", - "\n", - "[5 rows x 26 columns]" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Advanced stats table" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_advanced(2017, level='B')" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-161.01680.00.511NaN0.4860.26531.017.126.9Tyrese Rice
1ante-tomic-161.01367.00.605NaN0.0070.52520.415.324.1Ante Tomic
2petteri-koponen-154.01196.00.593NaN0.5260.24218.914.221.4Petteri Koponen
3victor-claver-156.01187.00.594NaN0.5210.21010.722.214.4Victor Claver
4aleksandar-vezenkov-162.01156.00.686NaN0.5000.24011.110.718.5Aleksandar Vezenkov
\n", - "
" - ], - "text/plain": [ - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", - "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", - "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", - "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", - "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", - "1 0.525 20.4 15.3 24.1 Ante Tomic \n", - "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", - "3 0.210 10.7 22.2 14.4 Victor Claver \n", - "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_advanced(2017, level='E')" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-130.0889.00.4910.4520.4730.20134.016.327.2Tyrese Rice
1ante-tomic-129.0633.00.5310.5250.0050.46519.518.924.0Ante Tomic
2petteri-koponen-127.0610.00.6070.5630.5800.22917.013.821.9Petteri Koponen
3victor-claver-127.0594.00.5910.5530.5000.29510.619.314.7Victor Claver
4aleksandar-vezenkov-130.0552.00.7220.6970.5000.23212.610.816.2Aleksandar Vezenkov
\n", - "
" - ], - "text/plain": [ - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 30.0 889.0 0.491 0.452 0.473 \n", - "1 ante-tomic-1 29.0 633.0 0.531 0.525 0.005 \n", - "2 petteri-koponen-1 27.0 610.0 0.607 0.563 0.580 \n", - "3 victor-claver-1 27.0 594.0 0.591 0.553 0.500 \n", - "4 aleksandar-vezenkov-1 30.0 552.0 0.722 0.697 0.500 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.201 34.0 16.3 27.2 Tyrese Rice \n", - "1 0.465 19.5 18.9 24.0 Ante Tomic \n", - "2 0.229 17.0 13.8 21.9 Petteri Koponen \n", - "3 0.295 10.6 19.3 14.7 Victor Claver \n", - "4 0.232 12.6 10.8 16.2 Aleksandar Vezenkov " - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = t.stats_advanced(2017, level='C')" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-131.0791.00.5350.4800.5020.34527.618.026.6Tyrese Rice
1ante-tomic-132.0734.00.6630.6450.0080.57421.312.324.3Ante Tomic
2aleksandar-vezenkov-132.0604.00.6610.6300.5000.2459.710.720.6Aleksandar Vezenkov
3brad-oleson-129.0603.00.7110.6800.5860.25015.617.914.7Brad Oleson
4victor-claver-129.0593.00.5980.5950.5430.12110.925.114.1Victor Claver
\n", - "
" - ], - "text/plain": [ - " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", - "0 tyrese-rice-1 31.0 791.0 0.535 0.480 0.502 \n", - "1 ante-tomic-1 32.0 734.0 0.663 0.645 0.008 \n", - "2 aleksandar-vezenkov-1 32.0 604.0 0.661 0.630 0.500 \n", - "3 brad-oleson-1 29.0 603.0 0.711 0.680 0.586 \n", - "4 victor-claver-1 29.0 593.0 0.598 0.595 0.543 \n", - "\n", - " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", - "0 0.345 27.6 18.0 26.6 Tyrese Rice \n", - "1 0.574 21.3 12.3 24.3 Ante Tomic \n", - "2 0.245 9.7 10.7 20.6 Aleksandar Vezenkov \n", - "3 0.250 15.6 17.9 14.7 Brad Oleson \n", - "4 0.121 10.9 25.1 14.1 Victor Claver " - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/sportsref/euro/seasons.py b/sportsref/euro/seasons.py index 96beaad..29188ae 100644 --- a/sportsref/euro/seasons.py +++ b/sportsref/euro/seasons.py @@ -9,12 +9,13 @@ class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - """Object representing a given NBA season.""" + """Object representing a given Euro season.""" def __init__(self, year, league_id): - """Initializes a Season object for an NBA season. + """Initializes a Season object for an Euro season. :year: The year of the season we want. + :league_id: The league_id that we want (list of league_ids can be obtained by euro.LEAGUE_IDS """ self.yr = int(year) self.lg_id = league_id @@ -43,8 +44,7 @@ def get_main_doc(self): @sportsref.decorators.memoize def get_schedule_doc(self): - """Returns PyQuery object for a given subpage URL. - :subpage: The subpage of the season, e.g. 'per_game'. + """Returns PyQuery object for a given schedule URL. :returns: PyQuery object. """ html = sportsref.utils.get_html(self._schedule_url()) @@ -64,7 +64,7 @@ def get_team_ids(self): @sportsref.decorators.memoize def team_ids_to_names(self): - """Mapping from 3-letter team IDs to full team names. + """Mapping from team IDs to full team names. :returns: Dictionary with team IDs as keys and full team strings as values. """ @@ -84,7 +84,7 @@ def team_ids_to_names(self): @sportsref.decorators.memoize def team_names_to_ids(self): - """Mapping from full team names to 3-letter team IDs. + """Mapping from full team names to team IDs. :returns: Dictionary with tean names as keys and team IDs as values. """ d = self.team_ids_to_names() @@ -96,7 +96,7 @@ def schedule(self, kind='R'): """Returns a list of BoxScore IDs for every game in the season. Only needs to handle 'R' or 'P' options because decorator handles 'B'. - :param kind: 'R' for regular season, 'P' for playoffs, 'B' for both. + :param kind: 'R' for regular season (club play), 'P' for playoffs (euroleague), 'B' for both. Defaults to 'R'. :returns: DataFrame of schedule information. :rtype: pd.DataFrame diff --git a/test_notebooks/euro/euro_season_test.ipynb b/test_notebooks/euro/euro_season_test.ipynb new file mode 100644 index 0000000..abd08ab --- /dev/null +++ b/test_notebooks/euro/euro_season_test.ipynb @@ -0,0 +1,1255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# euro.Season test notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "from sportsref import euro" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Need league_id to initialize - list of league_ids can be obtained with euro.LEAGUE_IDS" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['greek-basket-league', 'eurocup', 'spain-liga-acb', 'italy-basket-serie-a', 'france-lnb-pro-a', 'euroleague']\n" + ] + } + ], + "source": [ + "print(euro.LEAGUE_IDS)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "season = euro.Season(2017, 'france-lnb-pro-a', )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Helper methods" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['chalon', 'strasbourg', 'villeurbanne', 'monaco', 'paris-levallois', 'nanterre', 'gravelines', 'chalons-en-champagne', 'limoges', 'nancy', 'cholet', 'dijon', 'orleans', 'le-mans', 'pau-orthez', 'le-portel', 'hyeres-toulon', 'antibes']\n" + ] + } + ], + "source": [ + "print(season.get_team_ids())" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'chalon': 'Chalon/Saone', 'strasbourg': 'Strasbourg', 'villeurbanne': 'Lyon-Villeurbanne', 'monaco': 'Monaco', 'paris-levallois': 'Paris-Levallois', 'nanterre': 'Nanterre', 'gravelines': 'Gravelines-Dunkerque', 'chalons-en-champagne': 'Chalons-Reims', 'limoges': 'Limoges', 'nancy': 'Nancy', 'cholet': 'Cholet', 'dijon': 'Dijon', 'orleans': 'Orleans', 'le-mans': 'Le Mans', 'pau-orthez': 'Pau-Lacq-Orthez', 'le-portel': 'Le Portel', 'hyeres-toulon': 'Hyeres-Toulon', 'antibes': 'Antibes'}\n" + ] + } + ], + "source": [ + "print(season.team_ids_to_names())" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Chalon/Saone': 'chalon', 'Strasbourg': 'strasbourg', 'Lyon-Villeurbanne': 'villeurbanne', 'Monaco': 'monaco', 'Paris-Levallois': 'paris-levallois', 'Nanterre': 'nanterre', 'Gravelines-Dunkerque': 'gravelines', 'Chalons-Reims': 'chalons-en-champagne', 'Limoges': 'limoges', 'Nancy': 'nancy', 'Cholet': 'cholet', 'Dijon': 'dijon', 'Orleans': 'orleans', 'Le Mans': 'le-mans', 'Pau-Lacq-Orthez': 'pau-orthez', 'Le Portel': 'le-portel', 'Hyeres-Toulon': 'hyeres-toulon', 'Antibes': 'antibes'}\n" + ] + } + ], + "source": [ + "print(season.team_names_to_ids())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Schedule\n", + "\n", + "### takes kind argument: \n", + "#### R (Club play)\n", + "#### P (Euroleague play)\n", + "#### B (both)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "347\n", + "24\n", + "323\n" + ] + } + ], + "source": [ + "print(len(season.schedule(kind='B')))\n", + "print(len(season.schedule(kind='P')))\n", + "print(len(season.schedule(kind='R')))" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idvisitor_team_namevisitor_ptshome_team_namehome_ptsboxscore_idovertimesnotesis_playoffs
02016-09-23-hyeres-toulonGravelines-Dunkerque62.0Hyeres-Toulon75.0NaNNaNNaNFalse
12016-09-23-le-portelNanterre84.0Le Portel65.0NaNNaNNaNFalse
22016-09-23-paris-levalloisNancy67.0Paris-Levallois75.0NaNNaNNaNFalse
32016-09-24-chalonOrleans67.0Chalon/Saone87.0NaNNaNNaNFalse
42016-09-24-chalons-en-champagneAntibes92.0Chalons-Reims77.0NaNNaNNaNFalse
\n", + "
" + ], + "text/plain": [ + " boxscore_id visitor_team_name visitor_pts \\\n", + "0 2016-09-23-hyeres-toulon Gravelines-Dunkerque 62.0 \n", + "1 2016-09-23-le-portel Nanterre 84.0 \n", + "2 2016-09-23-paris-levallois Nancy 67.0 \n", + "3 2016-09-24-chalon Orleans 67.0 \n", + "4 2016-09-24-chalons-en-champagne Antibes 92.0 \n", + "\n", + " home_team_name home_pts boxscore_id overtimes notes is_playoffs \n", + "0 Hyeres-Toulon 75.0 NaN NaN NaN False \n", + "1 Le Portel 65.0 NaN NaN NaN False \n", + "2 Paris-Levallois 75.0 NaN NaN NaN False \n", + "3 Chalon/Saone 87.0 NaN NaN NaN False \n", + "4 Chalons-Reims 77.0 NaN NaN NaN False " + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.schedule(kind='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idvisitor_team_namevisitor_ptshome_team_namehome_ptsboxscore_idovertimesnotesis_playoffs
02017-05-22-monacoLyon-Villeurbanne72.0Monaco69.0NaNNaNNaNTrue
12017-05-22-strasbourgPau-Lacq-Orthez102.0Strasbourg92.0NaNNaNNaNTrue
22017-05-23-chalonLe Portel63.0Chalon/Saone76.0NaNNaNNaNTrue
32017-05-23-nanterreParis-Levallois88.0Nanterre85.0NaNNaNNaNTrue
42017-05-24-pau-orthezStrasbourg83.0Pau-Lacq-Orthez68.0NaNNaNNaNTrue
\n", + "
" + ], + "text/plain": [ + " boxscore_id visitor_team_name visitor_pts home_team_name \\\n", + "0 2017-05-22-monaco Lyon-Villeurbanne 72.0 Monaco \n", + "1 2017-05-22-strasbourg Pau-Lacq-Orthez 102.0 Strasbourg \n", + "2 2017-05-23-chalon Le Portel 63.0 Chalon/Saone \n", + "3 2017-05-23-nanterre Paris-Levallois 88.0 Nanterre \n", + "4 2017-05-24-pau-orthez Strasbourg 83.0 Pau-Lacq-Orthez \n", + "\n", + " home_pts boxscore_id overtimes notes is_playoffs \n", + "0 69.0 NaN NaN NaN True \n", + "1 92.0 NaN NaN NaN True \n", + "2 76.0 NaN NaN NaN True \n", + "3 85.0 NaN NaN NaN True \n", + "4 68.0 NaN NaN NaN True " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.schedule(kind='P').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idvisitor_team_namevisitor_ptshome_team_namehome_ptsboxscore_idovertimesnotesis_playoffs
02016-09-23-hyeres-toulonGravelines-Dunkerque62.0Hyeres-Toulon75.0NaNNaNNaNFalse
12016-09-23-le-portelNanterre84.0Le Portel65.0NaNNaNNaNFalse
22016-09-23-paris-levalloisNancy67.0Paris-Levallois75.0NaNNaNNaNFalse
32016-09-24-chalonOrleans67.0Chalon/Saone87.0NaNNaNNaNFalse
42016-09-24-chalons-en-champagneAntibes92.0Chalons-Reims77.0NaNNaNNaNFalse
\n", + "
" + ], + "text/plain": [ + " boxscore_id visitor_team_name visitor_pts \\\n", + "0 2016-09-23-hyeres-toulon Gravelines-Dunkerque 62.0 \n", + "1 2016-09-23-le-portel Nanterre 84.0 \n", + "2 2016-09-23-paris-levallois Nancy 67.0 \n", + "3 2016-09-24-chalon Orleans 67.0 \n", + "4 2016-09-24-chalons-en-champagne Antibes 92.0 \n", + "\n", + " home_team_name home_pts boxscore_id overtimes notes is_playoffs \n", + "0 Hyeres-Toulon 75.0 NaN NaN NaN False \n", + "1 Le Portel 65.0 NaN NaN NaN False \n", + "2 Paris-Levallois 75.0 NaN NaN NaN False \n", + "3 Chalon/Saone 87.0 NaN NaN NaN False \n", + "4 Chalons-Reims 77.0 NaN NaN NaN False " + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.schedule(kind='R').head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Standings (no args)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
winslosseswin_loss_pctgbpts_per_gopp_pts_per_gwins_pythlosses_pythwins_playoffslosses_playoffswin_loss_pct_playoffspts_per_g_playoffsopp_pts_per_g_playoffswins_pyth_playoffslosses_pyth_playoffshas_class_full_table
team_id
monaco30.04.00.88290.679.929.05.0NaN1.02.00.33370.370.71.02.0True
chalon27.07.00.7943109.699.527.07.0NaN8.03.00.72777.772.08.03.0True
nanterre25.09.00.735585.980.724.010.0NaN0.02.00.00078.082.51.01.0True
strasbourg23.011.00.6767107.5101.024.010.0NaN7.06.00.53874.274.46.07.0True
pau-orthez21.012.00.6368.585.582.021.012.0NaN1.02.00.33379.382.31.02.0True
\n", + "
" + ], + "text/plain": [ + " wins losses win_loss_pct gb pts_per_g opp_pts_per_g \\\n", + "team_id \n", + "monaco 30.0 4.0 0.882 — 90.6 79.9 \n", + "chalon 27.0 7.0 0.794 3 109.6 99.5 \n", + "nanterre 25.0 9.0 0.735 5 85.9 80.7 \n", + "strasbourg 23.0 11.0 0.676 7 107.5 101.0 \n", + "pau-orthez 21.0 12.0 0.636 8.5 85.5 82.0 \n", + "\n", + " wins_pyth losses_pyth wins_playoffs losses_playoffs \\\n", + "team_id \n", + "monaco 29.0 5.0 NaN 1.0 2.0 \n", + "chalon 27.0 7.0 NaN 8.0 3.0 \n", + "nanterre 24.0 10.0 NaN 0.0 2.0 \n", + "strasbourg 24.0 10.0 NaN 7.0 6.0 \n", + "pau-orthez 21.0 12.0 NaN 1.0 2.0 \n", + "\n", + " win_loss_pct_playoffs pts_per_g_playoffs opp_pts_per_g_playoffs \\\n", + "team_id \n", + "monaco 0.333 70.3 70.7 \n", + "chalon 0.727 77.7 72.0 \n", + "nanterre 0.000 78.0 82.5 \n", + "strasbourg 0.538 74.2 74.4 \n", + "pau-orthez 0.333 79.3 82.3 \n", + "\n", + " wins_pyth_playoffs losses_pyth_playoffs has_class_full_table \n", + "team_id \n", + "monaco 1.0 2.0 True \n", + "chalon 8.0 3.0 True \n", + "nanterre 1.0 1.0 True \n", + "strasbourg 6.0 7.0 True \n", + "pau-orthez 1.0 2.0 True " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.standings().head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## team stat tables (no args)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gfgfgafg_pctfg3fg3afg3_pctfg2fg2afg2_pct...ft_pctorbdrbtrbaststlblktovpfpts
team_id
chalon34.01381.02770.00.499357.0968.00.3691024.01802.00.568...0.706378.01117.01495.0819.0240.0159.0512.0738.03726.0
strasbourg34.01335.02900.00.460365.0969.00.377970.01931.00.502...0.704461.01096.01557.0894.0329.0123.0584.0977.03654.0
villeurbanne34.01107.02437.00.454299.0868.00.344808.01569.00.515...0.747340.01003.01343.0733.0259.0122.0559.0835.03107.0
monaco34.01107.02417.00.458306.0861.00.355801.01556.00.515...0.742439.0819.01258.0693.0326.0130.0448.0806.03080.0
paris-levallois34.01142.02524.00.452252.0768.00.328890.01756.00.507...0.696426.0979.01405.0642.0245.0109.0506.0844.03061.0
\n", + "

5 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " g fg fga fg_pct fg3 fg3a fg3_pct fg2 \\\n", + "team_id \n", + "chalon 34.0 1381.0 2770.0 0.499 357.0 968.0 0.369 1024.0 \n", + "strasbourg 34.0 1335.0 2900.0 0.460 365.0 969.0 0.377 970.0 \n", + "villeurbanne 34.0 1107.0 2437.0 0.454 299.0 868.0 0.344 808.0 \n", + "monaco 34.0 1107.0 2417.0 0.458 306.0 861.0 0.355 801.0 \n", + "paris-levallois 34.0 1142.0 2524.0 0.452 252.0 768.0 0.328 890.0 \n", + "\n", + " fg2a fg2_pct ... ft_pct orb drb trb \\\n", + "team_id ... \n", + "chalon 1802.0 0.568 ... 0.706 378.0 1117.0 1495.0 \n", + "strasbourg 1931.0 0.502 ... 0.704 461.0 1096.0 1557.0 \n", + "villeurbanne 1569.0 0.515 ... 0.747 340.0 1003.0 1343.0 \n", + "monaco 1556.0 0.515 ... 0.742 439.0 819.0 1258.0 \n", + "paris-levallois 1756.0 0.507 ... 0.696 426.0 979.0 1405.0 \n", + "\n", + " ast stl blk tov pf pts \n", + "team_id \n", + "chalon 819.0 240.0 159.0 512.0 738.0 3726.0 \n", + "strasbourg 894.0 329.0 123.0 584.0 977.0 3654.0 \n", + "villeurbanne 733.0 259.0 122.0 559.0 835.0 3107.0 \n", + "monaco 693.0 326.0 130.0 448.0 806.0 3080.0 \n", + "paris-levallois 642.0 245.0 109.0 506.0 844.0 3061.0 \n", + "\n", + "[5 rows x 22 columns]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.team_stats_totals().head()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pctfg2_per_gfg2a_per_gfg2_pct...ft_pctorb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_g
team_id
chalon34.040.681.50.49910.528.50.36930.153.00.568...0.70611.132.944.024.17.14.715.121.7109.6
strasbourg34.039.385.30.46010.728.50.37728.556.80.502...0.70413.632.245.826.39.73.617.228.7107.5
villeurbanne34.032.671.70.4548.825.50.34423.846.10.515...0.74710.029.539.521.67.63.616.424.691.4
monaco34.032.671.10.4589.025.30.35523.645.80.515...0.74212.924.137.020.49.63.813.223.790.6
paris-levallois34.033.674.20.4527.422.60.32826.251.60.507...0.69612.528.841.318.97.23.214.924.890.0
\n", + "

5 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " g fg_per_g fga_per_g fg_pct fg3_per_g fg3a_per_g \\\n", + "team_id \n", + "chalon 34.0 40.6 81.5 0.499 10.5 28.5 \n", + "strasbourg 34.0 39.3 85.3 0.460 10.7 28.5 \n", + "villeurbanne 34.0 32.6 71.7 0.454 8.8 25.5 \n", + "monaco 34.0 32.6 71.1 0.458 9.0 25.3 \n", + "paris-levallois 34.0 33.6 74.2 0.452 7.4 22.6 \n", + "\n", + " fg3_pct fg2_per_g fg2a_per_g fg2_pct ... ft_pct \\\n", + "team_id ... \n", + "chalon 0.369 30.1 53.0 0.568 ... 0.706 \n", + "strasbourg 0.377 28.5 56.8 0.502 ... 0.704 \n", + "villeurbanne 0.344 23.8 46.1 0.515 ... 0.747 \n", + "monaco 0.355 23.6 45.8 0.515 ... 0.742 \n", + "paris-levallois 0.328 26.2 51.6 0.507 ... 0.696 \n", + "\n", + " orb_per_g drb_per_g trb_per_g ast_per_g stl_per_g \\\n", + "team_id \n", + "chalon 11.1 32.9 44.0 24.1 7.1 \n", + "strasbourg 13.6 32.2 45.8 26.3 9.7 \n", + "villeurbanne 10.0 29.5 39.5 21.6 7.6 \n", + "monaco 12.9 24.1 37.0 20.4 9.6 \n", + "paris-levallois 12.5 28.8 41.3 18.9 7.2 \n", + "\n", + " blk_per_g tov_per_g pf_per_g pts_per_g \n", + "team_id \n", + "chalon 4.7 15.1 21.7 109.6 \n", + "strasbourg 3.6 17.2 28.7 107.5 \n", + "villeurbanne 3.6 16.4 24.6 91.4 \n", + "monaco 3.8 13.2 23.7 90.6 \n", + "paris-levallois 3.2 14.9 24.8 90.0 \n", + "\n", + "[5 rows x 22 columns]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "season.team_stats_per_game().head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From bed3efed6644dfc10fddb2246fa014659ac498d1 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 22:34:21 -0500 Subject: [PATCH 50/57] commented euro player + added test notebook --- sportsref/euro/players.py | 9 +- test_notebooks/euro/euro_player_test.ipynb | 3740 ++++++++++++++++++++ 2 files changed, 3746 insertions(+), 3 deletions(-) create mode 100644 test_notebooks/euro/euro_player_test.ipynb diff --git a/sportsref/euro/players.py b/sportsref/euro/players.py index e70dcb1..b339eec 100644 --- a/sportsref/euro/players.py +++ b/sportsref/euro/players.py @@ -17,7 +17,7 @@ class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - """Each instance of this class represents an EuroBB player, uniquely + """Each instance of this class represents an Euro player, uniquely identified by a player ID. The instance methods give various data available from the player's Sports Reference player page.""" @@ -95,8 +95,8 @@ def age(self, year, month=2, day=1): @sportsref.decorators.memoize def position(self): - """TODO: Docstring for position. - :returns: TODO + """Returns the position of a player (note: not consistently coded in bballref) + :returns: Position """ doc = self.get_main_doc() raw = doc('p:contains("Position:")').text() @@ -105,6 +105,9 @@ def position(self): @sportsref.decorators.memoize def nba_id(self): + """Returns the euro player's NBA bballref id if they played in the NBA, None if they haven't + :returns: NBA_ID + """ doc = self.get_main_doc() p = doc('p:contains("NBA Career:")') href = '' diff --git a/test_notebooks/euro/euro_player_test.ipynb b/test_notebooks/euro/euro_player_test.ipynb new file mode 100644 index 0000000..9c7892c --- /dev/null +++ b/test_notebooks/euro/euro_player_test.ipynb @@ -0,0 +1,3740 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# euro.Player test" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from sportsref import euro" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "player = euro.Player('victor-claver-1')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## simple methods: Almost no changes" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Victor Claver\n", + "28.443835616438356\n", + "81\n", + "224\n" + ] + } + ], + "source": [ + "print(player.name())\n", + "print(player.age(2017))\n", + "print(player.height())\n", + "print(player.weight())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Added position and nba_id\n", + "### If player also played in NBA, returns their bballref id, if not, returns None" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SForward\n", + "clavevi01\n" + ] + } + ], + "source": [ + "print(player.position())\n", + "print(player.nba_id())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Gamelogs - different url style" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(2016, 'ELG'), (2017, 'ELG'), (2017, 'SPA'), (2018, 'ELG'), (2018, 'SPA')]\n" + ] + } + ], + "source": [ + "# new method: to me, would be useful/necessary\n", + "# because gamelogs are split by league and year\n", + "\n", + "print(p.available_gamelogs())" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02016-10-02-manresa28-033BarcelonaFalseManresaW17.8500000.04.00.000...0.03.03.00.02.02.03.01.00.0-1.9
12016-10-09-barcelona28-040BarcelonaTrueVitoriaW24.4833331.04.00.250...1.05.06.02.00.01.02.01.02.01.5
22016-10-16-bilbao28-047BarcelonaFalseBilbaoL18.4666670.02.00.000...0.00.00.02.00.00.02.05.01.0-3.4
32016-10-23-barcelona28-054BarcelonaTrueSevillaW19.3166671.03.00.333...0.02.02.02.01.00.02.01.02.00.9
42016-10-30-fuenlabrada28-061BarcelonaFalseFuenlabradaW10.2500000.02.00.000...0.01.01.00.01.00.01.02.00.0-1.9
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " boxscore_id age team_id is_home opp_id \\\n", + "0 2016-10-02-manresa 28-033 Barcelona False Manresa \n", + "1 2016-10-09-barcelona 28-040 Barcelona True Vitoria \n", + "2 2016-10-16-bilbao 28-047 Barcelona False Bilbao \n", + "3 2016-10-23-barcelona 28-054 Barcelona True Sevilla \n", + "4 2016-10-30-fuenlabrada 28-061 Barcelona False Fuenlabrada \n", + "\n", + " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", + "0 W 17.850000 0.0 4.0 0.000 ... 0.0 3.0 3.0 0.0 \n", + "1 W 24.483333 1.0 4.0 0.250 ... 1.0 5.0 6.0 2.0 \n", + "2 L 18.466667 0.0 2.0 0.000 ... 0.0 0.0 0.0 2.0 \n", + "3 W 19.316667 1.0 3.0 0.333 ... 0.0 2.0 2.0 2.0 \n", + "4 W 10.250000 0.0 2.0 0.000 ... 0.0 1.0 1.0 0.0 \n", + "\n", + " stl blk tov pf pts game_score \n", + "0 2.0 2.0 3.0 1.0 0.0 -1.9 \n", + "1 0.0 1.0 2.0 1.0 2.0 1.5 \n", + "2 0.0 0.0 2.0 5.0 1.0 -3.4 \n", + "3 1.0 0.0 2.0 1.0 2.0 0.9 \n", + "4 1.0 0.0 1.0 2.0 0.0 -1.9 \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player.gamelog_basic(2017, 'SPA').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
boxscore_idageteam_idis_homeopp_idgame_resultmpfgfgafg_pct...orbdrbtrbaststlblktovpfptsgame_score
02017-11-03-barcelona29-065BarcelonaTrueOlympiakosW11.5000000.02.00.000...0.02.02.01.02.01.00.03.00.01.4
12017-11-09-barcelona29-071BarcelonaTrueAnadolu-EfesL15.2166675.07.00.714...2.00.02.01.03.00.00.01.012.013.8
22017-11-15-brose-baskets29-077BarcelonaFalseBrose-BasketsL15.8166671.03.00.333...0.04.04.01.00.00.02.01.03.00.8
32017-11-23-barcelona29-085BarcelonaTrueMaccabi-Tel-AvivW17.3333331.03.00.333...1.02.03.02.00.00.00.04.03.02.4
42017-12-01-cska-moscow29-093BarcelonaFalseCska-MoscowL6.5833330.00.0NaN...0.01.01.00.00.00.01.01.00.0-1.1
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " boxscore_id age team_id is_home opp_id \\\n", + "0 2017-11-03-barcelona 29-065 Barcelona True Olympiakos \n", + "1 2017-11-09-barcelona 29-071 Barcelona True Anadolu-Efes \n", + "2 2017-11-15-brose-baskets 29-077 Barcelona False Brose-Baskets \n", + "3 2017-11-23-barcelona 29-085 Barcelona True Maccabi-Tel-Aviv \n", + "4 2017-12-01-cska-moscow 29-093 Barcelona False Cska-Moscow \n", + "\n", + " game_result mp fg fga fg_pct ... orb drb trb ast \\\n", + "0 W 11.500000 0.0 2.0 0.000 ... 0.0 2.0 2.0 1.0 \n", + "1 L 15.216667 5.0 7.0 0.714 ... 2.0 0.0 2.0 1.0 \n", + "2 L 15.816667 1.0 3.0 0.333 ... 0.0 4.0 4.0 1.0 \n", + "3 W 17.333333 1.0 3.0 0.333 ... 1.0 2.0 3.0 2.0 \n", + "4 L 6.583333 0.0 0.0 NaN ... 0.0 1.0 1.0 0.0 \n", + "\n", + " stl blk tov pf pts game_score \n", + "0 2.0 1.0 0.0 3.0 0.0 1.4 \n", + "1 3.0 0.0 0.0 1.0 12.0 13.8 \n", + "2 0.0 0.0 2.0 1.0 3.0 0.8 \n", + "3 0.0 0.0 0.0 4.0 3.0 2.4 \n", + "4 0.0 0.0 1.0 1.0 0.0 -1.1 \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player.gamelog_basic(2018, 'ELG').head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## stat_tables:\n", + "\n", + "\n", + "### took out stats_per100, stats_advanced, stats_shooting, stats_pbp (data not on bballref)\n", + "\n", + "### changed table_ids\n", + "\n", + "### parameters:\n", + "\n", + "### Kind (works the same)\n", + "\n", + "### Level (needed, because different docs are pulled from)\n", + "\n", + "#### -B (pulls from main milos-teodosic doc - default)\n", + "#### -C (pulls from milos-teodosic-club)\n", + "#### -E (pulls from milos-teodosic-tournament, which is Eurocup/Euroleague play)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='B' - Both" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='R', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007Liga ACB19.0NaN6.60.92.20.4050.20.7...0.40.60.90.40.40.20.60.52.3False
12008ULEB Cup, Liga ACB48.0NaN17.72.24.60.4800.72.0...0.82.22.90.90.70.41.31.85.9False
22009Liga ACB, EuroCup20.0NaN21.32.54.80.5210.92.2...0.73.44.10.80.90.61.22.07.1False
32010Liga ACB, EuroCup50.0NaN25.63.06.80.4420.92.9...1.03.94.91.61.00.41.82.38.2False
42011EuroLeague, Liga ACB38.0NaN28.43.88.20.4651.33.3...1.13.64.71.81.40.62.22.211.3False
\n", + "

5 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", + "0 2007 Liga ACB 19.0 NaN 6.6 0.9 2.2 \n", + "1 2008 ULEB Cup, Liga ACB 48.0 NaN 17.7 2.2 4.6 \n", + "2 2009 Liga ACB, EuroCup 20.0 NaN 21.3 2.5 4.8 \n", + "3 2010 Liga ACB, EuroCup 50.0 NaN 25.6 3.0 6.8 \n", + "4 2011 EuroLeague, Liga ACB 38.0 NaN 28.4 3.8 8.2 \n", + "\n", + " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", + "0 0.405 0.2 0.7 ... 0.4 0.6 \n", + "1 0.480 0.7 2.0 ... 0.8 2.2 \n", + "2 0.521 0.9 2.2 ... 0.7 3.4 \n", + "3 0.442 0.9 2.9 ... 1.0 3.9 \n", + "4 0.465 1.3 3.3 ... 1.1 3.6 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.9 0.4 0.4 0.2 0.6 0.5 2.3 \n", + "1 2.9 0.9 0.7 0.4 1.3 1.8 5.9 \n", + "2 4.1 0.8 0.9 0.6 1.2 2.0 7.1 \n", + "3 4.9 1.6 1.0 0.4 1.8 2.3 8.2 \n", + "4 4.7 1.8 1.4 0.6 2.2 2.2 11.3 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "\n", + "[5 rows x 27 columns]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='P', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007Liga ACB4.0NaN20.84.08.00.5001.03.3...0.81.32.00.80.30.81.00.811.5True
12008Liga ACB3.0NaN12.30.72.00.3330.00.7...0.71.72.30.70.30.00.71.02.7True
22009Liga ACB2.0NaN25.00.55.00.1000.02.0...1.03.54.50.51.50.02.02.02.5True
32010Liga ACB2.0NaN23.53.07.00.4291.03.0...0.52.02.51.00.50.51.51.58.0True
42011Liga ACB2.0NaN27.02.06.50.3080.52.5...0.52.53.01.01.00.03.03.56.0True
\n", + "

5 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 2007 Liga ACB 4.0 NaN 20.8 4.0 8.0 0.500 \n", + "1 2008 Liga ACB 3.0 NaN 12.3 0.7 2.0 0.333 \n", + "2 2009 Liga ACB 2.0 NaN 25.0 0.5 5.0 0.100 \n", + "3 2010 Liga ACB 2.0 NaN 23.5 3.0 7.0 0.429 \n", + "4 2011 Liga ACB 2.0 NaN 27.0 2.0 6.5 0.308 \n", + "\n", + " fg3_per_g fg3a_per_g ... orb_per_g drb_per_g trb_per_g \\\n", + "0 1.0 3.3 ... 0.8 1.3 2.0 \n", + "1 0.0 0.7 ... 0.7 1.7 2.3 \n", + "2 0.0 2.0 ... 1.0 3.5 4.5 \n", + "3 1.0 3.0 ... 0.5 2.0 2.5 \n", + "4 0.5 2.5 ... 0.5 2.5 3.0 \n", + "\n", + " ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.8 0.3 0.8 1.0 0.8 11.5 \n", + "1 0.7 0.3 0.0 0.7 1.0 2.7 \n", + "2 0.5 1.5 0.0 2.0 2.0 2.5 \n", + "3 1.0 0.5 0.5 1.5 1.5 8.0 \n", + "4 1.0 1.0 0.0 3.0 3.5 6.0 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "3 True \n", + "4 True \n", + "\n", + "[5 rows x 27 columns]" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='B', level='B')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007Liga ACB19.0NaN6.60.92.20.4050.20.7...0.40.60.90.40.40.20.60.52.3False
12008ULEB Cup, Liga ACB48.0NaN17.72.24.60.4800.72.0...0.82.22.90.90.70.41.31.85.9False
22009Liga ACB, EuroCup20.0NaN21.32.54.80.5210.92.2...0.73.44.10.80.90.61.22.07.1False
32010Liga ACB, EuroCup50.0NaN25.63.06.80.4420.92.9...1.03.94.91.61.00.41.82.38.2False
42011EuroLeague, Liga ACB38.0NaN28.43.88.20.4651.33.3...1.13.64.71.81.40.62.22.211.3False
52012EuroCup, Liga ACB37.0NaN25.83.07.20.4151.23.4...1.22.43.61.31.20.41.92.68.7False
62016EuroLeague31.0NaN27.03.57.00.5001.12.7...1.74.15.91.60.80.51.01.79.4False
72017EuroLeague, Liga ACB56.0NaN21.22.04.30.4710.92.2...0.83.44.31.20.90.41.32.05.5False
82018EuroLeague, Liga ACB29.0NaN14.91.53.40.4400.51.6...0.51.62.11.00.70.30.41.94.0False
92007Liga ACB4.0NaN20.84.08.00.5001.03.3...0.81.32.00.80.30.81.00.811.5True
102008Liga ACB3.0NaN12.30.72.00.3330.00.7...0.71.72.30.70.30.00.71.02.7True
112009Liga ACB2.0NaN25.00.55.00.1000.02.0...1.03.54.50.51.50.02.02.02.5True
122010Liga ACB2.0NaN23.53.07.00.4291.03.0...0.52.02.51.00.50.51.51.58.0True
132011Liga ACB2.0NaN27.02.06.50.3080.52.5...0.52.53.01.01.00.03.03.56.0True
142012Liga ACB7.0NaN27.72.05.90.3410.42.1...1.03.34.30.91.00.42.32.95.1True
152017Liga ACB3.0NaN23.72.35.30.4381.02.3...1.03.34.31.01.70.32.31.36.7True
\n", + "

16 rows × 27 columns

\n", + "
" + ], + "text/plain": [ + " season lg_name g gs mp_per_g fg_per_g fga_per_g \\\n", + "0 2007 Liga ACB 19.0 NaN 6.6 0.9 2.2 \n", + "1 2008 ULEB Cup, Liga ACB 48.0 NaN 17.7 2.2 4.6 \n", + "2 2009 Liga ACB, EuroCup 20.0 NaN 21.3 2.5 4.8 \n", + "3 2010 Liga ACB, EuroCup 50.0 NaN 25.6 3.0 6.8 \n", + "4 2011 EuroLeague, Liga ACB 38.0 NaN 28.4 3.8 8.2 \n", + "5 2012 EuroCup, Liga ACB 37.0 NaN 25.8 3.0 7.2 \n", + "6 2016 EuroLeague 31.0 NaN 27.0 3.5 7.0 \n", + "7 2017 EuroLeague, Liga ACB 56.0 NaN 21.2 2.0 4.3 \n", + "8 2018 EuroLeague, Liga ACB 29.0 NaN 14.9 1.5 3.4 \n", + "9 2007 Liga ACB 4.0 NaN 20.8 4.0 8.0 \n", + "10 2008 Liga ACB 3.0 NaN 12.3 0.7 2.0 \n", + "11 2009 Liga ACB 2.0 NaN 25.0 0.5 5.0 \n", + "12 2010 Liga ACB 2.0 NaN 23.5 3.0 7.0 \n", + "13 2011 Liga ACB 2.0 NaN 27.0 2.0 6.5 \n", + "14 2012 Liga ACB 7.0 NaN 27.7 2.0 5.9 \n", + "15 2017 Liga ACB 3.0 NaN 23.7 2.3 5.3 \n", + "\n", + " fg_pct fg3_per_g fg3a_per_g ... orb_per_g drb_per_g \\\n", + "0 0.405 0.2 0.7 ... 0.4 0.6 \n", + "1 0.480 0.7 2.0 ... 0.8 2.2 \n", + "2 0.521 0.9 2.2 ... 0.7 3.4 \n", + "3 0.442 0.9 2.9 ... 1.0 3.9 \n", + "4 0.465 1.3 3.3 ... 1.1 3.6 \n", + "5 0.415 1.2 3.4 ... 1.2 2.4 \n", + "6 0.500 1.1 2.7 ... 1.7 4.1 \n", + "7 0.471 0.9 2.2 ... 0.8 3.4 \n", + "8 0.440 0.5 1.6 ... 0.5 1.6 \n", + "9 0.500 1.0 3.3 ... 0.8 1.3 \n", + "10 0.333 0.0 0.7 ... 0.7 1.7 \n", + "11 0.100 0.0 2.0 ... 1.0 3.5 \n", + "12 0.429 1.0 3.0 ... 0.5 2.0 \n", + "13 0.308 0.5 2.5 ... 0.5 2.5 \n", + "14 0.341 0.4 2.1 ... 1.0 3.3 \n", + "15 0.438 1.0 2.3 ... 1.0 3.3 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 0.9 0.4 0.4 0.2 0.6 0.5 \n", + "1 2.9 0.9 0.7 0.4 1.3 1.8 \n", + "2 4.1 0.8 0.9 0.6 1.2 2.0 \n", + "3 4.9 1.6 1.0 0.4 1.8 2.3 \n", + "4 4.7 1.8 1.4 0.6 2.2 2.2 \n", + "5 3.6 1.3 1.2 0.4 1.9 2.6 \n", + "6 5.9 1.6 0.8 0.5 1.0 1.7 \n", + "7 4.3 1.2 0.9 0.4 1.3 2.0 \n", + "8 2.1 1.0 0.7 0.3 0.4 1.9 \n", + "9 2.0 0.8 0.3 0.8 1.0 0.8 \n", + "10 2.3 0.7 0.3 0.0 0.7 1.0 \n", + "11 4.5 0.5 1.5 0.0 2.0 2.0 \n", + "12 2.5 1.0 0.5 0.5 1.5 1.5 \n", + "13 3.0 1.0 1.0 0.0 3.0 3.5 \n", + "14 4.3 0.9 1.0 0.4 2.3 2.9 \n", + "15 4.3 1.0 1.7 0.3 2.3 1.3 \n", + "\n", + " pts_per_g is_playoffs \n", + "0 2.3 False \n", + "1 5.9 False \n", + "2 7.1 False \n", + "3 8.2 False \n", + "4 11.3 False \n", + "5 8.7 False \n", + "6 9.4 False \n", + "7 5.5 False \n", + "8 4.0 False \n", + "9 11.5 True \n", + "10 2.7 True \n", + "11 2.5 True \n", + "12 8.0 True \n", + "13 6.0 True \n", + "14 5.1 True \n", + "15 6.7 True \n", + "\n", + "[16 rows x 27 columns]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='C' - Club" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='R', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007/euro/teams/valencia/2007.htmlLiga ACBes19.0NaN6.60.92.20.405...0.40.60.90.40.40.20.60.52.3False
12008/euro/teams/valencia/2008.htmlLiga ACBes34.0NaN18.12.44.90.491...0.92.23.11.00.60.31.32.06.5False
22009/euro/teams/valencia/2009.htmlLiga ACBes16.0NaN22.62.85.30.529...0.93.64.50.61.10.51.32.18.3False
32010/euro/teams/valencia/2010.htmlLiga ACBes34.0NaN25.43.06.70.450...1.03.94.81.50.90.41.82.28.2False
42011/euro/teams/valencia/2011.htmlLiga ACBes24.0NaN28.83.98.50.461...1.13.54.62.11.40.72.02.011.5False
\n", + "

5 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2007 /euro/teams/valencia/2007.html Liga ACB es 19.0 NaN \n", + "1 2008 /euro/teams/valencia/2008.html Liga ACB es 34.0 NaN \n", + "2 2009 /euro/teams/valencia/2009.html Liga ACB es 16.0 NaN \n", + "3 2010 /euro/teams/valencia/2010.html Liga ACB es 34.0 NaN \n", + "4 2011 /euro/teams/valencia/2011.html Liga ACB es 24.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 6.6 0.9 2.2 0.405 ... 0.4 0.6 \n", + "1 18.1 2.4 4.9 0.491 ... 0.9 2.2 \n", + "2 22.6 2.8 5.3 0.529 ... 0.9 3.6 \n", + "3 25.4 3.0 6.7 0.450 ... 1.0 3.9 \n", + "4 28.8 3.9 8.5 0.461 ... 1.1 3.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 0.9 0.4 0.4 0.2 0.6 0.5 2.3 \n", + "1 3.1 1.0 0.6 0.3 1.3 2.0 6.5 \n", + "2 4.5 0.6 1.1 0.5 1.3 2.1 8.3 \n", + "3 4.8 1.5 0.9 0.4 1.8 2.2 8.2 \n", + "4 4.6 2.1 1.4 0.7 2.0 2.0 11.5 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "\n", + "[5 rows x 29 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='P', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007/euro/teams/valencia/2007.htmlLiga ACBes4.0NaN20.84.08.00.500...0.81.32.00.80.30.81.00.811.5True
12008/euro/teams/valencia/2008.htmlLiga ACBes3.0NaN12.30.72.00.333...0.71.72.30.70.30.00.71.02.7True
22009/euro/teams/valencia/2009.htmlLiga ACBes2.0NaN25.00.55.00.100...1.03.54.50.51.50.02.02.02.5True
32010/euro/teams/valencia/2010.htmlLiga ACBes2.0NaN23.53.07.00.429...0.52.02.51.00.50.51.51.58.0True
42011/euro/teams/valencia/2011.htmlLiga ACBes2.0NaN27.02.06.50.308...0.52.53.01.01.00.03.03.56.0True
\n", + "

5 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2007 /euro/teams/valencia/2007.html Liga ACB es 4.0 NaN \n", + "1 2008 /euro/teams/valencia/2008.html Liga ACB es 3.0 NaN \n", + "2 2009 /euro/teams/valencia/2009.html Liga ACB es 2.0 NaN \n", + "3 2010 /euro/teams/valencia/2010.html Liga ACB es 2.0 NaN \n", + "4 2011 /euro/teams/valencia/2011.html Liga ACB es 2.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 20.8 4.0 8.0 0.500 ... 0.8 1.3 \n", + "1 12.3 0.7 2.0 0.333 ... 0.7 1.7 \n", + "2 25.0 0.5 5.0 0.100 ... 1.0 3.5 \n", + "3 23.5 3.0 7.0 0.429 ... 0.5 2.0 \n", + "4 27.0 2.0 6.5 0.308 ... 0.5 2.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.0 0.8 0.3 0.8 1.0 0.8 11.5 \n", + "1 2.3 0.7 0.3 0.0 0.7 1.0 2.7 \n", + "2 4.5 0.5 1.5 0.0 2.0 2.0 2.5 \n", + "3 2.5 1.0 0.5 0.5 1.5 1.5 8.0 \n", + "4 3.0 1.0 1.0 0.0 3.0 3.5 6.0 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "3 True \n", + "4 True \n", + "\n", + "[5 rows x 29 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "15\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='B', level='C')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_namelg_countryggsmp_per_gfg_per_gfga_per_gfg_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02007/euro/teams/valencia/2007.htmlLiga ACBes19.0NaN6.60.92.20.405...0.40.60.90.40.40.20.60.52.3False
12008/euro/teams/valencia/2008.htmlLiga ACBes34.0NaN18.12.44.90.491...0.92.23.11.00.60.31.32.06.5False
22009/euro/teams/valencia/2009.htmlLiga ACBes16.0NaN22.62.85.30.529...0.93.64.50.61.10.51.32.18.3False
32010/euro/teams/valencia/2010.htmlLiga ACBes34.0NaN25.43.06.70.450...1.03.94.81.50.90.41.82.28.2False
42011/euro/teams/valencia/2011.htmlLiga ACBes24.0NaN28.83.98.50.461...1.13.54.62.11.40.72.02.011.5False
52012/euro/teams/valencia/2012.htmlLiga ACBes27.0NaN25.32.97.00.420...1.22.33.51.31.10.52.02.58.4False
62017/euro/teams/barcelona/2017.htmlLiga ACBes29.0NaN20.41.94.00.483...0.83.34.11.20.90.61.42.35.0False
72018/euro/teams/barcelona/2018.htmlLiga ACBes12.0NaN16.61.43.30.425...0.41.72.11.00.80.30.52.23.8False
82007/euro/teams/valencia/2007.htmlLiga ACBes4.0NaN20.84.08.00.500...0.81.32.00.80.30.81.00.811.5True
92008/euro/teams/valencia/2008.htmlLiga ACBes3.0NaN12.30.72.00.333...0.71.72.30.70.30.00.71.02.7True
102009/euro/teams/valencia/2009.htmlLiga ACBes2.0NaN25.00.55.00.100...1.03.54.50.51.50.02.02.02.5True
112010/euro/teams/valencia/2010.htmlLiga ACBes2.0NaN23.53.07.00.429...0.52.02.51.00.50.51.51.58.0True
122011/euro/teams/valencia/2011.htmlLiga ACBes2.0NaN27.02.06.50.308...0.52.53.01.01.00.03.03.56.0True
132012/euro/teams/valencia/2012.htmlLiga ACBes7.0NaN27.72.05.90.341...1.03.34.30.91.00.42.32.95.1True
142017/euro/teams/barcelona/2017.htmlLiga ACBes3.0NaN23.72.35.30.438...1.03.34.31.01.70.32.31.36.7True
\n", + "

15 rows × 29 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name lg_country g gs \\\n", + "0 2007 /euro/teams/valencia/2007.html Liga ACB es 19.0 NaN \n", + "1 2008 /euro/teams/valencia/2008.html Liga ACB es 34.0 NaN \n", + "2 2009 /euro/teams/valencia/2009.html Liga ACB es 16.0 NaN \n", + "3 2010 /euro/teams/valencia/2010.html Liga ACB es 34.0 NaN \n", + "4 2011 /euro/teams/valencia/2011.html Liga ACB es 24.0 NaN \n", + "5 2012 /euro/teams/valencia/2012.html Liga ACB es 27.0 NaN \n", + "6 2017 /euro/teams/barcelona/2017.html Liga ACB es 29.0 NaN \n", + "7 2018 /euro/teams/barcelona/2018.html Liga ACB es 12.0 NaN \n", + "8 2007 /euro/teams/valencia/2007.html Liga ACB es 4.0 NaN \n", + "9 2008 /euro/teams/valencia/2008.html Liga ACB es 3.0 NaN \n", + "10 2009 /euro/teams/valencia/2009.html Liga ACB es 2.0 NaN \n", + "11 2010 /euro/teams/valencia/2010.html Liga ACB es 2.0 NaN \n", + "12 2011 /euro/teams/valencia/2011.html Liga ACB es 2.0 NaN \n", + "13 2012 /euro/teams/valencia/2012.html Liga ACB es 7.0 NaN \n", + "14 2017 /euro/teams/barcelona/2017.html Liga ACB es 3.0 NaN \n", + "\n", + " mp_per_g fg_per_g fga_per_g fg_pct ... orb_per_g drb_per_g \\\n", + "0 6.6 0.9 2.2 0.405 ... 0.4 0.6 \n", + "1 18.1 2.4 4.9 0.491 ... 0.9 2.2 \n", + "2 22.6 2.8 5.3 0.529 ... 0.9 3.6 \n", + "3 25.4 3.0 6.7 0.450 ... 1.0 3.9 \n", + "4 28.8 3.9 8.5 0.461 ... 1.1 3.5 \n", + "5 25.3 2.9 7.0 0.420 ... 1.2 2.3 \n", + "6 20.4 1.9 4.0 0.483 ... 0.8 3.3 \n", + "7 16.6 1.4 3.3 0.425 ... 0.4 1.7 \n", + "8 20.8 4.0 8.0 0.500 ... 0.8 1.3 \n", + "9 12.3 0.7 2.0 0.333 ... 0.7 1.7 \n", + "10 25.0 0.5 5.0 0.100 ... 1.0 3.5 \n", + "11 23.5 3.0 7.0 0.429 ... 0.5 2.0 \n", + "12 27.0 2.0 6.5 0.308 ... 0.5 2.5 \n", + "13 27.7 2.0 5.9 0.341 ... 1.0 3.3 \n", + "14 23.7 2.3 5.3 0.438 ... 1.0 3.3 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g \\\n", + "0 0.9 0.4 0.4 0.2 0.6 0.5 \n", + "1 3.1 1.0 0.6 0.3 1.3 2.0 \n", + "2 4.5 0.6 1.1 0.5 1.3 2.1 \n", + "3 4.8 1.5 0.9 0.4 1.8 2.2 \n", + "4 4.6 2.1 1.4 0.7 2.0 2.0 \n", + "5 3.5 1.3 1.1 0.5 2.0 2.5 \n", + "6 4.1 1.2 0.9 0.6 1.4 2.3 \n", + "7 2.1 1.0 0.8 0.3 0.5 2.2 \n", + "8 2.0 0.8 0.3 0.8 1.0 0.8 \n", + "9 2.3 0.7 0.3 0.0 0.7 1.0 \n", + "10 4.5 0.5 1.5 0.0 2.0 2.0 \n", + "11 2.5 1.0 0.5 0.5 1.5 1.5 \n", + "12 3.0 1.0 1.0 0.0 3.0 3.5 \n", + "13 4.3 0.9 1.0 0.4 2.3 2.9 \n", + "14 4.3 1.0 1.7 0.3 2.3 1.3 \n", + "\n", + " pts_per_g is_playoffs \n", + "0 2.3 False \n", + "1 6.5 False \n", + "2 8.3 False \n", + "3 8.2 False \n", + "4 11.5 False \n", + "5 8.4 False \n", + "6 5.0 False \n", + "7 3.8 False \n", + "8 11.5 True \n", + "9 2.7 True \n", + "10 2.5 True \n", + "11 8.0 True \n", + "12 6.0 True \n", + "13 5.1 True \n", + "14 6.7 True \n", + "\n", + "[15 rows x 29 columns]" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head(20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test: level='E' - Eurocup/Euroleague (because Eurocup/Euroleague will never have sep playoffs, kind modifier does nothing) -> need to deal with duplicate when kind='B' " + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='B', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02008/euro/teams/valencia/2008.htmlULEB Cup14.0NaN16.61.84.00.4460.6...0.42.12.50.60.90.61.31.44.4False
12009/euro/teams/valencia/2009.htmlEuroCup4.0NaN15.81.32.80.4550.0...0.02.52.51.50.00.81.01.32.5False
22010/euro/teams/valencia/2010.htmlEuroCup16.0NaN26.12.96.90.4271.0...1.23.95.11.71.10.41.72.48.3False
32011/euro/teams/valencia/2011.htmlEuroLeague14.0NaN27.63.67.70.4721.0...0.93.94.91.41.40.42.52.510.9False
42012/euro/teams/valencia/2012.htmlEuroCup10.0NaN27.33.17.70.4031.2...1.22.53.71.31.50.21.83.09.4False
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2008 /euro/teams/valencia/2008.html ULEB Cup 14.0 NaN 16.6 \n", + "1 2009 /euro/teams/valencia/2009.html EuroCup 4.0 NaN 15.8 \n", + "2 2010 /euro/teams/valencia/2010.html EuroCup 16.0 NaN 26.1 \n", + "3 2011 /euro/teams/valencia/2011.html EuroLeague 14.0 NaN 27.6 \n", + "4 2012 /euro/teams/valencia/2012.html EuroCup 10.0 NaN 27.3 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 1.8 4.0 0.446 0.6 ... 0.4 2.1 \n", + "1 1.3 2.8 0.455 0.0 ... 0.0 2.5 \n", + "2 2.9 6.9 0.427 1.0 ... 1.2 3.9 \n", + "3 3.6 7.7 0.472 1.0 ... 0.9 3.9 \n", + "4 3.1 7.7 0.403 1.2 ... 1.2 2.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.5 0.6 0.9 0.6 1.3 1.4 4.4 \n", + "1 2.5 1.5 0.0 0.8 1.0 1.3 2.5 \n", + "2 5.1 1.7 1.1 0.4 1.7 2.4 8.3 \n", + "3 4.9 1.4 1.4 0.4 2.5 2.5 10.9 \n", + "4 3.7 1.3 1.5 0.2 1.8 3.0 9.4 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='R', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02008/euro/teams/valencia/2008.htmlULEB Cup14.0NaN16.61.84.00.4460.6...0.42.12.50.60.90.61.31.44.4False
12009/euro/teams/valencia/2009.htmlEuroCup4.0NaN15.81.32.80.4550.0...0.02.52.51.50.00.81.01.32.5False
22010/euro/teams/valencia/2010.htmlEuroCup16.0NaN26.12.96.90.4271.0...1.23.95.11.71.10.41.72.48.3False
32011/euro/teams/valencia/2011.htmlEuroLeague14.0NaN27.63.67.70.4721.0...0.93.94.91.41.40.42.52.510.9False
42012/euro/teams/valencia/2012.htmlEuroCup10.0NaN27.33.17.70.4031.2...1.22.53.71.31.50.21.83.09.4False
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2008 /euro/teams/valencia/2008.html ULEB Cup 14.0 NaN 16.6 \n", + "1 2009 /euro/teams/valencia/2009.html EuroCup 4.0 NaN 15.8 \n", + "2 2010 /euro/teams/valencia/2010.html EuroCup 16.0 NaN 26.1 \n", + "3 2011 /euro/teams/valencia/2011.html EuroLeague 14.0 NaN 27.6 \n", + "4 2012 /euro/teams/valencia/2012.html EuroCup 10.0 NaN 27.3 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 1.8 4.0 0.446 0.6 ... 0.4 2.1 \n", + "1 1.3 2.8 0.455 0.0 ... 0.0 2.5 \n", + "2 2.9 6.9 0.427 1.0 ... 1.2 3.9 \n", + "3 3.6 7.7 0.472 1.0 ... 0.9 3.9 \n", + "4 3.1 7.7 0.403 1.2 ... 1.2 2.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.5 0.6 0.9 0.6 1.3 1.4 4.4 \n", + "1 2.5 1.5 0.0 0.8 1.0 1.3 2.5 \n", + "2 5.1 1.7 1.1 0.4 1.7 2.4 8.3 \n", + "3 4.9 1.4 1.4 0.4 2.5 2.5 10.9 \n", + "4 3.7 1.3 1.5 0.2 1.8 3.0 9.4 \n", + "\n", + " is_playoffs \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + } + ], + "source": [ + "df = player.stats_per_game(kind='P', level='E')\n", + "\n", + "print(len(df))" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_g...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gis_playoffs
02008/euro/teams/valencia/2008.htmlULEB Cup14.0NaN16.61.84.00.4460.6...0.42.12.50.60.90.61.31.44.4True
12009/euro/teams/valencia/2009.htmlEuroCup4.0NaN15.81.32.80.4550.0...0.02.52.51.50.00.81.01.32.5True
22010/euro/teams/valencia/2010.htmlEuroCup16.0NaN26.12.96.90.4271.0...1.23.95.11.71.10.41.72.48.3True
32011/euro/teams/valencia/2011.htmlEuroLeague14.0NaN27.63.67.70.4721.0...0.93.94.91.41.40.42.52.510.9True
42012/euro/teams/valencia/2012.htmlEuroCup10.0NaN27.33.17.70.4031.2...1.22.53.71.31.50.21.83.09.4True
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp_per_g \\\n", + "0 2008 /euro/teams/valencia/2008.html ULEB Cup 14.0 NaN 16.6 \n", + "1 2009 /euro/teams/valencia/2009.html EuroCup 4.0 NaN 15.8 \n", + "2 2010 /euro/teams/valencia/2010.html EuroCup 16.0 NaN 26.1 \n", + "3 2011 /euro/teams/valencia/2011.html EuroLeague 14.0 NaN 27.6 \n", + "4 2012 /euro/teams/valencia/2012.html EuroCup 10.0 NaN 27.3 \n", + "\n", + " fg_per_g fga_per_g fg_pct fg3_per_g ... orb_per_g drb_per_g \\\n", + "0 1.8 4.0 0.446 0.6 ... 0.4 2.1 \n", + "1 1.3 2.8 0.455 0.0 ... 0.0 2.5 \n", + "2 2.9 6.9 0.427 1.0 ... 1.2 3.9 \n", + "3 3.6 7.7 0.472 1.0 ... 0.9 3.9 \n", + "4 3.1 7.7 0.403 1.2 ... 1.2 2.5 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 2.5 0.6 0.9 0.6 1.3 1.4 4.4 \n", + "1 2.5 1.5 0.0 0.8 1.0 1.3 2.5 \n", + "2 5.1 1.7 1.1 0.4 1.7 2.4 8.3 \n", + "3 4.9 1.4 1.4 0.4 2.5 2.5 10.9 \n", + "4 3.7 1.3 1.5 0.2 1.8 3.0 9.4 \n", + "\n", + " is_playoffs \n", + "0 True \n", + "1 True \n", + "2 True \n", + "3 True \n", + "4 True \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## stats_totals and stats_per36 params are the same as stats_per_game shown above" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmpfgfgafg_pctfg3...orbdrbtrbaststlblktovpfptsis_playoffs
02008/euro/teams/valencia/2008.htmlULEB Cup14.0NaN232.025.056.00.4468.0...6.029.035.09.013.08.018.019.061.0True
12009/euro/teams/valencia/2009.htmlEuroCup4.0NaN63.05.011.00.4550.0...0.010.010.06.00.03.04.05.010.0True
22010/euro/teams/valencia/2010.htmlEuroCup16.0NaN418.047.0110.00.42716.0...19.062.081.027.017.07.027.039.0132.0True
32011/euro/teams/valencia/2011.htmlEuroLeague14.0NaN386.051.0108.00.47214.0...13.055.068.019.020.05.035.035.0153.0True
42012/euro/teams/valencia/2012.htmlEuroCup10.0NaN273.031.077.00.40312.0...12.025.037.013.015.02.018.030.094.0True
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp fg \\\n", + "0 2008 /euro/teams/valencia/2008.html ULEB Cup 14.0 NaN 232.0 25.0 \n", + "1 2009 /euro/teams/valencia/2009.html EuroCup 4.0 NaN 63.0 5.0 \n", + "2 2010 /euro/teams/valencia/2010.html EuroCup 16.0 NaN 418.0 47.0 \n", + "3 2011 /euro/teams/valencia/2011.html EuroLeague 14.0 NaN 386.0 51.0 \n", + "4 2012 /euro/teams/valencia/2012.html EuroCup 10.0 NaN 273.0 31.0 \n", + "\n", + " fga fg_pct fg3 ... orb drb trb ast stl blk tov \\\n", + "0 56.0 0.446 8.0 ... 6.0 29.0 35.0 9.0 13.0 8.0 18.0 \n", + "1 11.0 0.455 0.0 ... 0.0 10.0 10.0 6.0 0.0 3.0 4.0 \n", + "2 110.0 0.427 16.0 ... 19.0 62.0 81.0 27.0 17.0 7.0 27.0 \n", + "3 108.0 0.472 14.0 ... 13.0 55.0 68.0 19.0 20.0 5.0 35.0 \n", + "4 77.0 0.403 12.0 ... 12.0 25.0 37.0 13.0 15.0 2.0 18.0 \n", + "\n", + " pf pts is_playoffs \n", + "0 19.0 61.0 True \n", + "1 5.0 10.0 True \n", + "2 39.0 132.0 True \n", + "3 35.0 153.0 True \n", + "4 30.0 94.0 True \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player.stats_totals(kind='P', level='E').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
seasonteam_name_seasonlg_nameggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mp...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpis_playoffs
02008/euro/teams/valencia/2008.htmlULEB Cup14.0NaN232.03.98.70.4461.2...0.94.55.41.42.01.22.82.99.5True
12009/euro/teams/valencia/2009.htmlEuroCup4.0NaN63.02.96.30.4550.0...0.05.75.73.40.01.72.32.95.7True
22010/euro/teams/valencia/2010.htmlEuroCup16.0NaN418.04.09.50.4271.4...1.65.37.02.31.50.62.33.411.4True
32011/euro/teams/valencia/2011.htmlEuroLeague14.0NaN386.04.810.10.4721.3...1.25.16.31.81.90.53.33.314.3True
42012/euro/teams/valencia/2012.htmlEuroCup10.0NaN273.04.110.20.4031.6...1.63.34.91.72.00.32.44.012.4True
\n", + "

5 rows × 28 columns

\n", + "
" + ], + "text/plain": [ + " season team_name_season lg_name g gs mp \\\n", + "0 2008 /euro/teams/valencia/2008.html ULEB Cup 14.0 NaN 232.0 \n", + "1 2009 /euro/teams/valencia/2009.html EuroCup 4.0 NaN 63.0 \n", + "2 2010 /euro/teams/valencia/2010.html EuroCup 16.0 NaN 418.0 \n", + "3 2011 /euro/teams/valencia/2011.html EuroLeague 14.0 NaN 386.0 \n", + "4 2012 /euro/teams/valencia/2012.html EuroCup 10.0 NaN 273.0 \n", + "\n", + " fg_per_mp fga_per_mp fg_pct fg3_per_mp ... orb_per_mp \\\n", + "0 3.9 8.7 0.446 1.2 ... 0.9 \n", + "1 2.9 6.3 0.455 0.0 ... 0.0 \n", + "2 4.0 9.5 0.427 1.4 ... 1.6 \n", + "3 4.8 10.1 0.472 1.3 ... 1.2 \n", + "4 4.1 10.2 0.403 1.6 ... 1.6 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 4.5 5.4 1.4 2.0 1.2 2.8 \n", + "1 5.7 5.7 3.4 0.0 1.7 2.3 \n", + "2 5.3 7.0 2.3 1.5 0.6 2.3 \n", + "3 5.1 6.3 1.8 1.9 0.5 3.3 \n", + "4 3.3 4.9 1.7 2.0 0.3 2.4 \n", + "\n", + " pf_per_mp pts_per_mp is_playoffs \n", + "0 2.9 9.5 True \n", + "1 2.9 5.7 True \n", + "2 3.4 11.4 True \n", + "3 3.3 14.3 True \n", + "4 4.0 12.4 True \n", + "\n", + "[5 rows x 28 columns]" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player.stats_per36(kind='P', level='E').head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From b6c29472acee50f149bb747a5a917a4bcb900621 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 23:05:03 -0500 Subject: [PATCH 51/57] edit player comments and add test notebook - also a few small changes (level vs kind) --- sportsref/euro/teams.py | 44 +- test_notebooks/euro/euro_team_test.ipynb | 1759 ++++++++++++++++++++++ 2 files changed, 1782 insertions(+), 21 deletions(-) create mode 100644 test_notebooks/euro/euro_team_test.ipynb diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index f4386b2..bda732a 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -19,12 +19,13 @@ def __hash__(self): return hash(self.team_id) @sportsref.decorators.memoize - def team_year_url(self, year, kind='B'): + def team_year_url(self, year, level='B'): yr_str = str(year) - if kind == 'C': + if level == 'C': yr_str += '_' + self.get_league_id(year=year) - else: + elif level == 'E': yr_str += '_euroleague' + return (sportsref.euro.BASE_URL + '/teams/{}/{}.htm'.format(self.team_id, yr_str)) @@ -41,8 +42,8 @@ def get_main_doc(self): return mainDoc @sportsref.decorators.memoize - def get_year_doc(self, yr_str, kind='B'): - return pq(sportsref.utils.get_html(self.team_year_url(yr_str, kind=kind))) + def get_year_doc(self, yr_str, level='B'): + return pq(sportsref.utils.get_html(self.team_year_url(yr_str, level=level))) @sportsref.decorators.memoize def get_schedule_doc(self, year): @@ -65,9 +66,8 @@ def get_league_id(self, year=2018): def name(self): """Returns the real name of the franchise given the team ID. - Examples: - 'BOS' -> 'Boston Celtics' - 'NJN' -> 'Brooklyn Nets' + Example: + 'barcelona' -> 'FC Barcelona' :returns: A string corresponding to the team's full name. """ @@ -75,10 +75,9 @@ def name(self): name = doc('title').text().replace(' Seasons | Basketball-Reference.com', '') return name - def get_stats_table(self, table_id, year, kind='B'): - doc = self.get_year_doc(year, kind=kind) + def get_stats_table(self, table_id, year, level='B'): + doc = self.get_year_doc(year, level=level) table = doc('table#{}'.format(table_id)) - print(table_id) df = sportsref.utils.parse_table(table) return df @@ -86,6 +85,9 @@ def get_stats_table(self, table_id, year, kind='B'): @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) def schedule(self, year, kind='B'): + """Returns the teams schedule, with boxscore_ids for further investigation. + :returns: schedule Dataframe + """ doc = self.get_schedule_doc(year) for t in doc('table').items(): if self.team_id in t.attr('id'): @@ -106,22 +108,22 @@ def schedule(self, year, kind='B'): @sportsref.decorators.memoize - def all_team_opp_stats(self, year, kind='B'): - return self.get_stats_table('team_and_opp', year, kind=kind) + def all_team_opp_stats(self, year, level='B'): + return self.get_stats_table('team_and_opp', year, level=level) @sportsref.decorators.memoize - def stats_per_game(self, year, kind='B'): - return self.get_stats_table('per_game', year, kind=kind) + def stats_per_game(self, year, level='B'): + return self.get_stats_table('per_game', year, level=level) @sportsref.decorators.memoize - def stats_totals(self, year, kind='B'): - return self.get_stats_table('totals', year, kind=kind) + def stats_totals(self, year, level='B'): + return self.get_stats_table('totals', year, level=level) @sportsref.decorators.memoize - def stats_per36(self, year, kind='B'): - return self.get_stats_table('per_minute', year, kind=kind) + def stats_per36(self, year, level='B'): + return self.get_stats_table('per_minute', year, level=level) @sportsref.decorators.memoize - def stats_advanced(self, year, kind='B'): - return self.get_stats_table('advanced', year, kind=kind) + def stats_advanced(self, year, level='B'): + return self.get_stats_table('advanced', year, level=level) diff --git a/test_notebooks/euro/euro_team_test.ipynb b/test_notebooks/euro/euro_team_test.ipynb new file mode 100644 index 0000000..7848cba --- /dev/null +++ b/test_notebooks/euro/euro_team_test.ipynb @@ -0,0 +1,1759 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# euro.Team test" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Regenerating PSFConstants file\n", + "Regenerating GPFConstants file\n" + ] + } + ], + "source": [ + "from sportsref import euro" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "team = euro.Team('barcelona')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Helper methods" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "spain-liga-acb\n", + "FC Barcelona\n" + ] + } + ], + "source": [ + "print(team.get_league_id())\n", + "print(team.name())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tables are slightly different than player - because there is no playoff/reg season separate tables (just different pages distinguishing level of competition), no kind param, just level (no concatenation w kind_rpb needed) \n", + "\n", + "## In general, used kind when concatenation made sense, and level when it didn't (needed 2 different params because in player, both needed)\n", + "\n", + "### See https://www.basketball-reference.com/euro/teams/barcelona/2017_euroleague.html\n", + "\n", + "### 'E' = Euroleague\n", + "### 'C' = Club play\n", + "### 'B' = both (combined in 1 table, not concatenated together like playoff/reg season tables)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## all team and opp stats table:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team62.013100.01795.03812.00.471586.01579.00.3711209.0...0.744515.01510.02025.01084.0437.0140.0884.01313.04988.0
1Opponent62.013100.01754.04013.00.437584.01623.00.3601170.0...0.763573.01368.01941.01039.0453.0109.0779.01318.04897.0
\n", + "

2 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 62.0 13100.0 1795.0 3812.0 0.471 586.0 1579.0 0.371 \n", + "1 Opponent 62.0 13100.0 1754.0 4013.0 0.437 584.0 1623.0 0.360 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 1209.0 ... 0.744 515.0 1510.0 2025.0 1084.0 437.0 140.0 884.0 \n", + "1 1170.0 ... 0.763 573.0 1368.0 1941.0 1039.0 453.0 109.0 779.0 \n", + "\n", + " pf pts \n", + "0 1313.0 4988.0 \n", + "1 1318.0 4897.0 \n", + "\n", + "[2 rows x 24 columns]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.all_team_opp_stats(2017, level='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team30.06025.0767.01739.00.441271.0716.00.378496.0...0.737245.0680.0925.0517.0212.061.0420.0553.02141.0
1Opponent30.06025.0834.01844.00.452263.0729.00.361571.0...0.748254.0659.0913.0510.0232.065.0357.0599.02242.0
\n", + "

2 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 30.0 6025.0 767.0 1739.0 0.441 271.0 716.0 0.378 \n", + "1 Opponent 30.0 6025.0 834.0 1844.0 0.452 263.0 729.0 0.361 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 496.0 ... 0.737 245.0 680.0 925.0 517.0 212.0 61.0 420.0 \n", + "1 571.0 ... 0.748 254.0 659.0 913.0 510.0 232.0 65.0 357.0 \n", + "\n", + " pf pts \n", + "0 553.0 2141.0 \n", + "1 599.0 2242.0 \n", + "\n", + "[2 rows x 24 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.all_team_opp_stats(2017, level='E').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
team_idgmpfgfgafg_pctfg3fg3afg3_pctfg2...ft_pctorbdrbtrbaststlblktovpfpts
0Team32.07075.01028.02073.00.496315.0863.00.365713.0...0.748270.0830.01100.0567.0225.079.0464.0760.02847.0
1Opponent32.07075.0920.02169.00.424321.0894.00.359599.0...0.773319.0709.01028.0529.0221.044.0422.0719.02655.0
\n", + "

2 rows × 24 columns

\n", + "
" + ], + "text/plain": [ + " team_id g mp fg fga fg_pct fg3 fg3a fg3_pct \\\n", + "0 Team 32.0 7075.0 1028.0 2073.0 0.496 315.0 863.0 0.365 \n", + "1 Opponent 32.0 7075.0 920.0 2169.0 0.424 321.0 894.0 0.359 \n", + "\n", + " fg2 ... ft_pct orb drb trb ast stl blk tov \\\n", + "0 713.0 ... 0.748 270.0 830.0 1100.0 567.0 225.0 79.0 464.0 \n", + "1 599.0 ... 0.773 319.0 709.0 1028.0 529.0 221.0 44.0 422.0 \n", + "\n", + " pf pts \n", + "0 760.0 2847.0 \n", + "1 719.0 2655.0 \n", + "\n", + "[2 rows x 24 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.all_team_opp_stats(2017, level='C').head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Other stats tables have same level param" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmp_per_gfg_per_gfga_per_gfg_pctfg3_per_gfg3a_per_gfg3_pct...orb_per_gdrb_per_gtrb_per_gast_per_gstl_per_gblk_per_gtov_per_gpf_per_gpts_per_gplayer_name
0tyrese-rice-161.0NaN27.54.210.80.3901.65.20.307...0.21.31.64.11.00.12.52.312.3Tyrese Rice
1ante-tomic-161.0NaN22.44.37.30.5900.00.00.333...2.14.86.92.00.60.61.62.210.8Ante Tomic
2petteri-koponen-154.0NaN22.13.17.20.4361.63.80.417...0.31.71.92.10.70.11.31.99.4Petteri Koponen
3victor-claver-156.0NaN21.22.04.30.4710.92.20.395...0.83.44.31.20.90.41.32.05.5Victor Claver
4aleksandar-vezenkov-162.0NaN18.63.05.50.5531.12.70.420...0.92.33.21.00.60.20.71.98.3Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp_per_g fg_per_g fga_per_g fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 27.5 4.2 10.8 0.390 \n", + "1 ante-tomic-1 61.0 NaN 22.4 4.3 7.3 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 22.1 3.1 7.2 0.436 \n", + "3 victor-claver-1 56.0 NaN 21.2 2.0 4.3 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 18.6 3.0 5.5 0.553 \n", + "\n", + " fg3_per_g fg3a_per_g fg3_pct ... orb_per_g drb_per_g \\\n", + "0 1.6 5.2 0.307 ... 0.2 1.3 \n", + "1 0.0 0.0 0.333 ... 2.1 4.8 \n", + "2 1.6 3.8 0.417 ... 0.3 1.7 \n", + "3 0.9 2.2 0.395 ... 0.8 3.4 \n", + "4 1.1 2.7 0.420 ... 0.9 2.3 \n", + "\n", + " trb_per_g ast_per_g stl_per_g blk_per_g tov_per_g pf_per_g pts_per_g \\\n", + "0 1.6 4.1 1.0 0.1 2.5 2.3 12.3 \n", + "1 6.9 2.0 0.6 0.6 1.6 2.2 10.8 \n", + "2 1.9 2.1 0.7 0.1 1.3 1.9 9.4 \n", + "3 4.3 1.2 0.9 0.4 1.3 2.0 5.5 \n", + "4 3.2 1.0 0.6 0.2 0.7 1.9 8.3 \n", + "\n", + " player_name \n", + "0 Tyrese Rice \n", + "1 Ante Tomic \n", + "2 Petteri Koponen \n", + "3 Victor Claver \n", + "4 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.stats_per_game(2017, level='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfgfgafg_pctfg3fg3afg3_pct...orbdrbtrbaststlblktovpfptsplayer_name
0tyrese-rice-161.0NaN1680.0256.0657.00.39098.0319.00.307...15.080.095.0252.058.04.0151.0142.0750.0Tyrese Rice
1ante-tomic-161.0NaN1367.0262.0444.00.5901.03.00.333...128.0295.0423.0124.035.036.099.0135.0661.0Ante Tomic
2petteri-koponen-154.0NaN1196.0169.0388.00.43685.0204.00.417...15.090.0105.0112.039.03.071.0100.0509.0Petteri Koponen
3victor-claver-156.0NaN1187.0112.0238.00.47149.0124.00.395...46.0192.0238.069.051.024.074.0111.0309.0Victor Claver
4aleksandar-vezenkov-162.0NaN1156.0187.0338.00.55371.0169.00.420...55.0143.0198.061.037.015.045.0115.0513.0Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg fga fg_pct fg3 fg3a \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 256.0 657.0 0.390 98.0 319.0 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 262.0 444.0 0.590 1.0 3.0 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 169.0 388.0 0.436 85.0 204.0 \n", + "3 victor-claver-1 56.0 NaN 1187.0 112.0 238.0 0.471 49.0 124.0 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 187.0 338.0 0.553 71.0 169.0 \n", + "\n", + " fg3_pct ... orb drb trb ast stl blk \\\n", + "0 0.307 ... 15.0 80.0 95.0 252.0 58.0 4.0 \n", + "1 0.333 ... 128.0 295.0 423.0 124.0 35.0 36.0 \n", + "2 0.417 ... 15.0 90.0 105.0 112.0 39.0 3.0 \n", + "3 0.395 ... 46.0 192.0 238.0 69.0 51.0 24.0 \n", + "4 0.420 ... 55.0 143.0 198.0 61.0 37.0 15.0 \n", + "\n", + " tov pf pts player_name \n", + "0 151.0 142.0 750.0 Tyrese Rice \n", + "1 99.0 135.0 661.0 Ante Tomic \n", + "2 71.0 100.0 509.0 Petteri Koponen \n", + "3 74.0 111.0 309.0 Victor Claver \n", + "4 45.0 115.0 513.0 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.stats_totals(2017, level='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idggsmpfg_per_mpfga_per_mpfg_pctfg3_per_mpfg3a_per_mpfg3_pct...orb_per_mpdrb_per_mptrb_per_mpast_per_mpstl_per_mpblk_per_mptov_per_mppf_per_mppts_per_mpplayer_name
0tyrese-rice-161.0NaN1680.05.514.10.3902.16.80.307...0.31.72.05.41.20.13.23.016.1Tyrese Rice
1ante-tomic-161.0NaN1367.06.911.70.5900.00.10.333...3.47.811.13.30.90.92.63.617.4Ante Tomic
2petteri-koponen-154.0NaN1196.05.111.70.4362.66.10.417...0.52.73.23.41.20.12.13.015.3Petteri Koponen
3victor-claver-156.0NaN1187.03.47.20.4711.53.80.395...1.45.87.22.11.50.72.23.49.4Victor Claver
4aleksandar-vezenkov-162.0NaN1156.05.810.50.5532.25.30.420...1.74.56.21.91.20.51.43.616.0Aleksandar Vezenkov
\n", + "

5 rows × 26 columns

\n", + "
" + ], + "text/plain": [ + " player_id g gs mp fg_per_mp fga_per_mp fg_pct \\\n", + "0 tyrese-rice-1 61.0 NaN 1680.0 5.5 14.1 0.390 \n", + "1 ante-tomic-1 61.0 NaN 1367.0 6.9 11.7 0.590 \n", + "2 petteri-koponen-1 54.0 NaN 1196.0 5.1 11.7 0.436 \n", + "3 victor-claver-1 56.0 NaN 1187.0 3.4 7.2 0.471 \n", + "4 aleksandar-vezenkov-1 62.0 NaN 1156.0 5.8 10.5 0.553 \n", + "\n", + " fg3_per_mp fg3a_per_mp fg3_pct ... orb_per_mp \\\n", + "0 2.1 6.8 0.307 ... 0.3 \n", + "1 0.0 0.1 0.333 ... 3.4 \n", + "2 2.6 6.1 0.417 ... 0.5 \n", + "3 1.5 3.8 0.395 ... 1.4 \n", + "4 2.2 5.3 0.420 ... 1.7 \n", + "\n", + " drb_per_mp trb_per_mp ast_per_mp stl_per_mp blk_per_mp tov_per_mp \\\n", + "0 1.7 2.0 5.4 1.2 0.1 3.2 \n", + "1 7.8 11.1 3.3 0.9 0.9 2.6 \n", + "2 2.7 3.2 3.4 1.2 0.1 2.1 \n", + "3 5.8 7.2 2.1 1.5 0.7 2.2 \n", + "4 4.5 6.2 1.9 1.2 0.5 1.4 \n", + "\n", + " pf_per_mp pts_per_mp player_name \n", + "0 3.0 16.1 Tyrese Rice \n", + "1 3.6 17.4 Ante Tomic \n", + "2 3.0 15.3 Petteri Koponen \n", + "3 3.4 9.4 Victor Claver \n", + "4 3.6 16.0 Aleksandar Vezenkov \n", + "\n", + "[5 rows x 26 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.stats_per36(2017, level='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idgmpts_pctefg_pctfg3a_per_fga_pctfta_per_fga_pctast_pcttov_pctusg_pctplayer_name
0tyrese-rice-161.01680.00.511NaN0.4860.26531.017.126.9Tyrese Rice
1ante-tomic-161.01367.00.605NaN0.0070.52520.415.324.1Ante Tomic
2petteri-koponen-154.01196.00.593NaN0.5260.24218.914.221.4Petteri Koponen
3victor-claver-156.01187.00.594NaN0.5210.21010.722.214.4Victor Claver
4aleksandar-vezenkov-162.01156.00.686NaN0.5000.24011.110.718.5Aleksandar Vezenkov
\n", + "
" + ], + "text/plain": [ + " player_id g mp ts_pct efg_pct fg3a_per_fga_pct \\\n", + "0 tyrese-rice-1 61.0 1680.0 0.511 NaN 0.486 \n", + "1 ante-tomic-1 61.0 1367.0 0.605 NaN 0.007 \n", + "2 petteri-koponen-1 54.0 1196.0 0.593 NaN 0.526 \n", + "3 victor-claver-1 56.0 1187.0 0.594 NaN 0.521 \n", + "4 aleksandar-vezenkov-1 62.0 1156.0 0.686 NaN 0.500 \n", + "\n", + " fta_per_fga_pct ast_pct tov_pct usg_pct player_name \n", + "0 0.265 31.0 17.1 26.9 Tyrese Rice \n", + "1 0.525 20.4 15.3 24.1 Ante Tomic \n", + "2 0.242 18.9 14.2 21.4 Petteri Koponen \n", + "3 0.210 10.7 22.2 14.4 Victor Claver \n", + "4 0.240 11.1 10.7 18.5 Aleksandar Vezenkov " + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "team.stats_advanced(2017, level='B').head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Schedule: uses kind, because it must be concatenated" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "65\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gboxscore_idis_homeopp_name_linkgame_resultovertimesptsopp_ptswinslossesgame_streakis_playoffs
01.02016-10-02-manresaFalse/euro/teams/manresa/2017.htmlWNaN56.050.01.00.0W 1False
12.02016-10-09-barcelonaTrue/euro/teams/vitoria/2017.htmlWNaN98.092.02.00.0W 2False
23.02016-10-16-bilbaoFalse/euro/teams/bilbao/2017.htmlLNaN79.092.02.01.0L 1False
34.02016-10-23-barcelonaTrue/euro/teams/sevilla/2017.htmlWNaN80.058.03.01.0W 1False
45.02016-10-30-fuenlabradaFalse/euro/teams/fuenlabrada/2017.htmlWNaN78.075.04.01.0W 2False
\n", + "
" + ], + "text/plain": [ + " g boxscore_id is_home opp_name_link \\\n", + "0 1.0 2016-10-02-manresa False /euro/teams/manresa/2017.html \n", + "1 2.0 2016-10-09-barcelona True /euro/teams/vitoria/2017.html \n", + "2 3.0 2016-10-16-bilbao False /euro/teams/bilbao/2017.html \n", + "3 4.0 2016-10-23-barcelona True /euro/teams/sevilla/2017.html \n", + "4 5.0 2016-10-30-fuenlabrada False /euro/teams/fuenlabrada/2017.html \n", + "\n", + " game_result overtimes pts opp_pts wins losses game_streak is_playoffs \n", + "0 W NaN 56.0 50.0 1.0 0.0 W 1 False \n", + "1 W NaN 98.0 92.0 2.0 0.0 W 2 False \n", + "2 L NaN 79.0 92.0 2.0 1.0 L 1 False \n", + "3 W NaN 80.0 58.0 3.0 1.0 W 1 False \n", + "4 W NaN 78.0 75.0 4.0 1.0 W 2 False " + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(team.schedule(2017, kind='B')))\n", + "team.schedule(2017, kind='B').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "35\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gboxscore_idis_homeopp_name_linkgame_resultovertimesptsopp_ptswinslossesgame_streakis_playoffs
01.02016-10-02-manresaFalse/euro/teams/manresa/2017.htmlWNaN56.050.01.00.0W 1False
12.02016-10-09-barcelonaTrue/euro/teams/vitoria/2017.htmlWNaN98.092.02.00.0W 2False
23.02016-10-16-bilbaoFalse/euro/teams/bilbao/2017.htmlLNaN79.092.02.01.0L 1False
34.02016-10-23-barcelonaTrue/euro/teams/sevilla/2017.htmlWNaN80.058.03.01.0W 1False
45.02016-10-30-fuenlabradaFalse/euro/teams/fuenlabrada/2017.htmlWNaN78.075.04.01.0W 2False
\n", + "
" + ], + "text/plain": [ + " g boxscore_id is_home opp_name_link \\\n", + "0 1.0 2016-10-02-manresa False /euro/teams/manresa/2017.html \n", + "1 2.0 2016-10-09-barcelona True /euro/teams/vitoria/2017.html \n", + "2 3.0 2016-10-16-bilbao False /euro/teams/bilbao/2017.html \n", + "3 4.0 2016-10-23-barcelona True /euro/teams/sevilla/2017.html \n", + "4 5.0 2016-10-30-fuenlabrada False /euro/teams/fuenlabrada/2017.html \n", + "\n", + " game_result overtimes pts opp_pts wins losses game_streak is_playoffs \n", + "0 W NaN 56.0 50.0 1.0 0.0 W 1 False \n", + "1 W NaN 98.0 92.0 2.0 0.0 W 2 False \n", + "2 L NaN 79.0 92.0 2.0 1.0 L 1 False \n", + "3 W NaN 80.0 58.0 3.0 1.0 W 1 False \n", + "4 W NaN 78.0 75.0 4.0 1.0 W 2 False " + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(team.schedule(2017, kind='R')))\n", + "team.schedule(2017, kind='R').head()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "30\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gboxscore_idis_homeopp_name_linkgame_resultovertimesptsopp_ptswinslossesgame_streakis_playoffs
01.02016-10-14-unics-kazanFalse/euro/teams/unics-kazan/2017.htmlWNaN69.063.01.00.0W 1True
12.02016-10-21-barcelonaTrue/euro/teams/ulker-fenerbahce/2017.htmlLNaN72.073.01.01.0L 1True
23.02016-10-26-red-starFalse/euro/teams/red-star/2017.htmlLNaN65.076.01.02.0L 2True
34.02016-10-28-barcelonaTrue/euro/teams/brose-baskets/2017.htmlWNaN78.074.02.02.0W 1True
45.02016-11-02-maccabi-tel-avivFalse/euro/teams/maccabi-tel-aviv/2017.htmlWNaN79.069.03.02.0W 2True
\n", + "
" + ], + "text/plain": [ + " g boxscore_id is_home \\\n", + "0 1.0 2016-10-14-unics-kazan False \n", + "1 2.0 2016-10-21-barcelona True \n", + "2 3.0 2016-10-26-red-star False \n", + "3 4.0 2016-10-28-barcelona True \n", + "4 5.0 2016-11-02-maccabi-tel-aviv False \n", + "\n", + " opp_name_link game_result overtimes pts \\\n", + "0 /euro/teams/unics-kazan/2017.html W NaN 69.0 \n", + "1 /euro/teams/ulker-fenerbahce/2017.html L NaN 72.0 \n", + "2 /euro/teams/red-star/2017.html L NaN 65.0 \n", + "3 /euro/teams/brose-baskets/2017.html W NaN 78.0 \n", + "4 /euro/teams/maccabi-tel-aviv/2017.html W NaN 79.0 \n", + "\n", + " opp_pts wins losses game_streak is_playoffs \n", + "0 63.0 1.0 0.0 W 1 True \n", + "1 73.0 1.0 1.0 L 1 True \n", + "2 76.0 1.0 2.0 L 2 True \n", + "3 74.0 2.0 2.0 W 1 True \n", + "4 69.0 3.0 2.0 W 2 True " + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(len(team.schedule(2017, kind='P')))\n", + "team.schedule(2017, kind='P').head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From afdd3e61bca967578bbefa27a9dd3e470db49b5b Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Mon, 12 Feb 2018 23:14:34 -0500 Subject: [PATCH 52/57] added boxscore test notebook and slight changes to comments --- sportsref/euro/boxscores.py | 8 +- test_notebooks/euro/euro_boxscore_test.ipynb | 447 +++++++++++++++++++ 2 files changed, 451 insertions(+), 4 deletions(-) create mode 100644 test_notebooks/euro/euro_boxscore_test.ipynb diff --git a/sportsref/euro/boxscores.py b/sportsref/euro/boxscores.py index 0c04f70..e6f3243 100644 --- a/sportsref/euro/boxscores.py +++ b/sportsref/euro/boxscores.py @@ -62,7 +62,7 @@ def weekday(self): @sportsref.decorators.memoize def get_raw_id(self, home): """Returns home team ID. - :returns: 3-character string representing home team's ID. + :returns: string representing home team's ID. """ doc = self.get_main_doc() div = doc('.scorebox') @@ -80,7 +80,7 @@ def get_raw_id(self, home): @sportsref.decorators.memoize def get_score(self, home): """Returns home team ID. - :returns: 3-character string representing home team's ID. + :returns: string representing home team's ID. """ doc = self.get_main_doc() div = doc('.scorebox') @@ -97,7 +97,7 @@ def get_score(self, home): @sportsref.decorators.memoize def home(self): """Returns home team ID. - :returns: 3-character string representing home team's ID. + :returns: string representing home team's ID. """ l = self.get_raw_id(home=True) @@ -106,7 +106,7 @@ def home(self): @sportsref.decorators.memoize def away(self): """Returns away team ID. - :returns: 3-character string representing away team's ID. + :returns: string representing away team's ID. """ l = self.get_raw_id(home=False) diff --git a/test_notebooks/euro/euro_boxscore_test.ipynb b/test_notebooks/euro/euro_boxscore_test.ipynb new file mode 100644 index 0000000..825af71 --- /dev/null +++ b/test_notebooks/euro/euro_boxscore_test.ipynb @@ -0,0 +1,447 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# euro.BoxScore test" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from sportsref import euro" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "box = euro.BoxScore('2018-02-04-bilbao')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Non dataframe methods - not many visible changes, but differences in how to access them with pyquery in code" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2018-02-04\n", + "Sunday\n", + "bilbao\n", + "77\n", + "fuenlabrada\n", + "83\n", + "fuenlabrada\n", + "2018\n" + ] + } + ], + "source": [ + "print(box.date())\n", + "print(box.weekday())\n", + "print(box.home())\n", + "print(box.home_score())\n", + "print(box.away())\n", + "print(box.away_score())\n", + "print(box.winner())\n", + "print(box.season())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stats tables - very few changes" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idmpfgfgafg3fg3aftftaorbtrbaststlblktovpfptsplayer_name
0devin-thomas-130.06.09.00.00.02.06.02.04.02.04.03.00.04.014.0Thomas, Devin
1shane-hammink-128.04.05.00.00.04.04.00.03.02.01.00.00.02.012.0Hammink, Shane
2jonathan-tabu-126.02.07.01.04.07.08.00.03.00.01.00.02.04.012.0Tabu, Jonathan
3alex-mumbru-125.05.08.02.05.07.08.00.02.04.01.01.00.03.019.0Mumbrú, Álex
4axel-hervelle-119.00.02.00.00.04.04.02.04.03.00.00.01.03.04.0Hervelle, Axel
\n", + "
" + ], + "text/plain": [ + " player_id mp fg fga fg3 fg3a ft fta orb trb ast stl \\\n", + "0 devin-thomas-1 30.0 6.0 9.0 0.0 0.0 2.0 6.0 2.0 4.0 2.0 4.0 \n", + "1 shane-hammink-1 28.0 4.0 5.0 0.0 0.0 4.0 4.0 0.0 3.0 2.0 1.0 \n", + "2 jonathan-tabu-1 26.0 2.0 7.0 1.0 4.0 7.0 8.0 0.0 3.0 0.0 1.0 \n", + "3 alex-mumbru-1 25.0 5.0 8.0 2.0 5.0 7.0 8.0 0.0 2.0 4.0 1.0 \n", + "4 axel-hervelle-1 19.0 0.0 2.0 0.0 0.0 4.0 4.0 2.0 4.0 3.0 0.0 \n", + "\n", + " blk tov pf pts player_name \n", + "0 3.0 0.0 4.0 14.0 Thomas, Devin \n", + "1 0.0 0.0 2.0 12.0 Hammink, Shane \n", + "2 0.0 2.0 4.0 12.0 Tabu, Jonathan \n", + "3 1.0 0.0 3.0 19.0 Mumbrú, Álex \n", + "4 0.0 1.0 3.0 4.0 Hervelle, Axel " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "box.get_home_stats().head()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
player_idmpfgfgafg3fg3aftftaorbtrbaststlblktovpfptsplayer_name
0christian-eyenga-135.04.08.02.04.00.00.01.03.00.01.01.01.02.010.0Eyenga, C.
1rolands-smits-127.03.05.02.04.03.04.02.04.00.00.00.02.05.011.0Smits, Rolands
2marko-popovic-126.08.013.04.09.05.08.00.02.04.01.00.02.02.025.0Popovic, Marko
3blagota-sekulic-124.02.04.01.02.06.06.01.02.01.00.00.04.02.011.0Sekulic, Blagota
4francisco-cruz-124.04.08.01.04.01.02.00.02.04.02.00.01.01.010.0Cruz, Francisco
\n", + "
" + ], + "text/plain": [ + " player_id mp fg fga fg3 fg3a ft fta orb trb ast \\\n", + "0 christian-eyenga-1 35.0 4.0 8.0 2.0 4.0 0.0 0.0 1.0 3.0 0.0 \n", + "1 rolands-smits-1 27.0 3.0 5.0 2.0 4.0 3.0 4.0 2.0 4.0 0.0 \n", + "2 marko-popovic-1 26.0 8.0 13.0 4.0 9.0 5.0 8.0 0.0 2.0 4.0 \n", + "3 blagota-sekulic-1 24.0 2.0 4.0 1.0 2.0 6.0 6.0 1.0 2.0 1.0 \n", + "4 francisco-cruz-1 24.0 4.0 8.0 1.0 4.0 1.0 2.0 0.0 2.0 4.0 \n", + "\n", + " stl blk tov pf pts player_name \n", + "0 1.0 1.0 1.0 2.0 10.0 Eyenga, C. \n", + "1 0.0 0.0 2.0 5.0 11.0 Smits, Rolands \n", + "2 1.0 0.0 2.0 2.0 25.0 Popovic, Marko \n", + "3 0.0 0.0 4.0 2.0 11.0 Sekulic, Blagota \n", + "4 2.0 0.0 1.0 1.0 10.0 Cruz, Francisco " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "box.get_away_stats().head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From c6da441177fa85c8c4fa7c17334958a52acf76d7 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 13 Feb 2018 11:32:18 -0500 Subject: [PATCH 53/57] removed cbb --- sportsref/cbb/__init__.py | 20 -- sportsref/cbb/boxscores.py | 458 ------------------------- sportsref/cbb/pbp.py | 671 ------------------------------------- sportsref/cbb/players.py | 200 ----------- sportsref/cbb/seasons.py | 222 ------------ sportsref/cbb/teams.py | 75 ----- 6 files changed, 1646 deletions(-) delete mode 100644 sportsref/cbb/__init__.py delete mode 100644 sportsref/cbb/boxscores.py delete mode 100644 sportsref/cbb/pbp.py delete mode 100644 sportsref/cbb/players.py delete mode 100644 sportsref/cbb/seasons.py delete mode 100644 sportsref/cbb/teams.py diff --git a/sportsref/cbb/__init__.py b/sportsref/cbb/__init__.py deleted file mode 100644 index 6879d90..0000000 --- a/sportsref/cbb/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from . import boxscores -from . import pbp -from . import seasons -from . import teams - -from .boxscores import BoxScore -from .seasons import Season -from .teams import Team -from .players import Player - -BASE_URL = 'http://www.sports-reference.com/cbb' - -__all__ = [ - 'BASE_URL', - 'boxscores', 'BoxScore', - 'pbp', - 'seasons', 'Season', - 'teams', 'Team', - 'players', 'Player', -] diff --git a/sportsref/cbb/boxscores.py b/sportsref/cbb/boxscores.py deleted file mode 100644 index 20f3a8e..0000000 --- a/sportsref/cbb/boxscores.py +++ /dev/null @@ -1,458 +0,0 @@ -import future -import future.utils - -import datetime -import re - -import numpy as np -import pandas as pd -from pyquery import PyQuery as pq - -import sportsref - - -class BoxScore( - future.utils.with_metaclass(sportsref.decorators.Cached, object) -): - - def __init__(self, boxscore_id): - self.boxscore_id = boxscore_id - - def __eq__(self, other): - return self.boxscore_id == other.boxscore_id - - def __hash__(self): - return hash(self.boxscore_id) - - def __repr__(self): - return 'BoxScore({})'.format(self.boxscore_id) - - @sportsref.decorators.memoize - def get_main_doc(self): - url = ('{}/boxscores/{}.html' - .format(sportsref.nba.BASE_URL, self.boxscore_id)) - doc = pq(sportsref.utils.get_html(url)) - return doc - - @sportsref.decorators.memoize - def get_subpage_doc(self, page): - url = (sportsref.nba.BASE_URL + - '/boxscores/{}/{}.html'.format(page, self.boxscore_id)) - doc = pq(sportsref.utils.get_html(url)) - return doc - - @sportsref.decorators.memoize - def date(self): - """Returns the date of the game. See Python datetime.date documentation - for more. - :returns: A datetime.date object with year, month, and day attributes. - """ - match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) - year, month, day = list(map(int, match.groups())) - return datetime.date(year=year, month=month, day=day) - - @sportsref.decorators.memoize - def weekday(self): - days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', - 'Saturday', 'Sunday'] - date = self.date() - wd = date.weekday() - return days[wd] - - @sportsref.decorators.memoize - def linescore(self): - """Returns the linescore for the game as a DataFrame.""" - doc = self.get_main_doc() - table = doc('table#line_score') - - columns = [th.text() for th in table('tr.thead').items('th')] - columns[0] = 'team_id' - - data = [ - [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] - for tr in list(table('tr.thead').next_all('tr').items()) - ] - - return pd.DataFrame(data, index=['away', 'home'], - columns=columns, dtype='float') - - @sportsref.decorators.memoize - def home(self): - """Returns home team ID. - :returns: 3-character string representing home team's ID. - """ - linescore = self.linescore() - return linescore.loc['home', 'team_id'] - - @sportsref.decorators.memoize - def away(self): - """Returns away team ID. - :returns: 3-character string representing away team's ID. - """ - linescore = self.linescore() - return linescore.loc['away', 'team_id'] - - @sportsref.decorators.memoize - def home_score(self): - """Returns score of the home team. - :returns: int of the home score. - """ - linescore = self.linescore() - return linescore.loc['home', 'T'] - - @sportsref.decorators.memoize - def away_score(self): - """Returns score of the away team. - :returns: int of the away score. - """ - linescore = self.linescore() - return linescore.loc['away', 'T'] - - @sportsref.decorators.memoize - def winner(self): - """Returns the team ID of the winning team. Returns NaN if a tie.""" - hmScore = self.home_score() - awScore = self.away_score() - if hmScore > awScore: - return self.home() - elif hmScore < awScore: - return self.away() - else: - return None - - @sportsref.decorators.memoize - def season(self): - """ - Returns the year ID of the season in which this game took place. - - :returns: An int representing the year of the season. - """ - d = self.date() - if d.month >= 9: - return d.year + 1 - else: - return d.year - - def _get_player_stats(self, table_id_fmt): - """Returns a DataFrame of player stats from the game (either basic or - advanced, depending on the argument. - - :param table_id_fmt: Format string for str.format with a placeholder - for the team ID (e.g. 'box_{}_basic') - :returns: DataFrame of player stats - """ - - # get data - doc = self.get_main_doc() - tms = self.away(), self.home() - tm_ids = [table_id_fmt.format(tm) for tm in tms] - tables = [doc('table#{}'.format(tm_id).lower()) for tm_id in tm_ids] - dfs = [sportsref.utils.parse_table(table) for table in tables] - - # clean data and add features - for i, (tm, df) in enumerate(zip(tms, dfs)): - no_time = df['mp'] == 0 - stat_cols = [col for col, dtype in df.dtypes.items() - if dtype != 'object'] - df.loc[no_time, stat_cols] = 0 - df['team_id'] = tm - df['is_home'] = i == 1 - df['is_starter'] = [p < 5 for p in range(df.shape[0])] - df.drop_duplicates(subset='player_id', keep='first', inplace=True) - - return pd.concat(dfs) - - @sportsref.decorators.memoize - def basic_stats(self): - """Returns a DataFrame of basic player stats from the game.""" - return self._get_player_stats('box_{}_basic') - - @sportsref.decorators.memoize - def advanced_stats(self): - """Returns a DataFrame of advanced player stats from the game.""" - return self._get_player_stats('box_{}_advanced') - - @sportsref.decorators.memoize - def pbp(self, dense_lineups=False, sparse_lineups=False): - """Returns a dataframe of the play-by-play data from the game. - - :param dense_lineups: If True, adds 10 columns containing the names of - the players on the court. Defaults to False. - :param sparse_lineups: If True, adds binary columns denoting whether a - given player is in the game at the time of a pass. Defaults to - False. - :returns: pandas DataFrame of play-by-play. Similar to GPF. - """ - try: - doc = self.get_subpage_doc('pbp') - except: - raise ValueError( - 'Error fetching PBP subpage for boxscore {}' - .format(self.boxscore_id) - ) - table = doc('table#pbp') - trs = [ - tr for tr in list(table('tr').items()) - if (not tr.attr['class'] or # regular data rows - tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds - ] - rows = [tr.children('td') for tr in trs] - n_rows = len(trs) - data = [] - cur_qtr = 0 - bsid = self.boxscore_id - - for i in range(n_rows): - tr = trs[i] - row = rows[i] - p = {} - - # increment cur_qtr when we hit a new quarter - if tr.attr['id'] and tr.attr['id'].startswith('q'): - assert int(tr.attr['id'][1:]) == cur_qtr + 1 - cur_qtr += 1 - continue - - # add time of play to entry - t_str = row.eq(0).text() - t_regex = r'(\d+):(\d+)\.(\d+)' - mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) - endQ = (12 * 60 * min(cur_qtr, 4) + - 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) - secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) - p['secs_elapsed'] = secsElapsed - p['clock_time'] = t_str - p['quarter'] = cur_qtr - - # handle single play description - # ex: beginning/end of quarter, jump ball - if row.length == 2: - desc = row.eq(1) - # handle jump balls - if desc.text().lower().startswith('jump ball: '): - p['is_jump_ball'] = True - jb_str = sportsref.utils.flatten_links(desc) - p.update( - sportsref.nba.pbp.parse_play(bsid, jb_str, None) - ) - # ignore rows marking beginning/end of quarters - elif ( - desc.text().lower().startswith('start of ') or - desc.text().lower().startswith('end of ') - ): - continue - # if another case, log and continue - else: - if not desc.text().lower().startswith('end of '): - print(( - '{}, Q{}, {} other case: {}' - .format(self.boxscore_id, cur_qtr, - t_str, desc.text()) - )) - continue - - # handle team play description - # ex: shot, turnover, rebound, foul, sub, etc. - elif row.length == 6: - aw_desc, hm_desc = row.eq(1), row.eq(5) - is_hm_play = bool(hm_desc.text()) - desc = hm_desc if is_hm_play else aw_desc - desc = sportsref.utils.flatten_links(desc) - # parse the play - new_p = sportsref.nba.pbp.parse_play(bsid, desc, is_hm_play) - if not new_p: - continue - elif isinstance(new_p, list): - # this happens when a row needs to be expanded to 2 rows; - # ex: double personal foul -> two PF rows - - # first, update and append the first row - orig_p = dict(p) - p.update(new_p[0]) - data.append(p) - # second, set up the second row to be appended below - p = orig_p - new_p = new_p[1] - elif new_p.get('is_error'): - print(("can't parse: {}, boxscore: {}" - .format(desc, self.boxscore_id))) - # import pdb; pdb.set_trace() - p.update(new_p) - - # otherwise, I don't know what this was - else: - raise Exception(("don't know how to handle row of length {}" - .format(row.length))) - - data.append(p) - - # convert to DataFrame and clean columns - df = pd.DataFrame.from_records(data) - df.sort_values('secs_elapsed', inplace=True, kind='mergesort') - df = sportsref.nba.pbp.clean_features(df) - - # add columns for home team, away team, boxscore_id, date - away, home = self.away(), self.home() - df['home'] = home - df['away'] = away - df['boxscore_id'] = self.boxscore_id - df['season'] = self.season() - date = self.date() - df['year'] = date.year - df['month'] = date.month - df['day'] = date.day - - def _clean_rebs(df): - df.reset_index(drop=True, inplace=True) - no_reb_after = ( - (df.fta_num < df.tot_fta) | df.is_ftm | - df.get('is_tech_fta', False) - ).shift(1).fillna(False) - no_reb_before = ( - (df.fta_num == df.tot_fta) - ).shift(-1).fillna(False) - se_end_qtr = df.loc[ - df.clock_time == '0:00.0', 'secs_elapsed' - ].unique() - no_reb_when = df.secs_elapsed.isin(se_end_qtr) - drop_mask = ( - (df.rebounder == 'Team') & - (no_reb_after | no_reb_before | no_reb_when) - ).nonzero()[0] - df.drop(drop_mask, axis=0, inplace=True) - df.reset_index(drop=True, inplace=True) - return df - - # get rid of 'rebounds' after FTM, non-final FTA, or tech FTA - df = _clean_rebs(df) - - # track possession number for each possession - # TODO: see 201604130PHO, secs_elapsed == 2756 - # things that end a poss: - # FGM, dreb, TO, end of Q, made last FT, lost jump ball, - # def goaltending, shot clock violation - new_poss = (df.off_team == df.home).diff().fillna(False) - # def rebound considered part of the new possession - df['poss_id'] = np.cumsum(new_poss) + df.is_dreb - # create poss_id with rebs -> new possessions for granular groupbys - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # make sure plays with the same clock time are in the right order - # TODO: make sort_cols depend on what cols are in the play? - # or combine related plays, like and-1 shot and foul - # issues come up with FGA after timeout in 201604130LAL - # issues come up with PF between FGA and DREB in 201604120SAS - sort_cols = [col for col in - ['is_reb', 'is_fga', 'is_pf', 'is_tech_foul', - 'is_ejection', 'is_tech_fta', 'is_timeout', 'is_pf_fta', - 'fta_num', 'is_viol', 'is_to', 'is_jump_ball', 'is_sub'] - if col in df.columns] - asc_true = ['fta_num'] - ascend = [(col in asc_true) for col in sort_cols] - for label, group in df.groupby([df.secs_elapsed, poss_id_reb]): - if len(group) > 1: - df.loc[group.index, :] = group.sort_values( - sort_cols, ascending=ascend, kind='mergesort' - ).values - - # 2nd pass: get rid of 'rebounds' after FTM, non-final FTA, etc. - df = _clean_rebs(df) - - # makes sure off/def and poss_id are correct for subs after rearranging - # some possessions above - df.loc[df['is_sub'], ['off_team', 'def_team', 'poss_id']] = np.nan - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.poss_id.fillna(method='bfill', inplace=True) - # make off_team and def_team NaN for jump balls - if 'is_jump_ball' in df.columns: - df.loc[df['is_jump_ball'], ['off_team', 'def_team']] = np.nan - - # make sure 'off_team' is always the team shooting FTs, even on techs - # (impt for keeping track of the score) - if 'is_tech_fta' in df.columns: - tech_fta = df['is_tech_fta'] - df.loc[tech_fta, 'off_team'] = df.loc[tech_fta, 'fta_team'] - df.loc[tech_fta, 'def_team'] = np.where( - df.loc[tech_fta, 'off_team'] == home, away, home - ) - df.drop('fta_team', axis=1, inplace=True) - # redefine poss_id_reb - new_poss = (df.off_team == df.home).diff().fillna(False) - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # get rid of redundant subs - for (se, tm, pnum), group in df[df.is_sub].groupby( - [df.secs_elapsed, df.sub_team, poss_id_reb] - ): - if len(group) > 1: - sub_in = set() - sub_out = set() - # first, figure out who's in and who's out after subs - for i, row in group.iterrows(): - if row['sub_in'] in sub_out: - sub_out.remove(row['sub_in']) - else: - sub_in.add(row['sub_in']) - if row['sub_out'] in sub_in: - sub_in.remove(row['sub_out']) - else: - sub_out.add(row['sub_out']) - assert len(sub_in) == len(sub_out) - # second, add those subs - n_subs = len(sub_in) - for idx, p_in, p_out in zip( - group.index[:n_subs], sub_in, sub_out - ): - assert df.loc[idx, 'is_sub'] - df.loc[idx, 'sub_in'] = p_in - df.loc[idx, 'sub_out'] = p_out - df.loc[idx, 'sub_team'] = tm - df.loc[idx, 'detail'] = ( - '{} enters the game for {}'.format(p_in, p_out) - ) - # third, if applicable, remove old sub entries when there are - # redundant subs - n_extra = len(group) - len(sub_in) - if n_extra: - extra_idxs = group.index[-n_extra:] - df.drop(extra_idxs, axis=0, inplace=True) - - df.reset_index(drop=True, inplace=True) - - # add column for pts and score - df['pts'] = (df['is_ftm'] + 2 * df['is_fgm'] + - (df['is_fgm'] & df['is_three'])) - df['hm_pts'] = np.where(df.off_team == df.home, df.pts, 0) - df['aw_pts'] = np.where(df.off_team == df.away, df.pts, 0) - df['hm_score'] = np.cumsum(df['hm_pts']) - df['aw_score'] = np.cumsum(df['aw_pts']) - - # more helpful columns - # "play" is differentiated from "poss" by counting OReb as new play - # "plays" end with non-and1 FGA, TO, last non-tech FTA, or end of qtr - # (or double lane viol) - new_qtr = df.quarter.diff().shift(-1).fillna(False).astype(bool) - and1 = (df.is_fgm & df.is_pf.shift(-1).fillna(False) & - df.is_fta.shift(-2).fillna(False) & - ~df.secs_elapsed.diff().shift(-1).fillna(False).astype(bool)) - double_lane = (df.get('viol_type') == 'double lane') - new_play = df.eval('(is_fga & ~(@and1)) | is_to | @new_qtr |' - '(is_fta & ~is_tech_fta & fta_num == tot_fta) |' - '@double_lane') - df['play_id'] = np.cumsum(new_play).shift(1).fillna(0) - df['hm_off'] = df.off_team == df.home - - # get lineup data - if dense_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_dense_lineups(df)), axis=1 - ) - if sparse_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_sparse_lineups(df)), axis=1 - ) - - # TODO: add shot clock as a feature - - return df diff --git a/sportsref/cbb/pbp.py b/sportsref/cbb/pbp.py deleted file mode 100644 index a67eebd..0000000 --- a/sportsref/cbb/pbp.py +++ /dev/null @@ -1,671 +0,0 @@ -from builtins import enumerate, int, list, range, zip - -import operator -import re - -import numpy as np -import pandas as pd - -import sportsref - -PLAYER_RE = r'\w{0,7}\d{2}' - -HM_LINEUP_COLS = ['hm_player{}'.format(i) for i in range(1, 6)] -AW_LINEUP_COLS = ['aw_player{}'.format(i) for i in range(1, 6)] -ALL_LINEUP_COLS = AW_LINEUP_COLS + HM_LINEUP_COLS - - -def sparse_lineup_cols(df): - regex = '{}_in'.format(PLAYER_RE) - return [c for c in df.columns if re.match(regex, c)] - - -def parse_play(boxscore_id, details, is_hm): - """Parse play details from a play-by-play string describing a play. - - Assuming valid input, this function returns structured data in a dictionary - describing the play. If the play detail string was invalid, this function - returns None. - - :param boxscore_id: the boxscore ID of the play - :param details: detail string for the play - :param is_hm: bool indicating whether the offense is at home - :param returns: dictionary of play attributes or None if invalid - :rtype: dictionary or None - """ - # if input isn't a string, return None - if not details or not isinstance(details, str): - return None - - bs = sportsref.nba.BoxScore(boxscore_id) - aw, hm = bs.away(), bs.home() - season = sportsref.nba.Season(bs.season()) - hm_roster = set(bs.basic_stats().query('is_home == True').player_id.values) - - p = {} - p['detail'] = details - p['home'] = hm - p['away'] = aw - p['is_home_play'] = is_hm - - # parsing field goal attempts - shotRE = (r'(?P{0}) (?Pmakes|misses) ' - '(?P2|3)\-pt shot').format(PLAYER_RE) - distRE = r' (?:from (?P\d+) ft|at rim)' - assistRE = r' \(assist by (?P{0})\)'.format(PLAYER_RE) - blockRE = r' \(block by (?P{0})\)'.format(PLAYER_RE) - shotRE = r'{0}{1}(?:{2}|{3})?'.format(shotRE, distRE, assistRE, blockRE) - m = re.match(shotRE, details, re.IGNORECASE) - if m: - p['is_fga'] = True - p.update(m.groupdict()) - p['shot_dist'] = p['shot_dist'] if p['shot_dist'] is not None else 0 - p['shot_dist'] = int(p['shot_dist']) - p['is_fgm'] = p['is_fgm'] == 'makes' - p['is_three'] = p['is_three'] == '3' - p['is_assist'] = pd.notnull(p.get('assister')) - p['is_block'] = pd.notnull(p.get('blocker')) - shooter_home = p['shooter'] in hm_roster - p['off_team'] = hm if shooter_home else aw - p['def_team'] = aw if shooter_home else hm - return p - - # parsing jump balls - jumpRE = ((r'Jump ball: (?P{0}) vs\. (?P{0})' - r'(?: \((?P{0}) gains possession\))?') - .format(PLAYER_RE)) - m = re.match(jumpRE, details, re.IGNORECASE) - if m: - p['is_jump_ball'] = True - p.update(m.groupdict()) - return p - - # parsing rebounds - rebRE = (r'(?POffensive|Defensive) rebound' - r' by (?P{0}|Team)').format(PLAYER_RE) - m = re.match(rebRE, details, re.I) - if m: - p['is_reb'] = True - p.update(m.groupdict()) - p['is_oreb'] = p['is_oreb'].lower() == 'offensive' - p['is_dreb'] = not p['is_oreb'] - if p['rebounder'] == 'Team': - p['reb_team'], other = (hm, aw) if is_hm else (aw, hm) - else: - reb_home = p['rebounder'] in hm_roster - p['reb_team'], other = (hm, aw) if reb_home else (aw, hm) - p['off_team'] = p['reb_team'] if p['is_oreb'] else other - p['def_team'] = p['reb_team'] if p['is_dreb'] else other - return p - - # parsing free throws - ftRE = (r'(?P{}) (?Pmakes|misses) ' - r'(?Ptechnical )?(?Pflagrant )?' - r'(?Pclear path )?free throw' - r'(?: (?P\d+) of (?P\d+))?').format(PLAYER_RE) - m = re.match(ftRE, details, re.I) - if m: - p['is_fta'] = True - p.update(m.groupdict()) - p['is_ftm'] = p['is_ftm'] == 'makes' - p['is_tech_fta'] = bool(p['is_tech_fta']) - p['is_flag_fta'] = bool(p['is_flag_fta']) - p['is_clearpath_fta'] = bool(p['is_clearpath_fta']) - p['is_pf_fta'] = not p['is_tech_fta'] - if p['tot_fta']: - p['tot_fta'] = int(p['tot_fta']) - if p['fta_num']: - p['fta_num'] = int(p['fta_num']) - ft_home = p['ft_shooter'] in hm_roster - p['fta_team'] = hm if ft_home else aw - if not p['is_tech_fta']: - p['off_team'] = hm if ft_home else aw - p['def_team'] = aw if ft_home else hm - return p - - # parsing substitutions - subRE = (r'(?P{0}) enters the game for ' - r'(?P{0})').format(PLAYER_RE) - m = re.match(subRE, details, re.I) - if m: - p['is_sub'] = True - p.update(m.groupdict()) - sub_home = p['sub_in'] in hm_roster or p['sub_out'] in hm_roster - p['sub_team'] = hm if sub_home else aw - return p - - # parsing turnovers - toReasons = (r'(?P[^;]+)(?:; steal by ' - r'(?P{0}))?').format(PLAYER_RE) - toRE = (r'Turnover by (?P{}|Team) ' - r'\((?:{})\)').format(PLAYER_RE, toReasons) - m = re.match(toRE, details, re.I) - if m: - p['is_to'] = True - p.update(m.groupdict()) - p['to_type'] = p['to_type'].lower() - if p['to_type'] == 'offensive foul': - return None - p['is_steal'] = pd.notnull(p['stealer']) - p['is_travel'] = p['to_type'] == 'traveling' - p['is_shot_clock_viol'] = p['to_type'] == 'shot clock' - p['is_oob'] = p['to_type'] == 'step out of bounds' - p['is_three_sec_viol'] = p['to_type'] == '3 sec' - p['is_backcourt_viol'] = p['to_type'] == 'back court' - p['is_off_goaltend'] = p['to_type'] == 'offensive goaltending' - p['is_double_dribble'] = p['to_type'] == 'dbl dribble' - p['is_discont_dribble'] = p['to_type'] == 'discontinued dribble' - p['is_carry'] = p['to_type'] == 'palming' - if p['to_by'] == 'Team': - p['off_team'] = hm if is_hm else aw - p['def_team'] = aw if is_hm else hm - else: - to_home = p['to_by'] in hm_roster - p['off_team'] = hm if to_home else aw - p['def_team'] = aw if to_home else hm - return p - - # parsing shooting fouls - shotFoulRE = (r'Shooting(?P block)? foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(shotFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_shot_foul'] = True - p.update(m.groupdict()) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing offensive fouls - offFoulRE = (r'Offensive(?P charge)? foul ' - r'by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(offFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_off_foul'] = True - p['is_to'] = True - p['to_type'] = 'offensive foul' - p.update(m.groupdict()) - p['is_charge'] = bool(p['is_charge']) - p['fouler'] = p['to_by'] - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = hm if foul_on_home else aw - p['def_team'] = aw if foul_on_home else hm - p['foul_team'] = p['off_team'] - return p - - # parsing personal fouls - foulRE = (r'Personal (?Ptake )?(?Pblock )?' - r'foul by (?P{0})(?: \(drawn by ' - r'(?P{0})\))?').format(PLAYER_RE) - m = re.match(foulRE, details, re.I) - if m: - p['is_pf'] = True - p.update(m.groupdict()) - p['is_take_foul'] = bool(p['is_take_foul']) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # TODO: parsing double personal fouls - # double_foul_re = (r'Double personal foul by (?P{0}) and ' - # r'(?P{0})').format(PLAYER_RE) - # m = re.match(double_Foul_re, details, re.I) - # if m: - # p['is_pf'] = True - # p.update(m.groupdict()) - # p['off_team'] = - - # parsing loose ball fouls - looseBallRE = (r'Loose ball foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(looseBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_loose_ball_foul'] = True - p.update(m.groupdict()) - foul_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_home else aw - return p - - # parsing punching fouls - # TODO - - # parsing away from play fouls - awayFromBallRE = ((r'Away from play foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?') - .format(PLAYER_RE)) - m = re.match(awayFromBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_away_from_play_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - # TODO: figure out who had the ball based on previous play - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing inbound fouls - inboundRE = (r'Inbound foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(inboundRE, details, re.I) - if m: - p['is_pf'] = True - p['is_inbound_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing flagrant fouls - flagrantRE = (r'Flagrant foul type (?P1|2) by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(flagrantRE, details, re.I) - if m: - p['is_pf'] = True - p['is_flagrant'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing clear path fouls - clearPathRE = (r'Clear path foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(clearPathRE, details, re.I) - if m: - p['is_pf'] = True - p['is_clear_path_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing timeouts - timeoutRE = r'(?P.*?) (?:full )?timeout' - m = re.match(timeoutRE, details, re.I) - if m: - p['is_timeout'] = True - p.update(m.groupdict()) - isOfficialTO = p['timeout_team'].lower() == 'official' - name_to_id = season.team_names_to_ids() - p['timeout_team'] = ( - 'Official' if isOfficialTO else - name_to_id.get(hm, name_to_id.get(aw, p['timeout_team'])) - ) - return p - - # parsing technical fouls - techRE = (r'(?PHanging )?' - r'(?PTaunting )?' - r'(?PIll def )?' - r'(?PDelay )?' - r'(?PNon unsport )?' - r'tech(?:nical)? foul by ' - r'(?P{0}|Team)').format(PLAYER_RE) - m = re.match(techRE, details, re.I) - if m: - p['is_tech_foul'] = True - p.update(m.groupdict()) - p['is_hanging'] = bool(p['is_hanging']) - p['is_taunting'] = bool(p['is_taunting']) - p['is_ill_def'] = bool(p['is_ill_def']) - p['is_delay'] = bool(p['is_delay']) - p['is_unsport'] = bool(p['is_unsport']) - foul_on_home = p['tech_fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing ejections - ejectRE = r'(?P{0}|Team) ejected from game'.format(PLAYER_RE) - m = re.match(ejectRE, details, re.I) - if m: - p['is_ejection'] = True - p.update(m.groupdict()) - if p['ejectee'] == 'Team': - p['ejectee_team'] = hm if is_hm else aw - else: - eject_home = p['ejectee'] in hm_roster - p['ejectee_team'] = hm if eject_home else aw - return p - - # parsing defensive 3 seconds techs - def3TechRE = (r'(?:Def 3 sec tech foul|Defensive three seconds)' - r' by (?P{})').format(PLAYER_RE) - m = re.match(def3TechRE, details, re.I) - if m: - p['is_tech_foul'] = True - p['is_def_three_secs'] = True - p.update(m.groupdict()) - foul_on_home = p['tech_fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing violations - violRE = (r'Violation by (?P{0}|Team) ' - r'\((?P.*)\)').format(PLAYER_RE) - m = re.match(violRE, details, re.I) - if m: - p['is_viol'] = True - p.update(m.groupdict()) - if p['viol_type'] == 'kicked_ball': - p['is_to'] = True - p['to_by'] = p['violator'] - if p['violator'] == 'Team': - p['viol_team'] = hm if is_hm else aw - else: - viol_home = p['violator'] in hm_roster - p['viol_team'] = hm if viol_home else aw - return p - - p['is_error'] = True - return p - - -def clean_features(df): - """Fixes up columns of the passed DataFrame, such as casting T/F columns to - boolean and filling in NaNs for team and opp. - - :param df: DataFrame of play-by-play data. - :returns: Dataframe with cleaned columns. - """ - df = pd.DataFrame(df) - - bool_vals = set([True, False, None, np.nan]) - sparse_cols = sparse_lineup_cols(df) - for col in df: - - # make indicator columns boolean type (and fill in NaNs) - if set(df[col].unique()[:5]) <= bool_vals: - df[col] = (df[col] == True) - - # fill NaN's in sparse lineup columns to 0 - elif col in sparse_cols: - df[col] = df[col].fillna(0) - - # fix free throw columns on technicals - df.loc[df.is_tech_fta, ['fta_num', 'tot_fta']] = 1 - - # fill in NaN's/fix off_team and def_team columns - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.off_team.fillna(method='ffill', inplace=True) - df.def_team.fillna(method='ffill', inplace=True) - - return df - - -def clean_multigame_features(df): - """TODO: Docstring for clean_multigame_features. - - :df: TODO - :returns: TODO - """ - df = pd.DataFrame(df) - if df.index.value_counts().max() > 1: - df.reset_index(drop=True, inplace=True) - - df = clean_features(df) - - # if it's many games in one DataFrame, make poss_id and play_id unique - for col in ('play_id', 'poss_id'): - diffs = df[col].diff().fillna(0) - if (diffs < 0).any(): - new_col = np.cumsum(diffs.astype(bool)) - df.eval('{} = @new_col'.format(col), inplace=True) - - return df - - -def get_period_starters(df): - """TODO - """ - - def players_from_play(play): - """Figures out what players are in the game based on the players - mentioned in a play. Returns away and home players as two sets. - - :param play: A dictionary representing a parsed play. - :returns: (aw_players, hm_players) - :rtype: tuple of lists - """ - # if it's a tech FT from between periods, don't count this play - if ( - play['clock_time'] == '12:00.0' and - (play.get('is_tech_foul') or play.get('is_tech_fta')) - ): - return [], [] - - stats = sportsref.nba.BoxScore(play['boxscore_id']).basic_stats() - home_grouped = stats.groupby('is_home') - hm_roster = set(home_grouped.player_id.get_group(True).values) - aw_roster = set(home_grouped.player_id.get_group(False).values) - player_keys = [ - 'assister', 'away_jumper', 'blocker', 'drew_foul', 'fouler', - 'ft_shooter', 'gains_poss', 'home_jumper', 'rebounder', 'shooter', - 'stealer', 'sub_in', 'sub_out', 'to_by' - ] - players = [p for p in play[player_keys] if pd.notnull(p)] - - aw_players = [p for p in players if p in aw_roster] - hm_players = [p for p in players if p in hm_roster] - return aw_players, hm_players - - # create a mapping { quarter => (away_starters, home_starters) } - n_periods = df.quarter.nunique() - period_starters = [(set(), set()) for _ in range(n_periods)] - - # fill out this mapping quarter by quarter - for qtr, qtr_grp in df.groupby(df.quarter): - aw_starters, hm_starters = period_starters[qtr-1] - exclude = set() - # loop through sets of plays that happen at the "same time" - for label, time_grp in qtr_grp.groupby(qtr_grp.secs_elapsed): - # first, if they sub in and weren't already starters, exclude them - sub_ins = set(time_grp.sub_in.dropna().values) - exclude.update(sub_ins - aw_starters - hm_starters) - # second, figure out new starters from each play at this time - for i, row in time_grp.iterrows(): - aw_players, hm_players = players_from_play(row) - # update overall sets for the quarter - aw_starters.update(aw_players) - hm_starters.update(hm_players) - # remove excluded (subbed-in) players - hm_starters -= exclude - aw_starters -= exclude - # check whether we have found all starters - if len(hm_starters) > 5 or len(aw_starters) > 5: - import ipdb - ipdb.set_trace() - if len(hm_starters) >= 5 and len(aw_starters) >= 5: - break - - if len(hm_starters) != 5 or len(aw_starters) != 5: - print(('WARNING: wrong number of starters for a team in Q{} of {}' - .format(qtr, df.boxscore_id.iloc[0]))) - - return period_starters - - -def get_sparse_lineups(df): - """TODO: Docstring for get_sparse_lineups. - - :param df: TODO - :returns: TODO - """ - - # get the lineup data using get_dense_lineups if necessary - if (set(ALL_LINEUP_COLS) - set(df.columns)): - lineup_df = get_dense_lineups(df) - else: - lineup_df = df[ALL_LINEUP_COLS] - - # create the sparse representation - hm_lineups = lineup_df[HM_LINEUP_COLS].values - aw_lineups = lineup_df[AW_LINEUP_COLS].values - # +1 for home, -1 for away - hm_df = pd.DataFrame([ - {'{}_in'.format(player_id): 1 for player_id in lineup} - for lineup in hm_lineups - ], dtype=int) - aw_df = pd.DataFrame([ - {'{}_in'.format(player_id): -1 for player_id in lineup} - for lineup in aw_lineups - ], dtype=int) - sparse_df = pd.concat((hm_df, aw_df), axis=1).fillna(0) - return sparse_df - - -def get_dense_lineups(df): - """Returns a new DataFrame based on the one it is passed. Specifically, it - adds five columns for each team (ten total), where each column has the ID - of a player on the court during the play. - - This information is figured out sequentially from the game's substitution - data in the passed DataFrame, so the DataFrame passed as an argument must - be from a specific BoxScore (rather than a DataFrame of non-consecutive - plays). That is, the DataFrame must be of the form returned by - :func:`nba.BoxScore.pbp `. - - .. note:: Note that the lineups reflect the teams in the game when the play - happened, not after the play. For example, if a play is a substitution, - the lineups for that play will be the lineups before the substituion - occurs. - - :param df: A DataFrame of a game's play-by-play data. - :returns: A DataFrame with additional lineup columns. - - """ - # TODO: add this precondition to documentation - assert df['boxscore_id'].nunique() == 1 - - def lineup_dict(aw_lineup, hm_lineup): - """Returns a dictionary of lineups to be converted to columns. - Specifically, the columns are 'aw_player1' through 'aw_player5' and - 'hm_player1' through 'hm_player5'. - - :param aw_lineup: The away team's current lineup. - :param hm_lineup: The home team's current lineup. - :returns: A dictionary of lineups. - """ - return { - '{}_player{}'.format(tm, i+1): player - for tm, lineup in zip(['aw', 'hm'], [aw_lineup, hm_lineup]) - for i, player in enumerate(lineup) - } - - def handle_sub(row, aw_lineup, hm_lineup): - """Modifies the aw_lineup and hm_lineup lists based on the substitution - that takes place in the given row.""" - assert row['is_sub'] - sub_lineup = hm_lineup if row['sub_team'] == row['home'] else aw_lineup - try: - # make the sub - idx = sub_lineup.index(row['sub_out']) - sub_lineup[idx] = row['sub_in'] - except ValueError: - # if the sub was double-entered and it's already been executed... - if ( - row['sub_in'] in sub_lineup - and row['sub_out'] not in sub_lineup - ): - return aw_lineup, hm_lineup - # otherwise, let's print and pretend this never happened - print(('ERROR IN SUB IN {}, Q{}, {}: {}' - .format(row['boxscore_id'], row['quarter'], - row['clock_time'], row['detail']))) - raise - return aw_lineup, hm_lineup - - per_starters = get_period_starters(df) - cur_qtr = 0 - aw_lineup, hm_lineup = [], [] - df = df.reset_index(drop=True) - lineups = [{} for _ in range(df.shape[0])] - - # loop through select plays to determine lineups - sub_or_per_start = df.is_sub | df.quarter.diff().astype(bool) - for i, row in df.loc[sub_or_per_start].iterrows(): - if row['quarter'] > cur_qtr: - # first row in a quarter - assert row['quarter'] == cur_qtr + 1 - # first, finish up the last quarter's lineups - if cur_qtr > 0 and not df.loc[i-1, 'is_sub']: - lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) - # then, move on to the quarter, and enter the starting lineups - cur_qtr += 1 - aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - # if the first play in the quarter is a sub, handle that - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - else: - # during the quarter - # update lineups first then change lineups based on subs - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - - # create and clean DataFrame - lineup_df = pd.DataFrame(lineups) - if lineup_df.iloc[-1].isnull().all(): - lineup_df.iloc[-1] = lineup_dict(aw_lineup, hm_lineup) - lineup_df = lineup_df.groupby(df.quarter).fillna(method='bfill') - - # fill in NaN's based on minutes played - bool_mat = lineup_df.isnull() - mask = bool_mat.any(axis=1) - if mask.any(): - bs = sportsref.nba.BoxScore(df.boxscore_id[0]) - # first, get the true minutes played from the box score - stats = sportsref.nba.BoxScore(df.boxscore_id.iloc[0]).basic_stats() - true_mp = pd.Series( - stats.query('mp > 0')[['player_id', 'mp']] - .set_index('player_id').to_dict()['mp'] - ) * 60 - # next, calculate minutes played based on the lineup data - calc_mp = pd.Series( - {p: (df.secs_elapsed.diff() * - [p in row for row in lineup_df.values]).sum() - for p in stats.query('mp > 0').player_id.values}) - # finally, figure which players are missing minutes - diff = true_mp - calc_mp - players_missing = diff.loc[diff.abs() >= 150] - hm_roster = bs.basic_stats().query('is_home == True').player_id.values - missing_df = pd.DataFrame( - {'secs': players_missing.values, - 'is_home': players_missing.index.isin(hm_roster)}, - index=players_missing.index - ) - - if missing_df.empty: - # TODO: log this as a warning (or error?) - print('There are NaNs in the lineup data, but no players were ' - 'found to be missing significant minutes') - else: - # import ipdb - # ipdb.set_trace() - for is_home, group in missing_df.groupby('is_home'): - player_id = group.index.item() - tm_cols = (sportsref.nba.pbp.HM_LINEUP_COLS if is_home else - sportsref.nba.pbp.AW_LINEUP_COLS) - row_mask = lineup_df[tm_cols].isnull().any(axis=1) - lineup_df.loc[row_mask, tm_cols] = ( - lineup_df.loc[row_mask, tm_cols].fillna(player_id).values - ) - - return lineup_df diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py deleted file mode 100644 index b255a6e..0000000 --- a/sportsref/cbb/players.py +++ /dev/null @@ -1,200 +0,0 @@ -import future -import future.utils - -import datetime -import re - -import numpy as np -from pyquery import PyQuery as pq - -import sportsref - -__all__ = [ - 'Player', -] - - -class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - """Each instance of this class represents an CBB player, uniquely - identified by a player ID. The instance methods give various data available - from the player's Sports Reference player page.""" - - def __init__(self, player_id): - self.player_id = player_id - self.url_base = (sportsref.cbb.BASE_URL + - '/players/{0}').format(self.player_id) - self.main_url = self.url_base + '.html' - - def __eq__(self, other): - return self.player_id == other.player_id - - def __hash__(self): - return hash(self.player_id) - - def __repr__(self): - return 'Player({})'.format(self.player_id) - - def __str__(self): - return self.name() - - @sportsref.decorators.memoize - def get_main_doc(self): - return pq(sportsref.utils.get_html(self.main_url)) - - @sportsref.decorators.memoize - def get_sub_doc(self, rel_url): - url = '{}/{}'.format(self.url_base, rel_url) - return pq(sportsref.utils.get_html(url)) - - @sportsref.decorators.memoize - def name(self): - """Returns the name of the player as a string.""" - doc = self.get_main_doc() - return doc('h1[itemprop="name"]').text() - - @sportsref.decorators.memoize - def age(self, year, month=2, day=1): - """Returns the age of the player on a given date. - - :year: int representing the year. - :month: int representing the month (1-12). - :day: int representing the day within the month (1-31). - :returns: Age in years as a float. - """ - doc = self.get_main_doc() - date_string = doc('span[itemprop="birthDate"]').attr('data-birth') - regex = r'(\d{4})\-(\d{2})\-(\d{2})' - date_args = list(map(int, re.match(regex, date_string).groups())) - birth_date = datetime.date(*date_args) - age_date = datetime.date(year=year, month=month, day=day) - delta = age_date - birth_date - age = delta.days / 365. - return age - - @sportsref.decorators.memoize - def position(self): - """TODO: Docstring for position. - :returns: TODO - """ - raise Exception('not yet implemented - nba.Player.position') - - @sportsref.decorators.memoize - def height(self): - """Returns the player's height (in inches). - :returns: An int representing a player's height in inches. - """ - doc = self.get_main_doc() - raw = doc('span[itemprop="height"]').text() - try: - feet, inches = list(map(int, raw.split('-'))) - return feet * 12 + inches - except ValueError: - return None - - @sportsref.decorators.memoize - def weight(self): - """Returns the player's weight (in pounds). - :returns: An int representing a player's weight in pounds. - """ - doc = self.get_main_doc() - raw = doc('span[itemprop="weight"]').text() - try: - weight = re.match(r'(\d+)lb', raw).group(1) - return int(weight) - except ValueError: - return None - - @sportsref.decorators.kind_rpb(include_type=True) - def _get_stats_table(self, table_id, kind='R', summary=False): - """Gets a stats table from the player page; helper function that does - the work for per-game, per-100-poss, etc. stats. - - :table_id: the ID of the HTML table. - :kind: specifies regular season, playoffs, or both. One of 'R', 'P', - 'B'. Defaults to 'R'. - :returns: A DataFrame of stats. - """ - doc = self.get_main_doc() - #print(doc) - table_id = 'table#{}{}'.format( - 'playoffs_' if kind == 'P' else '', table_id) - - #print(table_id) - table = doc(table_id) - #print(doc(table_id)) - df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) - return df - - @sportsref.decorators.memoize - def stats_per_game(self, kind='R', summary=False): - """Returns a DataFrame of per-game box score stats.""" - return self._get_stats_table('players_per_game', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_totals(self, kind='R', summary=False): - """Returns a DataFrame of total box score statistics by season.""" - return self._get_stats_table('totals', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_per36(self, kind='R', summary=False): - """Returns a DataFrame of per-36-minutes stats.""" - return self._get_stats_table('per_minute', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_per100(self, kind='R', summary=False): - """Returns a DataFrame of per-100-possession stats.""" - return self._get_stats_table('per_poss', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_advanced(self, kind='R', summary=False): - """Returns a DataFrame of advanced stats.""" - return self._get_stats_table('advanced', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_shooting(self, kind='R', summary=False): - """Returns a DataFrame of shooting stats.""" - return self._get_stats_table('shooting', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_pbp(self, kind='R', summary=False): - """Returns a DataFrame of play-by-play stats.""" - return self._get_stats_table('advanced_pbp', kind=kind, - summary=summary) - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_basic(self, year, kind='R'): - """Returns a table of a player's basic game-by-game stats for a season. - - :param year: The year representing the desired season. - :param kind: specifies regular season, playoffs, or both. One of 'R', - 'P', 'B'. Defaults to 'R'. - :returns: A DataFrame of the player's standard boxscore stats from each - game of the season. - :rtype: pd.DataFrame - """ - doc = self.get_sub_doc('gamelog/{}'.format(year)) - table = (doc('table#pgl_basic_playoffs') - if kind == 'P' else doc('table#pgl_basic')) - df = sportsref.utils.parse_table(table) - return df - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_advanced(self, year, kind='R'): - """Returns a table of a player's advanced game-by-game stats for a - season. - - :param year: The year representing the desired season. - :param kind: specifies regular season, playoffs, or both. One of 'R', - 'P', 'B'. Defaults to 'R'. - :returns: A DataFrame of the player's advanced stats from each game of - the season. - :rtype: pd.DataFrame - """ - doc = self.get_sub_doc('gamelog-advanced/{}'.format(year)) - table = (doc('table#pgl_advanced_playoffs') - if kind == 'P' else doc('table#pgl_advanced')) - df = sportsref.utils.parse_table(table) - return df diff --git a/sportsref/cbb/seasons.py b/sportsref/cbb/seasons.py deleted file mode 100644 index 5be3575..0000000 --- a/sportsref/cbb/seasons.py +++ /dev/null @@ -1,222 +0,0 @@ -import future -import future.utils - -import pandas as pd -from pyquery import PyQuery as pq - -import sportsref - - -class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - """Object representing a given NBA season.""" - - def __init__(self, year): - """Initializes a Season object for an NBA season. - - :year: The year of the season we want. - """ - self.yr = int(year) - - def __eq__(self, other): - return (self.yr == other.yr) - - def __hash__(self): - return hash(self.yr) - - def __repr__(self): - return 'Season({})'.format(self.yr) - - def _subpage_url(self, page): - return (sportsref.nba.BASE_URL + - '/leagues/NBA_{}_{}.html'.format(self.yr, page)) - - @sportsref.decorators.memoize - def get_main_doc(self): - """Returns PyQuery object for the main season URL. - :returns: PyQuery object. - """ - url = (sportsref.nba.BASE_URL + - '/leagues/NBA_{}.html'.format(self.yr)) - return pq(sportsref.utils.get_html(url)) - - @sportsref.decorators.memoize - def get_sub_doc(self, subpage): - """Returns PyQuery object for a given subpage URL. - :subpage: The subpage of the season, e.g. 'per_game'. - :returns: PyQuery object. - """ - html = sportsref.utils.get_html(self._subpage_url(subpage)) - return pq(html) - - @sportsref.decorators.memoize - def get_team_ids(self): - """Returns a list of the team IDs for the given year. - :returns: List of team IDs. - """ - df = self.team_stats_per_game() - if not df.empty: - return df.index.tolist() - else: - print('ERROR: no teams found') - return [] - - @sportsref.decorators.memoize - def team_ids_to_names(self): - """Mapping from 3-letter team IDs to full team names. - :returns: Dictionary with team IDs as keys and full team strings as - values. - """ - doc = self.get_main_doc() - table = doc('table#team-stats-per_game') - flattened = sportsref.utils.parse_table(table, flatten=True) - unflattened = sportsref.utils.parse_table(table, flatten=False) - team_ids = flattened['team_id'] - team_names = unflattened['team_name'] - if len(team_names) != len(team_ids): - raise Exception("team names and team IDs don't align") - return dict(list(zip(team_ids, team_names))) - - @sportsref.decorators.memoize - def team_names_to_ids(self): - """Mapping from full team names to 3-letter team IDs. - :returns: Dictionary with tean names as keys and team IDs as values. - """ - d = self.team_ids_to_names() - return {v: k for k, v in list(d.items())} - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def schedule(self, kind='R'): - """Returns a list of BoxScore IDs for every game in the season. - Only needs to handle 'R' or 'P' options because decorator handles 'B'. - - :param kind: 'R' for regular season, 'P' for playoffs, 'B' for both. - Defaults to 'R'. - :returns: DataFrame of schedule information. - :rtype: pd.DataFrame - """ - kind = kind.upper()[0] - dfs = [] - - # get games from each month - for month in ('october', 'november', 'december', 'january', 'february', - 'march', 'april', 'may', 'june'): - try: - doc = self.get_sub_doc('games-{}'.format(month)) - except ValueError: - continue - table = doc('table#schedule') - df = sportsref.utils.parse_table(table) - dfs.append(df) - df = pd.concat(dfs).reset_index(drop=True) - - # figure out how many regular season games - try: - sportsref.utils.get_html('{}/playoffs/NBA_{}.html'.format( - sportsref.nba.BASE_URL, self.yr) - ) - is_past_season = True - except ValueError: - is_past_season = False - - if is_past_season: - team_per_game = self.team_stats_per_game() - n_reg_games = int(team_per_game.g.sum() / 2) - else: - n_reg_games = len(df) - - # subset appropriately based on `kind` - if kind == 'P': - return df.iloc[n_reg_games:] - else: - return df.iloc[:n_reg_games] - - def finals_winner(self): - """Returns the team ID for the winner of that year's NBA Finals. - :returns: 3-letter team ID for champ. - """ - raise NotImplementedError('nba.Season.finals_winner') - - def finals_loser(self): - """Returns the team ID for the loser of that year's NBA Finals. - :returns: 3-letter team ID for runner-up. - """ - raise NotImplementedError('nba.Season.finals_loser') - - @sportsref.decorators.memoize - def _get_team_stats_table(self, selector): - """Helper function for stats tables on season pages. Returns a - DataFrame.""" - doc = self.get_main_doc() - table = doc(selector) - df = sportsref.utils.parse_table(table) - df.set_index('team_id', inplace=True) - return df - - def team_stats_per_game(self): - """Returns a Pandas DataFrame of each team's basic per-game stats for - the season.""" - return self._get_team_stats_table('table#team-stats-per_game') - - def opp_stats_per_game(self): - """Returns a Pandas DataFrame of each team's opponent's basic per-game - stats for the season.""" - return self._get_team_stats_table('table#opponent-stats-per_game') - - def team_stats_totals(self): - """Returns a Pandas DataFrame of each team's basic stat totals for the - season.""" - return self._get_team_stats_table('table#team-stats-base') - - def opp_stats_totals(self): - """Returns a Pandas DataFrame of each team's opponent's basic stat - totals for the season.""" - return self._get_team_stats_table('table#opponent-stats-base') - - def misc_stats(self): - """Returns a Pandas DataFrame of miscellaneous stats about each team's - season.""" - return self._get_team_stats_table('table#misc_stats') - - def team_stats_shooting(self): - """Returns a Pandas DataFrame of each team's shooting stats for the - season.""" - return self._get_team_stats_table('table#team_shooting') - - def opp_stats_shooting(self): - """Returns a Pandas DataFrame of each team's opponent's shooting stats - for the season.""" - return self._get_team_stats_table('table#opponent_shooting') - - @sportsref.decorators.memoize - def _get_player_stats_table(self, identifier): - """Helper function for player season stats. - - :identifier: string identifying the type of stat, e.g. 'per_game'. - :returns: A DataFrame of stats. - """ - doc = self.get_sub_doc(identifier) - table = doc('table#{}_stats'.format(identifier)) - df = sportsref.utils.parse_table(table) - return df - - def player_stats_per_game(self): - """Returns a DataFrame of per-game player stats for a season.""" - return self._get_player_stats_table('per_game') - - def player_stats_totals(self): - """Returns a DataFrame of player stat totals for a season.""" - return self._get_player_stats_table('totals') - - def player_stats_per36(self): - """Returns a DataFrame of player per-36 min stats for a season.""" - return self._get_player_stats_table('per_minute') - - def player_stats_per100(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('per_poss') - - def player_stats_advanced(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('advanced') diff --git a/sportsref/cbb/teams.py b/sportsref/cbb/teams.py deleted file mode 100644 index 86d56f9..0000000 --- a/sportsref/cbb/teams.py +++ /dev/null @@ -1,75 +0,0 @@ -import future -import future.utils - -import numpy as np -from pyquery import PyQuery as pq - -import sportsref - - -class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - def __init__(self, team_id): - self.team_id = team_id.upper() - - def __eq__(self, other): - return (self.team_id == other.team_id) - - def __hash__(self): - return hash(self.team_id) - - @sportsref.decorators.memoize - def team_year_url(self, yr_str): - return (sportsref.nba.BASE_URL + - '/teams/{}/{}.htm'.format(self.team_id, yr_str)) - - @sportsref.decorators.memoize - def get_main_doc(self): - relURL = '/teams/{}'.format(self.team_id) - teamURL = sportsref.nba.BASE_URL + relURL - mainDoc = pq(sportsref.utils.get_html(teamURL)) - return mainDoc - - @sportsref.decorators.memoize - def get_year_doc(self, yr_str): - return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) - - @sportsref.decorators.memoize - def name(self): - """Returns the real name of the franchise given the team ID. - - Examples: - 'BOS' -> 'Boston Celtics' - 'NJN' -> 'Brooklyn Nets' - - :returns: A string corresponding to the team's full name. - """ - doc = self.get_main_doc() - name = doc('div#info h1[itemprop="name"]').text() - return name - - @sportsref.decorators.memoize - def roster(self, year): - """Returns the roster table for the given year. - - :year: The year for which we want the roster; defaults to current year. - :returns: A DataFrame containing roster information for that year. - """ - doc = self.get_year_doc(year) - table = doc('table#roster') - df = sportsref.utils.parse_table(table) - df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) - return df - - # TODO: kind_rpb - @sportsref.decorators.memoize - def schedule(self, year): - """Gets schedule information for a team-season. - - :year: The year for which we want the schedule. - :returns: DataFrame of schedule information. - """ - doc = self.get_year_doc('{}_games'.format(year)) - table = doc('table#games') - df = sportsref.utils.parse_table(table) - return df From aaf6af8f545d18ea93bd0b2ec43bcb9768815971 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 13 Feb 2018 11:33:10 -0500 Subject: [PATCH 54/57] removed cbb --- sportsref/cbb/__init__.py | 20 -- sportsref/cbb/boxscores.py | 458 ------------------------- sportsref/cbb/pbp.py | 671 ------------------------------------- sportsref/cbb/players.py | 200 ----------- sportsref/cbb/seasons.py | 222 ------------ sportsref/cbb/teams.py | 75 ----- 6 files changed, 1646 deletions(-) delete mode 100644 sportsref/cbb/__init__.py delete mode 100644 sportsref/cbb/boxscores.py delete mode 100644 sportsref/cbb/pbp.py delete mode 100644 sportsref/cbb/players.py delete mode 100644 sportsref/cbb/seasons.py delete mode 100644 sportsref/cbb/teams.py diff --git a/sportsref/cbb/__init__.py b/sportsref/cbb/__init__.py deleted file mode 100644 index 6879d90..0000000 --- a/sportsref/cbb/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from . import boxscores -from . import pbp -from . import seasons -from . import teams - -from .boxscores import BoxScore -from .seasons import Season -from .teams import Team -from .players import Player - -BASE_URL = 'http://www.sports-reference.com/cbb' - -__all__ = [ - 'BASE_URL', - 'boxscores', 'BoxScore', - 'pbp', - 'seasons', 'Season', - 'teams', 'Team', - 'players', 'Player', -] diff --git a/sportsref/cbb/boxscores.py b/sportsref/cbb/boxscores.py deleted file mode 100644 index 20f3a8e..0000000 --- a/sportsref/cbb/boxscores.py +++ /dev/null @@ -1,458 +0,0 @@ -import future -import future.utils - -import datetime -import re - -import numpy as np -import pandas as pd -from pyquery import PyQuery as pq - -import sportsref - - -class BoxScore( - future.utils.with_metaclass(sportsref.decorators.Cached, object) -): - - def __init__(self, boxscore_id): - self.boxscore_id = boxscore_id - - def __eq__(self, other): - return self.boxscore_id == other.boxscore_id - - def __hash__(self): - return hash(self.boxscore_id) - - def __repr__(self): - return 'BoxScore({})'.format(self.boxscore_id) - - @sportsref.decorators.memoize - def get_main_doc(self): - url = ('{}/boxscores/{}.html' - .format(sportsref.nba.BASE_URL, self.boxscore_id)) - doc = pq(sportsref.utils.get_html(url)) - return doc - - @sportsref.decorators.memoize - def get_subpage_doc(self, page): - url = (sportsref.nba.BASE_URL + - '/boxscores/{}/{}.html'.format(page, self.boxscore_id)) - doc = pq(sportsref.utils.get_html(url)) - return doc - - @sportsref.decorators.memoize - def date(self): - """Returns the date of the game. See Python datetime.date documentation - for more. - :returns: A datetime.date object with year, month, and day attributes. - """ - match = re.match(r'(\d{4})(\d{2})(\d{2})', self.boxscore_id) - year, month, day = list(map(int, match.groups())) - return datetime.date(year=year, month=month, day=day) - - @sportsref.decorators.memoize - def weekday(self): - days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', - 'Saturday', 'Sunday'] - date = self.date() - wd = date.weekday() - return days[wd] - - @sportsref.decorators.memoize - def linescore(self): - """Returns the linescore for the game as a DataFrame.""" - doc = self.get_main_doc() - table = doc('table#line_score') - - columns = [th.text() for th in table('tr.thead').items('th')] - columns[0] = 'team_id' - - data = [ - [sportsref.utils.flatten_links(td) for td in list(tr('td').items())] - for tr in list(table('tr.thead').next_all('tr').items()) - ] - - return pd.DataFrame(data, index=['away', 'home'], - columns=columns, dtype='float') - - @sportsref.decorators.memoize - def home(self): - """Returns home team ID. - :returns: 3-character string representing home team's ID. - """ - linescore = self.linescore() - return linescore.loc['home', 'team_id'] - - @sportsref.decorators.memoize - def away(self): - """Returns away team ID. - :returns: 3-character string representing away team's ID. - """ - linescore = self.linescore() - return linescore.loc['away', 'team_id'] - - @sportsref.decorators.memoize - def home_score(self): - """Returns score of the home team. - :returns: int of the home score. - """ - linescore = self.linescore() - return linescore.loc['home', 'T'] - - @sportsref.decorators.memoize - def away_score(self): - """Returns score of the away team. - :returns: int of the away score. - """ - linescore = self.linescore() - return linescore.loc['away', 'T'] - - @sportsref.decorators.memoize - def winner(self): - """Returns the team ID of the winning team. Returns NaN if a tie.""" - hmScore = self.home_score() - awScore = self.away_score() - if hmScore > awScore: - return self.home() - elif hmScore < awScore: - return self.away() - else: - return None - - @sportsref.decorators.memoize - def season(self): - """ - Returns the year ID of the season in which this game took place. - - :returns: An int representing the year of the season. - """ - d = self.date() - if d.month >= 9: - return d.year + 1 - else: - return d.year - - def _get_player_stats(self, table_id_fmt): - """Returns a DataFrame of player stats from the game (either basic or - advanced, depending on the argument. - - :param table_id_fmt: Format string for str.format with a placeholder - for the team ID (e.g. 'box_{}_basic') - :returns: DataFrame of player stats - """ - - # get data - doc = self.get_main_doc() - tms = self.away(), self.home() - tm_ids = [table_id_fmt.format(tm) for tm in tms] - tables = [doc('table#{}'.format(tm_id).lower()) for tm_id in tm_ids] - dfs = [sportsref.utils.parse_table(table) for table in tables] - - # clean data and add features - for i, (tm, df) in enumerate(zip(tms, dfs)): - no_time = df['mp'] == 0 - stat_cols = [col for col, dtype in df.dtypes.items() - if dtype != 'object'] - df.loc[no_time, stat_cols] = 0 - df['team_id'] = tm - df['is_home'] = i == 1 - df['is_starter'] = [p < 5 for p in range(df.shape[0])] - df.drop_duplicates(subset='player_id', keep='first', inplace=True) - - return pd.concat(dfs) - - @sportsref.decorators.memoize - def basic_stats(self): - """Returns a DataFrame of basic player stats from the game.""" - return self._get_player_stats('box_{}_basic') - - @sportsref.decorators.memoize - def advanced_stats(self): - """Returns a DataFrame of advanced player stats from the game.""" - return self._get_player_stats('box_{}_advanced') - - @sportsref.decorators.memoize - def pbp(self, dense_lineups=False, sparse_lineups=False): - """Returns a dataframe of the play-by-play data from the game. - - :param dense_lineups: If True, adds 10 columns containing the names of - the players on the court. Defaults to False. - :param sparse_lineups: If True, adds binary columns denoting whether a - given player is in the game at the time of a pass. Defaults to - False. - :returns: pandas DataFrame of play-by-play. Similar to GPF. - """ - try: - doc = self.get_subpage_doc('pbp') - except: - raise ValueError( - 'Error fetching PBP subpage for boxscore {}' - .format(self.boxscore_id) - ) - table = doc('table#pbp') - trs = [ - tr for tr in list(table('tr').items()) - if (not tr.attr['class'] or # regular data rows - tr.attr['id'] and tr.attr['id'].startswith('q')) # qtr bounds - ] - rows = [tr.children('td') for tr in trs] - n_rows = len(trs) - data = [] - cur_qtr = 0 - bsid = self.boxscore_id - - for i in range(n_rows): - tr = trs[i] - row = rows[i] - p = {} - - # increment cur_qtr when we hit a new quarter - if tr.attr['id'] and tr.attr['id'].startswith('q'): - assert int(tr.attr['id'][1:]) == cur_qtr + 1 - cur_qtr += 1 - continue - - # add time of play to entry - t_str = row.eq(0).text() - t_regex = r'(\d+):(\d+)\.(\d+)' - mins, secs, tenths = list(map(int, re.match(t_regex, t_str).groups())) - endQ = (12 * 60 * min(cur_qtr, 4) + - 5 * 60 * (cur_qtr - 4 if cur_qtr > 4 else 0)) - secsElapsed = endQ - (60 * mins + secs + 0.1 * tenths) - p['secs_elapsed'] = secsElapsed - p['clock_time'] = t_str - p['quarter'] = cur_qtr - - # handle single play description - # ex: beginning/end of quarter, jump ball - if row.length == 2: - desc = row.eq(1) - # handle jump balls - if desc.text().lower().startswith('jump ball: '): - p['is_jump_ball'] = True - jb_str = sportsref.utils.flatten_links(desc) - p.update( - sportsref.nba.pbp.parse_play(bsid, jb_str, None) - ) - # ignore rows marking beginning/end of quarters - elif ( - desc.text().lower().startswith('start of ') or - desc.text().lower().startswith('end of ') - ): - continue - # if another case, log and continue - else: - if not desc.text().lower().startswith('end of '): - print(( - '{}, Q{}, {} other case: {}' - .format(self.boxscore_id, cur_qtr, - t_str, desc.text()) - )) - continue - - # handle team play description - # ex: shot, turnover, rebound, foul, sub, etc. - elif row.length == 6: - aw_desc, hm_desc = row.eq(1), row.eq(5) - is_hm_play = bool(hm_desc.text()) - desc = hm_desc if is_hm_play else aw_desc - desc = sportsref.utils.flatten_links(desc) - # parse the play - new_p = sportsref.nba.pbp.parse_play(bsid, desc, is_hm_play) - if not new_p: - continue - elif isinstance(new_p, list): - # this happens when a row needs to be expanded to 2 rows; - # ex: double personal foul -> two PF rows - - # first, update and append the first row - orig_p = dict(p) - p.update(new_p[0]) - data.append(p) - # second, set up the second row to be appended below - p = orig_p - new_p = new_p[1] - elif new_p.get('is_error'): - print(("can't parse: {}, boxscore: {}" - .format(desc, self.boxscore_id))) - # import pdb; pdb.set_trace() - p.update(new_p) - - # otherwise, I don't know what this was - else: - raise Exception(("don't know how to handle row of length {}" - .format(row.length))) - - data.append(p) - - # convert to DataFrame and clean columns - df = pd.DataFrame.from_records(data) - df.sort_values('secs_elapsed', inplace=True, kind='mergesort') - df = sportsref.nba.pbp.clean_features(df) - - # add columns for home team, away team, boxscore_id, date - away, home = self.away(), self.home() - df['home'] = home - df['away'] = away - df['boxscore_id'] = self.boxscore_id - df['season'] = self.season() - date = self.date() - df['year'] = date.year - df['month'] = date.month - df['day'] = date.day - - def _clean_rebs(df): - df.reset_index(drop=True, inplace=True) - no_reb_after = ( - (df.fta_num < df.tot_fta) | df.is_ftm | - df.get('is_tech_fta', False) - ).shift(1).fillna(False) - no_reb_before = ( - (df.fta_num == df.tot_fta) - ).shift(-1).fillna(False) - se_end_qtr = df.loc[ - df.clock_time == '0:00.0', 'secs_elapsed' - ].unique() - no_reb_when = df.secs_elapsed.isin(se_end_qtr) - drop_mask = ( - (df.rebounder == 'Team') & - (no_reb_after | no_reb_before | no_reb_when) - ).nonzero()[0] - df.drop(drop_mask, axis=0, inplace=True) - df.reset_index(drop=True, inplace=True) - return df - - # get rid of 'rebounds' after FTM, non-final FTA, or tech FTA - df = _clean_rebs(df) - - # track possession number for each possession - # TODO: see 201604130PHO, secs_elapsed == 2756 - # things that end a poss: - # FGM, dreb, TO, end of Q, made last FT, lost jump ball, - # def goaltending, shot clock violation - new_poss = (df.off_team == df.home).diff().fillna(False) - # def rebound considered part of the new possession - df['poss_id'] = np.cumsum(new_poss) + df.is_dreb - # create poss_id with rebs -> new possessions for granular groupbys - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # make sure plays with the same clock time are in the right order - # TODO: make sort_cols depend on what cols are in the play? - # or combine related plays, like and-1 shot and foul - # issues come up with FGA after timeout in 201604130LAL - # issues come up with PF between FGA and DREB in 201604120SAS - sort_cols = [col for col in - ['is_reb', 'is_fga', 'is_pf', 'is_tech_foul', - 'is_ejection', 'is_tech_fta', 'is_timeout', 'is_pf_fta', - 'fta_num', 'is_viol', 'is_to', 'is_jump_ball', 'is_sub'] - if col in df.columns] - asc_true = ['fta_num'] - ascend = [(col in asc_true) for col in sort_cols] - for label, group in df.groupby([df.secs_elapsed, poss_id_reb]): - if len(group) > 1: - df.loc[group.index, :] = group.sort_values( - sort_cols, ascending=ascend, kind='mergesort' - ).values - - # 2nd pass: get rid of 'rebounds' after FTM, non-final FTA, etc. - df = _clean_rebs(df) - - # makes sure off/def and poss_id are correct for subs after rearranging - # some possessions above - df.loc[df['is_sub'], ['off_team', 'def_team', 'poss_id']] = np.nan - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.poss_id.fillna(method='bfill', inplace=True) - # make off_team and def_team NaN for jump balls - if 'is_jump_ball' in df.columns: - df.loc[df['is_jump_ball'], ['off_team', 'def_team']] = np.nan - - # make sure 'off_team' is always the team shooting FTs, even on techs - # (impt for keeping track of the score) - if 'is_tech_fta' in df.columns: - tech_fta = df['is_tech_fta'] - df.loc[tech_fta, 'off_team'] = df.loc[tech_fta, 'fta_team'] - df.loc[tech_fta, 'def_team'] = np.where( - df.loc[tech_fta, 'off_team'] == home, away, home - ) - df.drop('fta_team', axis=1, inplace=True) - # redefine poss_id_reb - new_poss = (df.off_team == df.home).diff().fillna(False) - poss_id_reb = np.cumsum(new_poss | df.is_reb) - - # get rid of redundant subs - for (se, tm, pnum), group in df[df.is_sub].groupby( - [df.secs_elapsed, df.sub_team, poss_id_reb] - ): - if len(group) > 1: - sub_in = set() - sub_out = set() - # first, figure out who's in and who's out after subs - for i, row in group.iterrows(): - if row['sub_in'] in sub_out: - sub_out.remove(row['sub_in']) - else: - sub_in.add(row['sub_in']) - if row['sub_out'] in sub_in: - sub_in.remove(row['sub_out']) - else: - sub_out.add(row['sub_out']) - assert len(sub_in) == len(sub_out) - # second, add those subs - n_subs = len(sub_in) - for idx, p_in, p_out in zip( - group.index[:n_subs], sub_in, sub_out - ): - assert df.loc[idx, 'is_sub'] - df.loc[idx, 'sub_in'] = p_in - df.loc[idx, 'sub_out'] = p_out - df.loc[idx, 'sub_team'] = tm - df.loc[idx, 'detail'] = ( - '{} enters the game for {}'.format(p_in, p_out) - ) - # third, if applicable, remove old sub entries when there are - # redundant subs - n_extra = len(group) - len(sub_in) - if n_extra: - extra_idxs = group.index[-n_extra:] - df.drop(extra_idxs, axis=0, inplace=True) - - df.reset_index(drop=True, inplace=True) - - # add column for pts and score - df['pts'] = (df['is_ftm'] + 2 * df['is_fgm'] + - (df['is_fgm'] & df['is_three'])) - df['hm_pts'] = np.where(df.off_team == df.home, df.pts, 0) - df['aw_pts'] = np.where(df.off_team == df.away, df.pts, 0) - df['hm_score'] = np.cumsum(df['hm_pts']) - df['aw_score'] = np.cumsum(df['aw_pts']) - - # more helpful columns - # "play" is differentiated from "poss" by counting OReb as new play - # "plays" end with non-and1 FGA, TO, last non-tech FTA, or end of qtr - # (or double lane viol) - new_qtr = df.quarter.diff().shift(-1).fillna(False).astype(bool) - and1 = (df.is_fgm & df.is_pf.shift(-1).fillna(False) & - df.is_fta.shift(-2).fillna(False) & - ~df.secs_elapsed.diff().shift(-1).fillna(False).astype(bool)) - double_lane = (df.get('viol_type') == 'double lane') - new_play = df.eval('(is_fga & ~(@and1)) | is_to | @new_qtr |' - '(is_fta & ~is_tech_fta & fta_num == tot_fta) |' - '@double_lane') - df['play_id'] = np.cumsum(new_play).shift(1).fillna(0) - df['hm_off'] = df.off_team == df.home - - # get lineup data - if dense_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_dense_lineups(df)), axis=1 - ) - if sparse_lineups: - df = pd.concat( - (df, sportsref.nba.pbp.get_sparse_lineups(df)), axis=1 - ) - - # TODO: add shot clock as a feature - - return df diff --git a/sportsref/cbb/pbp.py b/sportsref/cbb/pbp.py deleted file mode 100644 index a67eebd..0000000 --- a/sportsref/cbb/pbp.py +++ /dev/null @@ -1,671 +0,0 @@ -from builtins import enumerate, int, list, range, zip - -import operator -import re - -import numpy as np -import pandas as pd - -import sportsref - -PLAYER_RE = r'\w{0,7}\d{2}' - -HM_LINEUP_COLS = ['hm_player{}'.format(i) for i in range(1, 6)] -AW_LINEUP_COLS = ['aw_player{}'.format(i) for i in range(1, 6)] -ALL_LINEUP_COLS = AW_LINEUP_COLS + HM_LINEUP_COLS - - -def sparse_lineup_cols(df): - regex = '{}_in'.format(PLAYER_RE) - return [c for c in df.columns if re.match(regex, c)] - - -def parse_play(boxscore_id, details, is_hm): - """Parse play details from a play-by-play string describing a play. - - Assuming valid input, this function returns structured data in a dictionary - describing the play. If the play detail string was invalid, this function - returns None. - - :param boxscore_id: the boxscore ID of the play - :param details: detail string for the play - :param is_hm: bool indicating whether the offense is at home - :param returns: dictionary of play attributes or None if invalid - :rtype: dictionary or None - """ - # if input isn't a string, return None - if not details or not isinstance(details, str): - return None - - bs = sportsref.nba.BoxScore(boxscore_id) - aw, hm = bs.away(), bs.home() - season = sportsref.nba.Season(bs.season()) - hm_roster = set(bs.basic_stats().query('is_home == True').player_id.values) - - p = {} - p['detail'] = details - p['home'] = hm - p['away'] = aw - p['is_home_play'] = is_hm - - # parsing field goal attempts - shotRE = (r'(?P{0}) (?Pmakes|misses) ' - '(?P2|3)\-pt shot').format(PLAYER_RE) - distRE = r' (?:from (?P\d+) ft|at rim)' - assistRE = r' \(assist by (?P{0})\)'.format(PLAYER_RE) - blockRE = r' \(block by (?P{0})\)'.format(PLAYER_RE) - shotRE = r'{0}{1}(?:{2}|{3})?'.format(shotRE, distRE, assistRE, blockRE) - m = re.match(shotRE, details, re.IGNORECASE) - if m: - p['is_fga'] = True - p.update(m.groupdict()) - p['shot_dist'] = p['shot_dist'] if p['shot_dist'] is not None else 0 - p['shot_dist'] = int(p['shot_dist']) - p['is_fgm'] = p['is_fgm'] == 'makes' - p['is_three'] = p['is_three'] == '3' - p['is_assist'] = pd.notnull(p.get('assister')) - p['is_block'] = pd.notnull(p.get('blocker')) - shooter_home = p['shooter'] in hm_roster - p['off_team'] = hm if shooter_home else aw - p['def_team'] = aw if shooter_home else hm - return p - - # parsing jump balls - jumpRE = ((r'Jump ball: (?P{0}) vs\. (?P{0})' - r'(?: \((?P{0}) gains possession\))?') - .format(PLAYER_RE)) - m = re.match(jumpRE, details, re.IGNORECASE) - if m: - p['is_jump_ball'] = True - p.update(m.groupdict()) - return p - - # parsing rebounds - rebRE = (r'(?POffensive|Defensive) rebound' - r' by (?P{0}|Team)').format(PLAYER_RE) - m = re.match(rebRE, details, re.I) - if m: - p['is_reb'] = True - p.update(m.groupdict()) - p['is_oreb'] = p['is_oreb'].lower() == 'offensive' - p['is_dreb'] = not p['is_oreb'] - if p['rebounder'] == 'Team': - p['reb_team'], other = (hm, aw) if is_hm else (aw, hm) - else: - reb_home = p['rebounder'] in hm_roster - p['reb_team'], other = (hm, aw) if reb_home else (aw, hm) - p['off_team'] = p['reb_team'] if p['is_oreb'] else other - p['def_team'] = p['reb_team'] if p['is_dreb'] else other - return p - - # parsing free throws - ftRE = (r'(?P{}) (?Pmakes|misses) ' - r'(?Ptechnical )?(?Pflagrant )?' - r'(?Pclear path )?free throw' - r'(?: (?P\d+) of (?P\d+))?').format(PLAYER_RE) - m = re.match(ftRE, details, re.I) - if m: - p['is_fta'] = True - p.update(m.groupdict()) - p['is_ftm'] = p['is_ftm'] == 'makes' - p['is_tech_fta'] = bool(p['is_tech_fta']) - p['is_flag_fta'] = bool(p['is_flag_fta']) - p['is_clearpath_fta'] = bool(p['is_clearpath_fta']) - p['is_pf_fta'] = not p['is_tech_fta'] - if p['tot_fta']: - p['tot_fta'] = int(p['tot_fta']) - if p['fta_num']: - p['fta_num'] = int(p['fta_num']) - ft_home = p['ft_shooter'] in hm_roster - p['fta_team'] = hm if ft_home else aw - if not p['is_tech_fta']: - p['off_team'] = hm if ft_home else aw - p['def_team'] = aw if ft_home else hm - return p - - # parsing substitutions - subRE = (r'(?P{0}) enters the game for ' - r'(?P{0})').format(PLAYER_RE) - m = re.match(subRE, details, re.I) - if m: - p['is_sub'] = True - p.update(m.groupdict()) - sub_home = p['sub_in'] in hm_roster or p['sub_out'] in hm_roster - p['sub_team'] = hm if sub_home else aw - return p - - # parsing turnovers - toReasons = (r'(?P[^;]+)(?:; steal by ' - r'(?P{0}))?').format(PLAYER_RE) - toRE = (r'Turnover by (?P{}|Team) ' - r'\((?:{})\)').format(PLAYER_RE, toReasons) - m = re.match(toRE, details, re.I) - if m: - p['is_to'] = True - p.update(m.groupdict()) - p['to_type'] = p['to_type'].lower() - if p['to_type'] == 'offensive foul': - return None - p['is_steal'] = pd.notnull(p['stealer']) - p['is_travel'] = p['to_type'] == 'traveling' - p['is_shot_clock_viol'] = p['to_type'] == 'shot clock' - p['is_oob'] = p['to_type'] == 'step out of bounds' - p['is_three_sec_viol'] = p['to_type'] == '3 sec' - p['is_backcourt_viol'] = p['to_type'] == 'back court' - p['is_off_goaltend'] = p['to_type'] == 'offensive goaltending' - p['is_double_dribble'] = p['to_type'] == 'dbl dribble' - p['is_discont_dribble'] = p['to_type'] == 'discontinued dribble' - p['is_carry'] = p['to_type'] == 'palming' - if p['to_by'] == 'Team': - p['off_team'] = hm if is_hm else aw - p['def_team'] = aw if is_hm else hm - else: - to_home = p['to_by'] in hm_roster - p['off_team'] = hm if to_home else aw - p['def_team'] = aw if to_home else hm - return p - - # parsing shooting fouls - shotFoulRE = (r'Shooting(?P block)? foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(shotFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_shot_foul'] = True - p.update(m.groupdict()) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing offensive fouls - offFoulRE = (r'Offensive(?P charge)? foul ' - r'by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(offFoulRE, details, re.I) - if m: - p['is_pf'] = True - p['is_off_foul'] = True - p['is_to'] = True - p['to_type'] = 'offensive foul' - p.update(m.groupdict()) - p['is_charge'] = bool(p['is_charge']) - p['fouler'] = p['to_by'] - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = hm if foul_on_home else aw - p['def_team'] = aw if foul_on_home else hm - p['foul_team'] = p['off_team'] - return p - - # parsing personal fouls - foulRE = (r'Personal (?Ptake )?(?Pblock )?' - r'foul by (?P{0})(?: \(drawn by ' - r'(?P{0})\))?').format(PLAYER_RE) - m = re.match(foulRE, details, re.I) - if m: - p['is_pf'] = True - p.update(m.groupdict()) - p['is_take_foul'] = bool(p['is_take_foul']) - p['is_block_foul'] = bool(p['is_block_foul']) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # TODO: parsing double personal fouls - # double_foul_re = (r'Double personal foul by (?P{0}) and ' - # r'(?P{0})').format(PLAYER_RE) - # m = re.match(double_Foul_re, details, re.I) - # if m: - # p['is_pf'] = True - # p.update(m.groupdict()) - # p['off_team'] = - - # parsing loose ball fouls - looseBallRE = (r'Loose ball foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(looseBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_loose_ball_foul'] = True - p.update(m.groupdict()) - foul_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_home else aw - return p - - # parsing punching fouls - # TODO - - # parsing away from play fouls - awayFromBallRE = ((r'Away from play foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?') - .format(PLAYER_RE)) - m = re.match(awayFromBallRE, details, re.I) - if m: - p['is_pf'] = True - p['is_away_from_play_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - # TODO: figure out who had the ball based on previous play - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing inbound fouls - inboundRE = (r'Inbound foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(inboundRE, details, re.I) - if m: - p['is_pf'] = True - p['is_inbound_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing flagrant fouls - flagrantRE = (r'Flagrant foul type (?P1|2) by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(flagrantRE, details, re.I) - if m: - p['is_pf'] = True - p['is_flagrant'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing clear path fouls - clearPathRE = (r'Clear path foul by (?P{0})' - r'(?: \(drawn by (?P{0})\))?').format(PLAYER_RE) - m = re.match(clearPathRE, details, re.I) - if m: - p['is_pf'] = True - p['is_clear_path_foul'] = True - p.update(m.groupdict()) - foul_on_home = p['fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing timeouts - timeoutRE = r'(?P.*?) (?:full )?timeout' - m = re.match(timeoutRE, details, re.I) - if m: - p['is_timeout'] = True - p.update(m.groupdict()) - isOfficialTO = p['timeout_team'].lower() == 'official' - name_to_id = season.team_names_to_ids() - p['timeout_team'] = ( - 'Official' if isOfficialTO else - name_to_id.get(hm, name_to_id.get(aw, p['timeout_team'])) - ) - return p - - # parsing technical fouls - techRE = (r'(?PHanging )?' - r'(?PTaunting )?' - r'(?PIll def )?' - r'(?PDelay )?' - r'(?PNon unsport )?' - r'tech(?:nical)? foul by ' - r'(?P{0}|Team)').format(PLAYER_RE) - m = re.match(techRE, details, re.I) - if m: - p['is_tech_foul'] = True - p.update(m.groupdict()) - p['is_hanging'] = bool(p['is_hanging']) - p['is_taunting'] = bool(p['is_taunting']) - p['is_ill_def'] = bool(p['is_ill_def']) - p['is_delay'] = bool(p['is_delay']) - p['is_unsport'] = bool(p['is_unsport']) - foul_on_home = p['tech_fouler'] in hm_roster - p['foul_team'] = hm if foul_on_home else aw - return p - - # parsing ejections - ejectRE = r'(?P{0}|Team) ejected from game'.format(PLAYER_RE) - m = re.match(ejectRE, details, re.I) - if m: - p['is_ejection'] = True - p.update(m.groupdict()) - if p['ejectee'] == 'Team': - p['ejectee_team'] = hm if is_hm else aw - else: - eject_home = p['ejectee'] in hm_roster - p['ejectee_team'] = hm if eject_home else aw - return p - - # parsing defensive 3 seconds techs - def3TechRE = (r'(?:Def 3 sec tech foul|Defensive three seconds)' - r' by (?P{})').format(PLAYER_RE) - m = re.match(def3TechRE, details, re.I) - if m: - p['is_tech_foul'] = True - p['is_def_three_secs'] = True - p.update(m.groupdict()) - foul_on_home = p['tech_fouler'] in hm_roster - p['off_team'] = aw if foul_on_home else hm - p['def_team'] = hm if foul_on_home else aw - p['foul_team'] = p['def_team'] - return p - - # parsing violations - violRE = (r'Violation by (?P{0}|Team) ' - r'\((?P.*)\)').format(PLAYER_RE) - m = re.match(violRE, details, re.I) - if m: - p['is_viol'] = True - p.update(m.groupdict()) - if p['viol_type'] == 'kicked_ball': - p['is_to'] = True - p['to_by'] = p['violator'] - if p['violator'] == 'Team': - p['viol_team'] = hm if is_hm else aw - else: - viol_home = p['violator'] in hm_roster - p['viol_team'] = hm if viol_home else aw - return p - - p['is_error'] = True - return p - - -def clean_features(df): - """Fixes up columns of the passed DataFrame, such as casting T/F columns to - boolean and filling in NaNs for team and opp. - - :param df: DataFrame of play-by-play data. - :returns: Dataframe with cleaned columns. - """ - df = pd.DataFrame(df) - - bool_vals = set([True, False, None, np.nan]) - sparse_cols = sparse_lineup_cols(df) - for col in df: - - # make indicator columns boolean type (and fill in NaNs) - if set(df[col].unique()[:5]) <= bool_vals: - df[col] = (df[col] == True) - - # fill NaN's in sparse lineup columns to 0 - elif col in sparse_cols: - df[col] = df[col].fillna(0) - - # fix free throw columns on technicals - df.loc[df.is_tech_fta, ['fta_num', 'tot_fta']] = 1 - - # fill in NaN's/fix off_team and def_team columns - df.off_team.fillna(method='bfill', inplace=True) - df.def_team.fillna(method='bfill', inplace=True) - df.off_team.fillna(method='ffill', inplace=True) - df.def_team.fillna(method='ffill', inplace=True) - - return df - - -def clean_multigame_features(df): - """TODO: Docstring for clean_multigame_features. - - :df: TODO - :returns: TODO - """ - df = pd.DataFrame(df) - if df.index.value_counts().max() > 1: - df.reset_index(drop=True, inplace=True) - - df = clean_features(df) - - # if it's many games in one DataFrame, make poss_id and play_id unique - for col in ('play_id', 'poss_id'): - diffs = df[col].diff().fillna(0) - if (diffs < 0).any(): - new_col = np.cumsum(diffs.astype(bool)) - df.eval('{} = @new_col'.format(col), inplace=True) - - return df - - -def get_period_starters(df): - """TODO - """ - - def players_from_play(play): - """Figures out what players are in the game based on the players - mentioned in a play. Returns away and home players as two sets. - - :param play: A dictionary representing a parsed play. - :returns: (aw_players, hm_players) - :rtype: tuple of lists - """ - # if it's a tech FT from between periods, don't count this play - if ( - play['clock_time'] == '12:00.0' and - (play.get('is_tech_foul') or play.get('is_tech_fta')) - ): - return [], [] - - stats = sportsref.nba.BoxScore(play['boxscore_id']).basic_stats() - home_grouped = stats.groupby('is_home') - hm_roster = set(home_grouped.player_id.get_group(True).values) - aw_roster = set(home_grouped.player_id.get_group(False).values) - player_keys = [ - 'assister', 'away_jumper', 'blocker', 'drew_foul', 'fouler', - 'ft_shooter', 'gains_poss', 'home_jumper', 'rebounder', 'shooter', - 'stealer', 'sub_in', 'sub_out', 'to_by' - ] - players = [p for p in play[player_keys] if pd.notnull(p)] - - aw_players = [p for p in players if p in aw_roster] - hm_players = [p for p in players if p in hm_roster] - return aw_players, hm_players - - # create a mapping { quarter => (away_starters, home_starters) } - n_periods = df.quarter.nunique() - period_starters = [(set(), set()) for _ in range(n_periods)] - - # fill out this mapping quarter by quarter - for qtr, qtr_grp in df.groupby(df.quarter): - aw_starters, hm_starters = period_starters[qtr-1] - exclude = set() - # loop through sets of plays that happen at the "same time" - for label, time_grp in qtr_grp.groupby(qtr_grp.secs_elapsed): - # first, if they sub in and weren't already starters, exclude them - sub_ins = set(time_grp.sub_in.dropna().values) - exclude.update(sub_ins - aw_starters - hm_starters) - # second, figure out new starters from each play at this time - for i, row in time_grp.iterrows(): - aw_players, hm_players = players_from_play(row) - # update overall sets for the quarter - aw_starters.update(aw_players) - hm_starters.update(hm_players) - # remove excluded (subbed-in) players - hm_starters -= exclude - aw_starters -= exclude - # check whether we have found all starters - if len(hm_starters) > 5 or len(aw_starters) > 5: - import ipdb - ipdb.set_trace() - if len(hm_starters) >= 5 and len(aw_starters) >= 5: - break - - if len(hm_starters) != 5 or len(aw_starters) != 5: - print(('WARNING: wrong number of starters for a team in Q{} of {}' - .format(qtr, df.boxscore_id.iloc[0]))) - - return period_starters - - -def get_sparse_lineups(df): - """TODO: Docstring for get_sparse_lineups. - - :param df: TODO - :returns: TODO - """ - - # get the lineup data using get_dense_lineups if necessary - if (set(ALL_LINEUP_COLS) - set(df.columns)): - lineup_df = get_dense_lineups(df) - else: - lineup_df = df[ALL_LINEUP_COLS] - - # create the sparse representation - hm_lineups = lineup_df[HM_LINEUP_COLS].values - aw_lineups = lineup_df[AW_LINEUP_COLS].values - # +1 for home, -1 for away - hm_df = pd.DataFrame([ - {'{}_in'.format(player_id): 1 for player_id in lineup} - for lineup in hm_lineups - ], dtype=int) - aw_df = pd.DataFrame([ - {'{}_in'.format(player_id): -1 for player_id in lineup} - for lineup in aw_lineups - ], dtype=int) - sparse_df = pd.concat((hm_df, aw_df), axis=1).fillna(0) - return sparse_df - - -def get_dense_lineups(df): - """Returns a new DataFrame based on the one it is passed. Specifically, it - adds five columns for each team (ten total), where each column has the ID - of a player on the court during the play. - - This information is figured out sequentially from the game's substitution - data in the passed DataFrame, so the DataFrame passed as an argument must - be from a specific BoxScore (rather than a DataFrame of non-consecutive - plays). That is, the DataFrame must be of the form returned by - :func:`nba.BoxScore.pbp `. - - .. note:: Note that the lineups reflect the teams in the game when the play - happened, not after the play. For example, if a play is a substitution, - the lineups for that play will be the lineups before the substituion - occurs. - - :param df: A DataFrame of a game's play-by-play data. - :returns: A DataFrame with additional lineup columns. - - """ - # TODO: add this precondition to documentation - assert df['boxscore_id'].nunique() == 1 - - def lineup_dict(aw_lineup, hm_lineup): - """Returns a dictionary of lineups to be converted to columns. - Specifically, the columns are 'aw_player1' through 'aw_player5' and - 'hm_player1' through 'hm_player5'. - - :param aw_lineup: The away team's current lineup. - :param hm_lineup: The home team's current lineup. - :returns: A dictionary of lineups. - """ - return { - '{}_player{}'.format(tm, i+1): player - for tm, lineup in zip(['aw', 'hm'], [aw_lineup, hm_lineup]) - for i, player in enumerate(lineup) - } - - def handle_sub(row, aw_lineup, hm_lineup): - """Modifies the aw_lineup and hm_lineup lists based on the substitution - that takes place in the given row.""" - assert row['is_sub'] - sub_lineup = hm_lineup if row['sub_team'] == row['home'] else aw_lineup - try: - # make the sub - idx = sub_lineup.index(row['sub_out']) - sub_lineup[idx] = row['sub_in'] - except ValueError: - # if the sub was double-entered and it's already been executed... - if ( - row['sub_in'] in sub_lineup - and row['sub_out'] not in sub_lineup - ): - return aw_lineup, hm_lineup - # otherwise, let's print and pretend this never happened - print(('ERROR IN SUB IN {}, Q{}, {}: {}' - .format(row['boxscore_id'], row['quarter'], - row['clock_time'], row['detail']))) - raise - return aw_lineup, hm_lineup - - per_starters = get_period_starters(df) - cur_qtr = 0 - aw_lineup, hm_lineup = [], [] - df = df.reset_index(drop=True) - lineups = [{} for _ in range(df.shape[0])] - - # loop through select plays to determine lineups - sub_or_per_start = df.is_sub | df.quarter.diff().astype(bool) - for i, row in df.loc[sub_or_per_start].iterrows(): - if row['quarter'] > cur_qtr: - # first row in a quarter - assert row['quarter'] == cur_qtr + 1 - # first, finish up the last quarter's lineups - if cur_qtr > 0 and not df.loc[i-1, 'is_sub']: - lineups[i-1] = lineup_dict(aw_lineup, hm_lineup) - # then, move on to the quarter, and enter the starting lineups - cur_qtr += 1 - aw_lineup, hm_lineup = list(map(list, per_starters[cur_qtr-1])) - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - # if the first play in the quarter is a sub, handle that - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - else: - # during the quarter - # update lineups first then change lineups based on subs - lineups[i] = lineup_dict(aw_lineup, hm_lineup) - if row['is_sub']: - aw_lineup, hm_lineup = handle_sub(row, aw_lineup, hm_lineup) - - # create and clean DataFrame - lineup_df = pd.DataFrame(lineups) - if lineup_df.iloc[-1].isnull().all(): - lineup_df.iloc[-1] = lineup_dict(aw_lineup, hm_lineup) - lineup_df = lineup_df.groupby(df.quarter).fillna(method='bfill') - - # fill in NaN's based on minutes played - bool_mat = lineup_df.isnull() - mask = bool_mat.any(axis=1) - if mask.any(): - bs = sportsref.nba.BoxScore(df.boxscore_id[0]) - # first, get the true minutes played from the box score - stats = sportsref.nba.BoxScore(df.boxscore_id.iloc[0]).basic_stats() - true_mp = pd.Series( - stats.query('mp > 0')[['player_id', 'mp']] - .set_index('player_id').to_dict()['mp'] - ) * 60 - # next, calculate minutes played based on the lineup data - calc_mp = pd.Series( - {p: (df.secs_elapsed.diff() * - [p in row for row in lineup_df.values]).sum() - for p in stats.query('mp > 0').player_id.values}) - # finally, figure which players are missing minutes - diff = true_mp - calc_mp - players_missing = diff.loc[diff.abs() >= 150] - hm_roster = bs.basic_stats().query('is_home == True').player_id.values - missing_df = pd.DataFrame( - {'secs': players_missing.values, - 'is_home': players_missing.index.isin(hm_roster)}, - index=players_missing.index - ) - - if missing_df.empty: - # TODO: log this as a warning (or error?) - print('There are NaNs in the lineup data, but no players were ' - 'found to be missing significant minutes') - else: - # import ipdb - # ipdb.set_trace() - for is_home, group in missing_df.groupby('is_home'): - player_id = group.index.item() - tm_cols = (sportsref.nba.pbp.HM_LINEUP_COLS if is_home else - sportsref.nba.pbp.AW_LINEUP_COLS) - row_mask = lineup_df[tm_cols].isnull().any(axis=1) - lineup_df.loc[row_mask, tm_cols] = ( - lineup_df.loc[row_mask, tm_cols].fillna(player_id).values - ) - - return lineup_df diff --git a/sportsref/cbb/players.py b/sportsref/cbb/players.py deleted file mode 100644 index b255a6e..0000000 --- a/sportsref/cbb/players.py +++ /dev/null @@ -1,200 +0,0 @@ -import future -import future.utils - -import datetime -import re - -import numpy as np -from pyquery import PyQuery as pq - -import sportsref - -__all__ = [ - 'Player', -] - - -class Player(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - """Each instance of this class represents an CBB player, uniquely - identified by a player ID. The instance methods give various data available - from the player's Sports Reference player page.""" - - def __init__(self, player_id): - self.player_id = player_id - self.url_base = (sportsref.cbb.BASE_URL + - '/players/{0}').format(self.player_id) - self.main_url = self.url_base + '.html' - - def __eq__(self, other): - return self.player_id == other.player_id - - def __hash__(self): - return hash(self.player_id) - - def __repr__(self): - return 'Player({})'.format(self.player_id) - - def __str__(self): - return self.name() - - @sportsref.decorators.memoize - def get_main_doc(self): - return pq(sportsref.utils.get_html(self.main_url)) - - @sportsref.decorators.memoize - def get_sub_doc(self, rel_url): - url = '{}/{}'.format(self.url_base, rel_url) - return pq(sportsref.utils.get_html(url)) - - @sportsref.decorators.memoize - def name(self): - """Returns the name of the player as a string.""" - doc = self.get_main_doc() - return doc('h1[itemprop="name"]').text() - - @sportsref.decorators.memoize - def age(self, year, month=2, day=1): - """Returns the age of the player on a given date. - - :year: int representing the year. - :month: int representing the month (1-12). - :day: int representing the day within the month (1-31). - :returns: Age in years as a float. - """ - doc = self.get_main_doc() - date_string = doc('span[itemprop="birthDate"]').attr('data-birth') - regex = r'(\d{4})\-(\d{2})\-(\d{2})' - date_args = list(map(int, re.match(regex, date_string).groups())) - birth_date = datetime.date(*date_args) - age_date = datetime.date(year=year, month=month, day=day) - delta = age_date - birth_date - age = delta.days / 365. - return age - - @sportsref.decorators.memoize - def position(self): - """TODO: Docstring for position. - :returns: TODO - """ - raise Exception('not yet implemented - nba.Player.position') - - @sportsref.decorators.memoize - def height(self): - """Returns the player's height (in inches). - :returns: An int representing a player's height in inches. - """ - doc = self.get_main_doc() - raw = doc('span[itemprop="height"]').text() - try: - feet, inches = list(map(int, raw.split('-'))) - return feet * 12 + inches - except ValueError: - return None - - @sportsref.decorators.memoize - def weight(self): - """Returns the player's weight (in pounds). - :returns: An int representing a player's weight in pounds. - """ - doc = self.get_main_doc() - raw = doc('span[itemprop="weight"]').text() - try: - weight = re.match(r'(\d+)lb', raw).group(1) - return int(weight) - except ValueError: - return None - - @sportsref.decorators.kind_rpb(include_type=True) - def _get_stats_table(self, table_id, kind='R', summary=False): - """Gets a stats table from the player page; helper function that does - the work for per-game, per-100-poss, etc. stats. - - :table_id: the ID of the HTML table. - :kind: specifies regular season, playoffs, or both. One of 'R', 'P', - 'B'. Defaults to 'R'. - :returns: A DataFrame of stats. - """ - doc = self.get_main_doc() - #print(doc) - table_id = 'table#{}{}'.format( - 'playoffs_' if kind == 'P' else '', table_id) - - #print(table_id) - table = doc(table_id) - #print(doc(table_id)) - df = sportsref.utils.parse_table(table, flatten=(not summary), footer=summary) - return df - - @sportsref.decorators.memoize - def stats_per_game(self, kind='R', summary=False): - """Returns a DataFrame of per-game box score stats.""" - return self._get_stats_table('players_per_game', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_totals(self, kind='R', summary=False): - """Returns a DataFrame of total box score statistics by season.""" - return self._get_stats_table('totals', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_per36(self, kind='R', summary=False): - """Returns a DataFrame of per-36-minutes stats.""" - return self._get_stats_table('per_minute', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_per100(self, kind='R', summary=False): - """Returns a DataFrame of per-100-possession stats.""" - return self._get_stats_table('per_poss', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_advanced(self, kind='R', summary=False): - """Returns a DataFrame of advanced stats.""" - return self._get_stats_table('advanced', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_shooting(self, kind='R', summary=False): - """Returns a DataFrame of shooting stats.""" - return self._get_stats_table('shooting', kind=kind, summary=summary) - - @sportsref.decorators.memoize - def stats_pbp(self, kind='R', summary=False): - """Returns a DataFrame of play-by-play stats.""" - return self._get_stats_table('advanced_pbp', kind=kind, - summary=summary) - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_basic(self, year, kind='R'): - """Returns a table of a player's basic game-by-game stats for a season. - - :param year: The year representing the desired season. - :param kind: specifies regular season, playoffs, or both. One of 'R', - 'P', 'B'. Defaults to 'R'. - :returns: A DataFrame of the player's standard boxscore stats from each - game of the season. - :rtype: pd.DataFrame - """ - doc = self.get_sub_doc('gamelog/{}'.format(year)) - table = (doc('table#pgl_basic_playoffs') - if kind == 'P' else doc('table#pgl_basic')) - df = sportsref.utils.parse_table(table) - return df - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def gamelog_advanced(self, year, kind='R'): - """Returns a table of a player's advanced game-by-game stats for a - season. - - :param year: The year representing the desired season. - :param kind: specifies regular season, playoffs, or both. One of 'R', - 'P', 'B'. Defaults to 'R'. - :returns: A DataFrame of the player's advanced stats from each game of - the season. - :rtype: pd.DataFrame - """ - doc = self.get_sub_doc('gamelog-advanced/{}'.format(year)) - table = (doc('table#pgl_advanced_playoffs') - if kind == 'P' else doc('table#pgl_advanced')) - df = sportsref.utils.parse_table(table) - return df diff --git a/sportsref/cbb/seasons.py b/sportsref/cbb/seasons.py deleted file mode 100644 index 5be3575..0000000 --- a/sportsref/cbb/seasons.py +++ /dev/null @@ -1,222 +0,0 @@ -import future -import future.utils - -import pandas as pd -from pyquery import PyQuery as pq - -import sportsref - - -class Season(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - """Object representing a given NBA season.""" - - def __init__(self, year): - """Initializes a Season object for an NBA season. - - :year: The year of the season we want. - """ - self.yr = int(year) - - def __eq__(self, other): - return (self.yr == other.yr) - - def __hash__(self): - return hash(self.yr) - - def __repr__(self): - return 'Season({})'.format(self.yr) - - def _subpage_url(self, page): - return (sportsref.nba.BASE_URL + - '/leagues/NBA_{}_{}.html'.format(self.yr, page)) - - @sportsref.decorators.memoize - def get_main_doc(self): - """Returns PyQuery object for the main season URL. - :returns: PyQuery object. - """ - url = (sportsref.nba.BASE_URL + - '/leagues/NBA_{}.html'.format(self.yr)) - return pq(sportsref.utils.get_html(url)) - - @sportsref.decorators.memoize - def get_sub_doc(self, subpage): - """Returns PyQuery object for a given subpage URL. - :subpage: The subpage of the season, e.g. 'per_game'. - :returns: PyQuery object. - """ - html = sportsref.utils.get_html(self._subpage_url(subpage)) - return pq(html) - - @sportsref.decorators.memoize - def get_team_ids(self): - """Returns a list of the team IDs for the given year. - :returns: List of team IDs. - """ - df = self.team_stats_per_game() - if not df.empty: - return df.index.tolist() - else: - print('ERROR: no teams found') - return [] - - @sportsref.decorators.memoize - def team_ids_to_names(self): - """Mapping from 3-letter team IDs to full team names. - :returns: Dictionary with team IDs as keys and full team strings as - values. - """ - doc = self.get_main_doc() - table = doc('table#team-stats-per_game') - flattened = sportsref.utils.parse_table(table, flatten=True) - unflattened = sportsref.utils.parse_table(table, flatten=False) - team_ids = flattened['team_id'] - team_names = unflattened['team_name'] - if len(team_names) != len(team_ids): - raise Exception("team names and team IDs don't align") - return dict(list(zip(team_ids, team_names))) - - @sportsref.decorators.memoize - def team_names_to_ids(self): - """Mapping from full team names to 3-letter team IDs. - :returns: Dictionary with tean names as keys and team IDs as values. - """ - d = self.team_ids_to_names() - return {v: k for k, v in list(d.items())} - - @sportsref.decorators.memoize - @sportsref.decorators.kind_rpb(include_type=True) - def schedule(self, kind='R'): - """Returns a list of BoxScore IDs for every game in the season. - Only needs to handle 'R' or 'P' options because decorator handles 'B'. - - :param kind: 'R' for regular season, 'P' for playoffs, 'B' for both. - Defaults to 'R'. - :returns: DataFrame of schedule information. - :rtype: pd.DataFrame - """ - kind = kind.upper()[0] - dfs = [] - - # get games from each month - for month in ('october', 'november', 'december', 'january', 'february', - 'march', 'april', 'may', 'june'): - try: - doc = self.get_sub_doc('games-{}'.format(month)) - except ValueError: - continue - table = doc('table#schedule') - df = sportsref.utils.parse_table(table) - dfs.append(df) - df = pd.concat(dfs).reset_index(drop=True) - - # figure out how many regular season games - try: - sportsref.utils.get_html('{}/playoffs/NBA_{}.html'.format( - sportsref.nba.BASE_URL, self.yr) - ) - is_past_season = True - except ValueError: - is_past_season = False - - if is_past_season: - team_per_game = self.team_stats_per_game() - n_reg_games = int(team_per_game.g.sum() / 2) - else: - n_reg_games = len(df) - - # subset appropriately based on `kind` - if kind == 'P': - return df.iloc[n_reg_games:] - else: - return df.iloc[:n_reg_games] - - def finals_winner(self): - """Returns the team ID for the winner of that year's NBA Finals. - :returns: 3-letter team ID for champ. - """ - raise NotImplementedError('nba.Season.finals_winner') - - def finals_loser(self): - """Returns the team ID for the loser of that year's NBA Finals. - :returns: 3-letter team ID for runner-up. - """ - raise NotImplementedError('nba.Season.finals_loser') - - @sportsref.decorators.memoize - def _get_team_stats_table(self, selector): - """Helper function for stats tables on season pages. Returns a - DataFrame.""" - doc = self.get_main_doc() - table = doc(selector) - df = sportsref.utils.parse_table(table) - df.set_index('team_id', inplace=True) - return df - - def team_stats_per_game(self): - """Returns a Pandas DataFrame of each team's basic per-game stats for - the season.""" - return self._get_team_stats_table('table#team-stats-per_game') - - def opp_stats_per_game(self): - """Returns a Pandas DataFrame of each team's opponent's basic per-game - stats for the season.""" - return self._get_team_stats_table('table#opponent-stats-per_game') - - def team_stats_totals(self): - """Returns a Pandas DataFrame of each team's basic stat totals for the - season.""" - return self._get_team_stats_table('table#team-stats-base') - - def opp_stats_totals(self): - """Returns a Pandas DataFrame of each team's opponent's basic stat - totals for the season.""" - return self._get_team_stats_table('table#opponent-stats-base') - - def misc_stats(self): - """Returns a Pandas DataFrame of miscellaneous stats about each team's - season.""" - return self._get_team_stats_table('table#misc_stats') - - def team_stats_shooting(self): - """Returns a Pandas DataFrame of each team's shooting stats for the - season.""" - return self._get_team_stats_table('table#team_shooting') - - def opp_stats_shooting(self): - """Returns a Pandas DataFrame of each team's opponent's shooting stats - for the season.""" - return self._get_team_stats_table('table#opponent_shooting') - - @sportsref.decorators.memoize - def _get_player_stats_table(self, identifier): - """Helper function for player season stats. - - :identifier: string identifying the type of stat, e.g. 'per_game'. - :returns: A DataFrame of stats. - """ - doc = self.get_sub_doc(identifier) - table = doc('table#{}_stats'.format(identifier)) - df = sportsref.utils.parse_table(table) - return df - - def player_stats_per_game(self): - """Returns a DataFrame of per-game player stats for a season.""" - return self._get_player_stats_table('per_game') - - def player_stats_totals(self): - """Returns a DataFrame of player stat totals for a season.""" - return self._get_player_stats_table('totals') - - def player_stats_per36(self): - """Returns a DataFrame of player per-36 min stats for a season.""" - return self._get_player_stats_table('per_minute') - - def player_stats_per100(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('per_poss') - - def player_stats_advanced(self): - """Returns a DataFrame of player per-100 poss stats for a season.""" - return self._get_player_stats_table('advanced') diff --git a/sportsref/cbb/teams.py b/sportsref/cbb/teams.py deleted file mode 100644 index 86d56f9..0000000 --- a/sportsref/cbb/teams.py +++ /dev/null @@ -1,75 +0,0 @@ -import future -import future.utils - -import numpy as np -from pyquery import PyQuery as pq - -import sportsref - - -class Team(future.utils.with_metaclass(sportsref.decorators.Cached, object)): - - def __init__(self, team_id): - self.team_id = team_id.upper() - - def __eq__(self, other): - return (self.team_id == other.team_id) - - def __hash__(self): - return hash(self.team_id) - - @sportsref.decorators.memoize - def team_year_url(self, yr_str): - return (sportsref.nba.BASE_URL + - '/teams/{}/{}.htm'.format(self.team_id, yr_str)) - - @sportsref.decorators.memoize - def get_main_doc(self): - relURL = '/teams/{}'.format(self.team_id) - teamURL = sportsref.nba.BASE_URL + relURL - mainDoc = pq(sportsref.utils.get_html(teamURL)) - return mainDoc - - @sportsref.decorators.memoize - def get_year_doc(self, yr_str): - return pq(sportsref.utils.get_html(self.team_year_url(yr_str))) - - @sportsref.decorators.memoize - def name(self): - """Returns the real name of the franchise given the team ID. - - Examples: - 'BOS' -> 'Boston Celtics' - 'NJN' -> 'Brooklyn Nets' - - :returns: A string corresponding to the team's full name. - """ - doc = self.get_main_doc() - name = doc('div#info h1[itemprop="name"]').text() - return name - - @sportsref.decorators.memoize - def roster(self, year): - """Returns the roster table for the given year. - - :year: The year for which we want the roster; defaults to current year. - :returns: A DataFrame containing roster information for that year. - """ - doc = self.get_year_doc(year) - table = doc('table#roster') - df = sportsref.utils.parse_table(table) - df['years_experience'] = df['years_experience'].replace('R', 0).astype(int) - return df - - # TODO: kind_rpb - @sportsref.decorators.memoize - def schedule(self, year): - """Gets schedule information for a team-season. - - :year: The year for which we want the schedule. - :returns: DataFrame of schedule information. - """ - doc = self.get_year_doc('{}_games'.format(year)) - table = doc('table#games') - df = sportsref.utils.parse_table(table) - return df From cc65ecfcf3a02068bfd3e1ce6c6ce0e7378bdb3f Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 13 Feb 2018 11:45:29 -0500 Subject: [PATCH 55/57] tiny fixes --- sportsref/euro/teams.py | 6 +++--- sportsref/utils.py | 1 + test_notebooks/euro/euro_player_test.ipynb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sportsref/euro/teams.py b/sportsref/euro/teams.py index bda732a..4822e31 100644 --- a/sportsref/euro/teams.py +++ b/sportsref/euro/teams.py @@ -85,9 +85,9 @@ def get_stats_table(self, table_id, year, level='B'): @sportsref.decorators.memoize @sportsref.decorators.kind_rpb(include_type=True) def schedule(self, year, kind='B'): - """Returns the teams schedule, with boxscore_ids for further investigation. - :returns: schedule Dataframe - """ + """Returns the teams schedule, with boxscore_ids for further investigation. + :returns: schedule Dataframe + """ doc = self.get_schedule_doc(year) for t in doc('table').items(): if self.team_id in t.attr('id'): diff --git a/sportsref/utils.py b/sportsref/utils.py index cb160df..20547c5 100644 --- a/sportsref/utils.py +++ b/sportsref/utils.py @@ -329,6 +329,7 @@ def rel_url_to_id(url): url.startswith(s) for s in ( '/play-index/', + '/euro/' ) ): return url diff --git a/test_notebooks/euro/euro_player_test.ipynb b/test_notebooks/euro/euro_player_test.ipynb index 9c7892c..bee655c 100644 --- a/test_notebooks/euro/euro_player_test.ipynb +++ b/test_notebooks/euro/euro_player_test.ipynb @@ -110,7 +110,7 @@ "# new method: to me, would be useful/necessary\n", "# because gamelogs are split by league and year\n", "\n", - "print(p.available_gamelogs())" + "print(player.available_gamelogs())" ] }, { From 2610f7c148bcdc2f88a2ef016cacb8fda3f43f1b Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 13 Feb 2018 11:50:44 -0500 Subject: [PATCH 56/57] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ac9d2f6..914fe46 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -# Develop Todo: +# sportsref +Scraping sports data from sports-reference.com and related sites -### DONE Figure out why teams/all_teams_opp_stats table isn't parsing -### comment teams -> merge to master -### check euro/players comments - -### euro/seasons +NOTE: Very much still a WIP. Feel free to use, just bear in mind that the API +is subject to change. Documentation is on the to-do list, once the API is a bit +more rigid. From 39525760ca67ce4643cb7829f0c4604837e050c0 Mon Sep 17 00:00:00 2001 From: Alex Beard Date: Tue, 13 Feb 2018 11:56:43 -0500 Subject: [PATCH 57/57] readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 914fe46..a1a07a8 100644 --- a/README.md +++ b/README.md @@ -4,5 +4,3 @@ Scraping sports data from sports-reference.com and related sites NOTE: Very much still a WIP. Feel free to use, just bear in mind that the API is subject to change. Documentation is on the to-do list, once the API is a bit more rigid. - -