Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Per 100 Possessions stats to NBA #476

Merged
merged 1 commit into from
Sep 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion sportsreference/nba/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,24 @@
'shooting_fouls_drawn': 'td[data-stat="drawn_shooting"]',
'and_ones': 'td[data-stat="and1s"]',
'shots_blocked': 'td[data-stat="fga_blkd"]',
'salary': 'td[data-stat="salary"]'
'salary': 'td[data-stat="salary"]',
'field_goals_per_poss': 'td[data-stat="fg_per_poss"]',
'field_goal_attempts_per_poss': 'td[data-stat="fga_per_poss"]',
'three_pointers_per_poss': 'td[data-stat="fg3_per_poss"]',
'three_point_attempts_per_poss': 'td[data-stat="fg3a_per_poss"]',
'two_pointers_per_poss': 'td[data-stat="fg2_per_poss"]',
'two_point_attempts_per_poss': 'td[data-stat="fg2a_per_poss"]',
'free_throws_per_poss': 'td[data-stat="ft_per_poss"]',
'free_throw_attempts_per_poss': 'td[data-stat="fta_per_poss"]',
'offensive_rebounds_per_poss': 'td[data-stat="orb_per_poss"]',
'defensive_rebounds_per_poss': 'td[data-stat="drb_per_poss"]',
'total_rebounds_per_poss': 'td[data-stat="trb_per_poss"]',
'assists_per_poss': 'td[data-stat="ast_per_poss"]',
'steals_per_poss': 'td[data-stat="stl_per_poss"]',
'blocks_per_poss': 'td[data-stat="blk_per_poss"]',
'turnovers_per_poss': 'td[data-stat="tov_per_poss"]',
'personal_fouls_per_poss': 'td[data-stat="pf_per_poss"]',
'points_per_poss': 'td[data-stat="pts_per_poss"]'
}

