Skip to content
Open
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
125 changes: 120 additions & 5 deletions sportsref/nfl/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,15 @@ def college(self):
return college

@sportsref.decorators.memoize
def ncaaf_player_id(self):
doc = self.get_doc()
rawText = (doc('div#meta p').filter(lambda i, e:
'College' in e.text_content()))
cleanedText = sportsref.utils.flatten_links(rawText)
collegeid = re.search(r'\((.*?)\)', cleanedText).group(1)
return collegeid

@ sportsref.decorators.memoize
def high_school(self):
doc = self.get_doc()
rawText = (doc('div#meta p')
Expand Down Expand Up @@ -212,7 +221,8 @@ def passing(self, kind='R'):
:returns: Pandas DataFrame with passing stats.
"""
doc = self.get_doc()
table = doc('#passing') if kind == 'R' else doc('#passing_playoffs')
table = doc('table#passing') if kind == 'R' else \
doc('table#passing_playoffs')
df = sportsref.utils.parse_table(table)
return df

Expand All @@ -225,14 +235,119 @@ def rushing_and_receiving(self, kind='R'):
:returns: Pandas DataFrame with rushing/receiving stats.
"""
doc = self.get_doc()
table = (doc('#rushing_and_receiving') if kind == 'R'
else doc('#rushing_and_receiving_playoffs'))
table = (doc('table#rushing_and_receiving') if kind == 'R'
else doc('table#rushing_and_receiving_playoffs'))
if not table:
table = (doc('#receiving_and_rushing') if kind == 'R'
else doc('#receiving_and_rushing_playoffs'))
table = (doc('table#receiving_and_rushing') if kind == 'R'
else doc('table#receiving_and_rushing_playoffs'))
df = sportsref.utils.parse_table(table)
return df

@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def defense_and_fumbles(self, kind='R'):
"""Gets yearly defense/fumble stats for the player.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with defense/fumble stats.
"""
doc = self.get_doc()
table = (doc('table#defense') if kind == 'R'
else doc('table#defense_playoffs'))
df = sportsref.utils.parse_table(table)
return df

@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def kick_and_punt_returns(self, kind='R'):
"""Gets yearly kick/punt return stats for the player.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with kick/punt return stats.
"""
doc = self.get_doc()
table = (doc('table#returns') if kind == 'R'
else doc('table#returns_playoffs'))
df = sportsref.utils.parse_table(table)
return df

@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def games(self, kind='R'):
"""Gets yearly games stats for the player.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with games stats.
"""
doc = self.get_doc()
table = (doc('table#games_played') if kind == 'R'
else doc('table#games_played_playoffs'))
df = sportsref.utils.parse_table(table)
return df

@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def kicking_and_punting(self, kind='R'):
"""Gets yearly kicking/punting stats for the player.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with kicking/punting stats.
"""
doc = self.get_doc()
table = (doc('table#kicking') if kind == 'R'
else doc('table#kicking_playoffs'))
df = sportsref.utils.parse_table(table)
return df

@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def all_scoring(self, kind='R'):
"""Gets yearly all scoring stats for the player.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with all scoring stats.
"""
doc = self.get_doc()
table = (doc('table#scoring') if kind == 'R'
else doc('table#scoring_playoffs'))
df = sportsref.utils.parse_table(table)
return df


@sportsref.decorators.memoize
@sportsref.decorators.kind_rpb(include_type=True)
def all_annual_stats(self, kind='R'):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't actually tested this function, but it looks good to me.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll use this function a lot, so I'll thoroughly test it on pretty much every possible player once I get rolling.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. On my todo list for the overall project is to write an actual test suite but I probably won't until I finish my thesis. But until then I'm fine with you just opening new pull requests or whatever if there are bugs after it's merged in.

"""Gets yearly all annual stats for the player by grabbing
each individual dataset and then merging them for full years.

:kind: One of 'R', 'P', or 'B'. Case-insensitive; defaults to 'R'.
:returns: Pandas DataFrame with all annual stats.
"""
dfPassing = self.passing(kind)
dfPassing = dfPassing.ix[dfPassing["has_class_full_table"]]
dfRushRec = self.rushing_and_receiving(kind)
dfRushRec = dfRushRec.ix[dfRushRec["has_class_full_table"]]
dfDefense = self.defense_and_fumbles(kind)
dfDefense = dfDefense.ix[dfDefense["has_class_full_table"]]
dfReturns = self.kick_and_punt_returns(kind)
dfReturns = dfReturns.ix[dfReturns["has_class_full_table"]]
dfGames = self.games(kind)
dfGames = dfGames.ix[dfGames["has_class_full_table"]]
dfKicking = self.kicking_and_punting(kind)
dfKicking = dfKicking.ix[dfKicking["has_class_full_table"]]
dfScoring = self.all_scoring(kind)
dfScoring = dfScoring.ix[dfScoring["has_class_full_table"]]
# the mergeList declares the common fields to merge on
mergeList = ['year', 'age', 'team', 'pos', 'uniform_number', 'g', 'gs']
dfAll = dfPassing.merge(dfRushRec, 'outer', mergeList)
dfAll = dfAll.merge(dfDefense, 'outer', mergeList)
dfAll = dfAll.merge(dfReturns, 'outer', mergeList)
dfAll = dfAll.merge(dfGames, 'outer', mergeList)
dfAll = dfAll.merge(dfKicking, 'outer', mergeList)
dfAll = dfAll.merge(dfScoring, 'outer', mergeList)

return dfAll

def _plays(self, year, play_type):
"""Returns a DataFrame of plays for a given year for a given play type
(like rushing, receiving, or passing).
Expand Down
41 changes: 40 additions & 1 deletion sportsref/nfl/teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,45 @@ def team_stats(self, year):
df = sportsref.utils.parse_table(table)
return df.ix[df.player_id == 'Team Stats'].iloc[0]

@sportsref.decorators.memoize
def injuries(self, year):
""" This gets the injuries from pro-football-reference for each team

:param year: year to query
:return: the pfrid and injury status per week for the year
"""
# get doc and table for the injuries
doc = self.get_year_doc('{}_injuries'.format(str(year)))
table = doc('table#team_injuries')

# check if valid return
if not len(table):
return pd.DataFrame()
else:
# identify columns, rows, data, and make dataframe
columns = [c.text() for c in table('thead tr th').items()]
rows = list(table('tbody tr').items())
data = [[(td.attr('data-append-csv') if td.attr('class') == "left "
else (
td.attr('data-tip') if "dnp" not in td.attr('class')
else "dnp;" + td.attr('data-tip')))
for td in row.items('th,td')] for row in rows]
injuries_one_team = pd.DataFrame(data, columns=columns)
return injuries_one_team

@sportsref.decorators.memoize
def snap_count(self, year):
""" get snaps per team per year

:param year: year of query
:return: dataframe with pfrID, snap count (sum of just off and defense)
"""
# set link and table_name and then get the pyquery table
doc = self.get_year_doc('{}-snap-counts'.format(str(year)))
table = doc('table#snap_counts')
snap_counts = sportsref.utils.parse_table(table)
return snap_counts

@sportsref.decorators.memoize
def opp_stats(self, year):
"""Returns a Series (dict-like) of the team's opponent's stats from the
Expand All @@ -262,6 +301,6 @@ def passing(self, year):
@sportsref.decorators.memoize
def rushing_and_receiving(self, year):
doc = self.get_year_doc(year)
table = doc('#rushing_and_receiving')
table = doc('table#rushing_and_receiving')
df = sportsref.utils.parse_table(table)
return df