NATIONALITY = {
Expand Down
175 changes: 173 additions & 2 deletions sportsreference/nba/roster.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ def __init__(self, player_id):
self._shots_blocked = None
self._salary = None
self._contract = None
self._field_goals_per_poss = None
self._field_goal_attempts_per_poss = None
self._three_pointers_per_poss = None
self._three_point_attempts_per_poss = None
self._two_pointers_per_poss = None
self._two_point_attempts_per_poss = None
self._free_throws_per_poss = None
self._free_throw_attempts_per_poss = None
self._offensive_rebounds_per_poss = None
self._defensive_rebounds_per_poss = None
self._total_rebounds_per_poss = None
self._assists_per_poss = None
self._steals_per_poss = None
self._blocks_per_poss = None
self._turnovers_per_poss = None
self._personal_fouls_per_poss = None
self._points_per_poss = None

player_data = self._pull_player_data()
if not player_data:
Expand Down Expand Up @@ -300,8 +317,8 @@ def _combine_all_stats(self, player_info):
"""
all_stats_dict = {}

for table_id in ['totals', 'advanced', 'shooting', 'advanced_pbp',
'all_salaries']:
for table_id in ['totals', 'per_poss', 'advanced', 'shooting',
'advanced_pbp', 'all_salaries']:
table_items = utils._get_stats_table(player_info,
'table#%s' % table_id)
career_items = utils._get_stats_table(player_info,
Expand Down Expand Up @@ -561,19 +578,23 @@ class index value, the dictionary should be regenerated every time the
'and_ones': self.and_ones,
'assist_percentage': self.assist_percentage,
'assists': self.assists,
'assists_per_poss': self.assists_per_poss,
'block_percentage': self.block_percentage,
'blocking_fouls': self.blocking_fouls,
'blocks': self.blocks,
'blocks_per_poss': self.blocks_per_poss,
'box_plus_minus': self.box_plus_minus,
'center_percentage': self.center_percentage,
'defensive_box_plus_minus': self.defensive_box_plus_minus,
'defensive_rebound_percentage': self.defensive_rebound_percentage,
'defensive_rebounds': self.defensive_rebounds,
'defensive_rebounds_per_poss': self.defensive_rebounds_per_poss,
'defensive_win_shares': self.defensive_win_shares,
'dunks': self.dunks,
'effective_field_goal_percentage':
self.effective_field_goal_percentage,
'field_goal_attempts': self.field_goal_attempts,
'field_goal_attempts_per_poss': self.field_goal_attempts_per_poss,
'field_goal_perc_sixteen_foot_plus_two_pointers':
self.field_goal_perc_sixteen_foot_plus_two_pointers,
'field_goal_perc_ten_to_sixteen_feet':
Expand All @@ -584,10 +605,13 @@ class index value, the dictionary should be regenerated every time the
self.field_goal_perc_zero_to_three_feet,
'field_goal_percentage': self.field_goal_percentage,
'field_goals': self.field_goals,
'field_goals_per_poss': self.field_goals_per_poss,
'free_throw_attempt_rate': self.free_throw_attempt_rate,
'free_throw_attempts': self.free_throw_attempts,
'free_throw_attempts_per_poss': self.free_throw_attempts_per_poss,
'free_throw_percentage': self.free_throw_percentage,
'free_throws': self.free_throws,
'free_throws_per_poss': self.free_throws_per_poss,
'games_played': self.games_played,
'games_started': self.games_started,
'half_court_heaves': self.half_court_heaves,
Expand All @@ -601,6 +625,7 @@ class index value, the dictionary should be regenerated every time the
'offensive_fouls': self.offensive_fouls,
'offensive_rebound_percentage': self.offensive_rebound_percentage,
'offensive_rebounds': self.offensive_rebounds,
'offensive_rebounds_per_poss': self.offensive_rebounds_per_poss,
'offensive_win_shares': self.offensive_win_shares,
'on_court_plus_minus': self.on_court_plus_minus,
'other_turnovers': self.other_turnovers,
Expand All @@ -622,10 +647,12 @@ class index value, the dictionary should be regenerated every time the
'percentage_zero_to_three_footers':
self.percentage_zero_to_three_footers,
'personal_fouls': self.personal_fouls,
'personal_fouls_per_poss': self.personal_fouls_per_poss,
'player_efficiency_rating': self.player_efficiency_rating,
'player_id': self.player_id,
'point_guard_percentage': self.point_guard_percentage,
'points': self.points,
'points_per_poss': self.points_per_poss,
'points_generated_by_assists': self.points_generated_by_assists,
'position': self.position,
'power_forward_percentage': self.power_forward_percentage,
Expand All @@ -638,24 +665,32 @@ class index value, the dictionary should be regenerated every time the
'small_forward_percentage': self.small_forward_percentage,
'steal_percentage': self.steal_percentage,
'steals': self.steals,
'steals_per_poss': self.steals_per_poss,
'take_fouls': self.take_fouls,
'team_abbreviation': self.team_abbreviation,
'three_point_attempt_rate': self.three_point_attempt_rate,
'three_point_attempts': self.three_point_attempts,
'three_point_attempts_per_poss':
self.three_point_attempts_per_poss,
'three_point_percentage': self.three_point_percentage,
'three_point_shot_percentage_from_corner':
self.three_point_shot_percentage_from_corner,
'three_pointers': self.three_pointers,
'three_pointers_assisted_percentage':
self.three_pointers_assisted_percentage,
'three_pointers_per_poss': self.three_pointers_per_poss,
'total_rebound_percentage': self.total_rebound_percentage,
'total_rebounds': self.total_rebounds,
'total_rebounds_per_poss': self.total_rebounds_per_poss,
'true_shooting_percentage': self.true_shooting_percentage,
'turnover_percentage': self.turnover_percentage,
'turnovers': self.turnovers,
'turnovers_per_poss': self.turnovers_per_poss,
'two_point_attempts': self.two_point_attempts,
'two_point_attempts_per_poss': self.two_point_attempts_per_poss,
'two_point_percentage': self.two_point_percentage,
'two_pointers': self.two_pointers,
'two_pointers_per_poss': self.two_pointers_per_poss,
'two_pointers_assisted_percentage':
self.two_pointers_assisted_percentage,
'usage_percentage': self.usage_percentage,
Expand Down Expand Up @@ -756,6 +791,38 @@ def games_started(self):
"""
return self._games_started

@_float_property_decorator
def field_goals_per_poss(self):
"""
Returns a ``float`` of the total number of field goals the player
scored per 100 posessions.
"""
return self._field_goals_per_poss

@_float_property_decorator
def field_goal_attempts_per_poss(self):
"""
Returns a ``float`` of the total number of field goals the player
attempted per 100 posessions.
"""
return self._field_goal_attempts_per_poss

@_float_property_decorator
def three_pointers_per_poss(self):
"""
Returns a ``float`` of the total number of three point field goals the
player made per 100 posessions.
"""
return self._three_pointers_per_poss

@_float_property_decorator
def three_point_attempts_per_poss(self):
"""
Returns a ``float`` of the total number of three point field goals the
player attempted per 100 posessions.
"""
return self._three_point_attempts_per_poss

@_int_property_decorator
def two_pointers(self):
"""
Expand All @@ -772,6 +839,22 @@ def two_point_attempts(self):
"""
return self._two_point_attempts

@_float_property_decorator
def two_pointers_per_poss(self):
"""
Returns a ``float`` of the total number of two point field goals the
player made per 100 posessions.
"""
return self._two_pointers_per_poss

@_float_property_decorator
def two_point_attempts_per_poss(self):
"""
Returns a ``float`` of the total number of two point field goals the
player attempted per 100 posessions.
"""
return self._two_point_attempts_per_poss

@_float_property_decorator
def two_point_percentage(self):
"""
Expand All @@ -780,6 +863,94 @@ def two_point_percentage(self):
"""
return self._two_point_percentage

@_float_property_decorator
def free_throws_per_poss(self):
"""
Returns a ``float`` of the total number of free throws the player made
per 100 posessions.
"""
return self._free_throws_per_poss

@_float_property_decorator
def free_throw_attempts_per_poss(self):
"""
Returns a ``float`` of the total number of free throws the player
attempted per 100 posessions.
"""
return self._free_throw_attempts_per_poss

@_float_property_decorator
def offensive_rebounds_per_poss(self):
"""
Returns a ``float`` of the total number of offensive rebounds the
player grabbed per 100 posessions.
"""
return self._offensive_rebounds_per_poss

@_float_property_decorator
def defensive_rebounds_per_poss(self):
"""
Returns a ``float`` of the total number of defensive rebounds the
player grabbed per 100 posessions.
"""
return self._defensive_rebounds_per_poss

@_float_property_decorator
def total_rebounds_per_poss(self):
"""
Returns a ``float`` of the total number of offensive and defensive
rebounds the player grabbed per 100 posessions.
"""
return self._total_rebounds_per_poss

@_float_property_decorator
def assists_per_poss(self):
"""
Returns a ``float`` of the total number of assists the player tallied
per 100 posessions.
"""
return self._assists_per_poss

@_float_property_decorator
def steals_per_poss(self):
"""
Returns a ``float`` of the total number of steals the player tallied
per 100 posessions.
"""
return self._steals_per_poss

@_float_property_decorator
def blocks_per_poss(self):
"""
Returns a ``float`` of the total number of shots the player blocked
per 100 posessions.
"""
return self._blocks_per_poss

@_float_property_decorator
def turnovers_per_poss(self):
"""
Returns a ``float`` of the total number of times the player turned the
ball over per 100 posessions.
"""
return self._turnovers_per_poss

@_float_property_decorator
def personal_fouls_per_poss(self):
"""
Returns a ``float`` of the total number of personal fouls the player
committed per 100 posessions.
"""
return self._personal_fouls_per_poss

@_float_property_decorator
def points_per_poss(self):
"""
Returns a ``float`` of the total number of points the player scored
per 100 posessions.
"""
return self._points_per_poss

@_float_property_decorator
def player_efficiency_rating(self):
"""
Expand Down
38 changes: 36 additions & 2 deletions tests/integration/roster/test_nba_roster.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,24 @@ def setup_method(self, *args, **kwargs):
'2020-21': '$40,824,000',
'2021-22': '$43,848,000',
'2022-23': '$46,872,000'
}
},
'field_goals_per_poss': 10.0,
'field_goal_attempts_per_poss': 22.5,
'three_pointers_per_poss': 3.5,
'three_point_attempts_per_poss': 9.7,
'two_pointers_per_poss': 6.5,
'two_point_attempts_per_poss': 12.8,
'free_throws_per_poss': 10.4,
'free_throw_attempts_per_poss': 12.2,
'offensive_rebounds_per_poss': 1.1,
'defensive_rebounds_per_poss': 6.4,
'total_rebounds_per_poss': 7.5,
'assists_per_poss': 8.9,
'steals_per_poss': 2.2,
'blocks_per_poss': 0.7,
'turnovers_per_poss': 5.1,
'personal_fouls_per_poss': 3.7,
'points_per_poss': 33.9
}

self.results_2018 = {
Expand Down Expand Up @@ -259,7 +276,24 @@ def setup_method(self, *args, **kwargs):
'2020-21': '$40,824,000',
'2021-22': '$43,848,000',
'2022-23': '$46,872,000'
}
},
'field_goals_per_poss': 12.6,
'field_goal_attempts_per_poss': 27.9,
'three_pointers_per_poss': 5.1,
'three_point_attempts_per_poss': 13.9,
'two_pointers_per_poss': 7.4,
'two_point_attempts_per_poss': 14.0,
'free_throws_per_poss': 12.0,
'free_throw_attempts_per_poss': 14.0,
'offensive_rebounds_per_poss': 0.8,
'defensive_rebounds_per_poss': 6.7,
'total_rebounds_per_poss': 7.5,
'assists_per_poss': 12.2,
'steals_per_poss': 2.4,
'blocks_per_poss': 1.0,
'turnovers_per_poss': 6.1,
'personal_fouls_per_poss': 3.3,
'points_per_poss': 42.3
}

self.player = Player('hardeja01')
Expand Down