***This article was originally published on April 30, 2019***
For this project, we wanted to analyze the NBA players who have won the Most Valuable Player award, or the MVP award. Generally, this award is given to the best basketball player for a particular season.
Media votes at the end of the regular season on who wins the award. We wanted to get a better idea of what criteria and factors play a role in what makes a player an MVP, along with what the voters consider to be the "most valuable."
Data Collection
For our data source, we chose Sports Reference. Specifically, we chose Basketball-Reference.com. They have all the statistics regarding the NBA and basketball, from team records, player stats, award winners, game results, and much more.They had a page about the history of NBA MVP winners, and it was the perfect source to pull from to gather data and analyze.
The page featured info such as player info, age, and voting numbers. It also showed accompanying stats such as points, rebounds, assists, blocks, steals, shooting percentage, and more.
We first had to crawl for the data. We used a similar crawler tool from a class lecture (INFO-I369 Performance Analytics class taught at Indiana University Bloomington), which also used Basketball-Reference.com.
There, we were able to download the HTML page, which will allow us to go through the table and parse the data. The crawler downloads from the Basketball-Reference URL, and downloads as an HTML page called "nba-mvp."
#Downloading page data and HTML
from urllib.request import Request, urlopen
#NBA MVP award winners
##download https://www.basketball-reference.com/awards/mvp.html
url = 'https://www.basketball-reference.com/awards/mvp.html'
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
html = urlopen(req).read()
##save file to disk
f = open('nba-mvp.html','w')
f.write(html.decode('utf-8'))
f.close()
Along with the crawler, we had to find a way to download the URLs of all the NBA player pages from the list of MVP winners. We wanted to do this to be able to use player data and info to compare statistics.
To do this, we needed to go through the table and download the URLs from the column featuring the players' names. The names are all accompanied by an URL to their individual profile page on the Basketball-Reference website.
To start off, we had to read from the HTML file we downloaded earlier via the crawler. We then created an empty list to store the URLs of the players. We then went through the HTML and found all elements with "td" for the table.
From there, the next piece of code in the for loop is an if statement that looks only for the players with "NBA" in the table, since the table also features "ABA" MVP winners (a different basketball league at the time that eventually merged with the NBA).
After this, we were able to get through the column of the players and add the elements to the list. After this, we noticed that there were duplicates in the table since there were players with multiple MVP awards. The next step was to remove the duplicates.
The code we used was similar to an example in a lecture of downloading URLs via structure of the URL and for-loop, which also used Basketball-Reference. However, the structure of player URLs made it a bit more difficult.
The structure involved a string for the player's name along with a separate number ID. With this, we had to "re.findall" for both formats and combine them into a dictionary. With this, we are able to match the ID with the player string to create the URL structure and download the player pages.
#Script to download pages of the NBA players and store into a folder
from urllib.request import Request, urlopen
import time
import random
import re
from bs4 import BeautifulSoup
#from file
filein = 'nba-mvp.html'
soup = BeautifulSoup(open(filein), 'lxml')
#empty list for urls
player_urls = []
#Searching through table
entries = soup.find_all('tr', attrs={'class' : ''})
for entry in entries:
#table extracting from contained td elements
columns = entry.find_all('td')
#Searching in NBA MVP winner table
if len (columns)>3 and columns[0].get_text() == 'NBA':
#Searching through column of player names contained with links
player = columns[1]
for p in player:
#add players to list
player_urls.append(p)
#Remove duplicates from list (some players won award more than once)
seen = set()
players_no_duplicate = []
for item in player_urls:
if item not in seen:
seen.add(item)
players_no_duplicate.append(item)
new_players = players_no_duplicate
str1 = ''.join(str(e) for e in new_players)
#HTML structure of player pages
mvp_players = re.findall('"/players/[a-z]/(.*?).html', str1)
mvp_players2 = re.findall('"/players/(.*?)/', str1)
#Combining lists into dictionary to make for loop work in order to write files
mvp_dict = dict(zip(mvp_players, mvp_players2))
#For loop saves HTML files of player's pages
for player, letter in mvp_dict.items():
#Rest between parsing
tmp = random.random()*5.0
print ('Sleep for ', tmp, ' seconds')
time.sleep(tmp)
#URL structure for players
url = 'https://www.basketball-reference.com/players/'+ str(letter) + '/' + str(player) +'.html'
print ('Download from :', url)
#download
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
html = urlopen(req).read()
fileout = 'NBA-MVPs/'+ (player) +'.html'
print ('Save to : ', fileout, '\n')
#save file to disk
f = open(fileout,'w')
f.write(html.decode('utf-8'))
f.close()
Sleep for 3.4936360349325963 seconds Download from : https://www.basketball-reference.com/players/a/abdulka01.html Save to : NBA-MVPs/abdulka01.html Sleep for 3.666410242661151 seconds Download from : https://www.basketball-reference.com/players/c/cousybo01.html Save to : NBA-MVPs/cousybo01.html Sleep for 1.3745451959709787 seconds Download from : https://www.basketball-reference.com/players/w/waltobi01.html Save to : NBA-MVPs/waltobi01.html Sleep for 3.995848551646914 seconds Download from : https://www.basketball-reference.com/players/e/ervinju01.html Save to : NBA-MVPs/ervinju01.html Sleep for 3.8237503092385996 seconds Download from : https://www.basketball-reference.com/players/r/reedwi01.html Save to : NBA-MVPs/reedwi01.html Sleep for 1.3029917173148626 seconds Download from : https://www.basketball-reference.com/players/n/nowitdi01.html Save to : NBA-MVPs/nowitdi01.html Sleep for 3.283549197513305 seconds Download from : https://www.basketball-reference.com/players/c/cowenda01.html Save to : NBA-MVPs/cowenda01.html Sleep for 0.7194799968133597 seconds Download from : https://www.basketball-reference.com/players/i/iversal01.html Save to : NBA-MVPs/iversal01.html Sleep for 1.953568381269653 seconds Download from : https://www.basketball-reference.com/players/r/rosede01.html Save to : NBA-MVPs/rosede01.html Sleep for 2.216694743687364 seconds Download from : https://www.basketball-reference.com/players/b/birdla01.html Save to : NBA-MVPs/birdla01.html Sleep for 0.2951086570759498 seconds Download from : https://www.basketball-reference.com/players/m/mcadobo01.html Save to : NBA-MVPs/mcadobo01.html Sleep for 2.0548438859024802 seconds Download from : https://www.basketball-reference.com/players/c/curryst01.html Save to : NBA-MVPs/curryst01.html Sleep for 1.5588188715655682 seconds Download from : https://www.basketball-reference.com/players/p/pettibo01.html Save to : NBA-MVPs/pettibo01.html Sleep for 4.47021686710008 seconds Download from : https://www.basketball-reference.com/players/n/nashst01.html Save to : NBA-MVPs/nashst01.html Sleep for 0.3204173311522224 seconds Download from : https://www.basketball-reference.com/players/d/duncati01.html Save to : NBA-MVPs/duncati01.html Sleep for 2.3266782946652045 seconds Download from : https://www.basketball-reference.com/players/u/unselwe01.html Save to : NBA-MVPs/unselwe01.html Sleep for 3.984902952381843 seconds Download from : https://www.basketball-reference.com/players/r/roberos01.html Save to : NBA-MVPs/roberos01.html Sleep for 0.4027238605708261 seconds Download from : https://www.basketball-reference.com/players/r/russebi01.html Save to : NBA-MVPs/russebi01.html Sleep for 2.9228123790731297 seconds Download from : https://www.basketball-reference.com/players/d/duranke01.html Save to : NBA-MVPs/duranke01.html Sleep for 4.130703470454606 seconds Download from : https://www.basketball-reference.com/players/j/johnsma02.html Save to : NBA-MVPs/johnsma02.html Sleep for 0.32157602146052067 seconds Download from : https://www.basketball-reference.com/players/m/malonmo01.html Save to : NBA-MVPs/malonmo01.html Sleep for 3.9674057026172194 seconds Download from : https://www.basketball-reference.com/players/o/olajuha01.html Save to : NBA-MVPs/olajuha01.html Sleep for 2.342974653582497 seconds Download from : https://www.basketball-reference.com/players/w/westbru01.html Save to : NBA-MVPs/westbru01.html Sleep for 0.11401640754318487 seconds Download from : https://www.basketball-reference.com/players/j/jamesle01.html Save to : NBA-MVPs/jamesle01.html Sleep for 2.3864208976883443 seconds Download from : https://www.basketball-reference.com/players/g/garneke01.html Save to : NBA-MVPs/garneke01.html Sleep for 1.4518620893393896 seconds Download from : https://www.basketball-reference.com/players/h/hardeja01.html Save to : NBA-MVPs/hardeja01.html Sleep for 2.665840647859949 seconds Download from : https://www.basketball-reference.com/players/m/malonka01.html Save to : NBA-MVPs/malonka01.html Sleep for 1.3516385494845196 seconds Download from : https://www.basketball-reference.com/players/b/barklch01.html Save to : NBA-MVPs/barklch01.html Sleep for 2.632243605961218 seconds Download from : https://www.basketball-reference.com/players/c/chambwi01.html Save to : NBA-MVPs/chambwi01.html Sleep for 1.3766649178931374 seconds Download from : https://www.basketball-reference.com/players/r/robinda01.html Save to : NBA-MVPs/robinda01.html Sleep for 2.5778407697494288 seconds Download from : https://www.basketball-reference.com/players/j/jordami01.html Save to : NBA-MVPs/jordami01.html Sleep for 2.2448373568042723 seconds Download from : https://www.basketball-reference.com/players/b/bryanko01.html Save to : NBA-MVPs/bryanko01.html Sleep for 3.6874784692124765 seconds Download from : https://www.basketball-reference.com/players/o/onealsh01.html Save to : NBA-MVPs/onealsh01.html
The next step was parsing through the data. We used a similar example from class in going through the table, along with its columns and rows.
Using the beginning of the code from the example right above, we were able to go through the table and parse data. Along with this, we were able to recreate the table to analyze and download the data of the MVP players' statistics.
#TASK A
#TABLE PARSING DATA FOR NBA MVP AWARD WINNERS
from bs4 import BeautifulSoup
#from file
filein = 'nba-mvp.html'
soup = BeautifulSoup(open(filein), 'lxml')
entries = soup.find_all('tr', attrs={'class' : ''})
for entry in entries:
#print entry
#table extracing from contained th and td elements
seasons = entry.find_all('th')
columns = entry.find_all('td')
if len (columns)>3 and columns[0].get_text() == 'NBA':
#Year MVP won
year = seasons[0].get_text()
#Team player was on
team = columns[4].get_text()
#NBA player's name
player = columns[1].get_text()
#Player age
age = columns[3].get_text()
#Games played
games = columns[5].get_text()
#Minutes per game
minutes = columns[6].get_text()
#Points per game
points = columns[7].get_text()
#Rebounds per game
rebounds = columns[8].get_text()
#assists per game
assists = columns[9].get_text()
#steals per game
steals = columns[10].get_text()
#blocks per game
blocks = columns[11].get_text()
#field goal percentage
field_goal = columns[12].get_text()
#3-point percentage
three_point = columns[13].get_text()
#Free throw percentage
free_throw = columns[14].get_text()
#win shares
win_shares = columns[15].get_text()
#win shares/48
ws48 = columns[16].get_text()
#table of winners and data
tt = ''+year+'|:|'+team+'|:|'+player+'|:|'+age+'|:|'+games+'|:|'+minutes+'|:|'+points+'|:|'+rebounds+'|:|'+assists+'|:|'+steals+'|:|'+blocks+'|:|'+field_goal+'|:|'+three_point+'|:|'+free_throw+'|:|'+win_shares+'|:|'+ws48
print (tt)
2017-18|:|HOU|:|James Harden|:|28|:|72|:|35.4|:|30.4|:|5.4|:|8.8|:|1.8|:|0.7|:|.449|:|.367|:|.858|:|15.4|:|.289
2016-17|:|OKC|:|Russell Westbrook|:|28|:|81|:|34.6|:|31.6|:|10.7|:|10.4|:|1.6|:|0.4|:|.425|:|.343|:|.845|:|13.1|:|.224
2015-16|:|GSW|:|Stephen Curry|:|27|:|79|:|34.2|:|30.1|:|5.4|:|6.7|:|2.1|:|0.2|:|.504|:|.454|:|.908|:|17.9|:|.318
2014-15|:|GSW|:|Stephen Curry|:|26|:|80|:|32.7|:|23.8|:|4.3|:|7.7|:|2.0|:|0.2|:|.487|:|.443|:|.914|:|15.7|:|.288
2013-14|:|OKC|:|Kevin Durant|:|25|:|81|:|38.5|:|32.0|:|7.4|:|5.5|:|1.3|:|0.7|:|.503|:|.391|:|.873|:|19.2|:|.295
2012-13|:|MIA|:|LeBron James|:|28|:|76|:|37.9|:|26.8|:|8.0|:|7.3|:|1.7|:|0.9|:|.565|:|.406|:|.753|:|19.3|:|.322
2011-12|:|MIA|:|LeBron James|:|27|:|62|:|37.5|:|27.1|:|7.9|:|6.2|:|1.9|:|0.8|:|.531|:|.362|:|.771|:|14.5|:|.298
2010-11|:|CHI|:|Derrick Rose|:|22|:|81|:|37.4|:|25.0|:|4.1|:|7.7|:|1.0|:|0.6|:|.445|:|.332|:|.858|:|13.1|:|.208
2009-10|:|CLE|:|LeBron James|:|25|:|76|:|39.0|:|29.7|:|7.3|:|8.6|:|1.6|:|1.0|:|.503|:|.333|:|.767|:|18.5|:|.299
2008-09|:|CLE|:|LeBron James|:|24|:|81|:|37.7|:|28.4|:|7.6|:|7.2|:|1.7|:|1.1|:|.489|:|.344|:|.780|:|20.3|:|.318
2007-08|:|LAL|:|Kobe Bryant|:|29|:|82|:|38.9|:|28.3|:|6.3|:|5.4|:|1.8|:|0.5|:|.459|:|.361|:|.840|:|13.8|:|.208
2006-07|:|DAL|:|Dirk Nowitzki|:|28|:|78|:|36.2|:|24.6|:|8.9|:|3.4|:|0.7|:|0.8|:|.502|:|.416|:|.904|:|16.3|:|.278
2005-06|:|PHO|:|Steve Nash|:|31|:|79|:|35.4|:|18.8|:|4.2|:|10.5|:|0.8|:|0.2|:|.512|:|.439|:|.921|:|12.4|:|.212
2004-05|:|PHO|:|Steve Nash|:|30|:|75|:|34.3|:|15.5|:|3.3|:|11.5|:|1.0|:|0.1|:|.502|:|.431|:|.887|:|10.9|:|.203
2003-04|:|MIN|:|Kevin Garnett|:|27|:|82|:|39.4|:|24.2|:|13.9|:|5.0|:|1.5|:|2.2|:|.499|:|.256|:|.791|:|18.3|:|.272
2002-03|:|SAS|:|Tim Duncan|:|26|:|81|:|39.3|:|23.3|:|12.9|:|3.9|:|0.7|:|2.9|:|.513|:|.273|:|.710|:|16.5|:|.248
2001-02|:|SAS|:|Tim Duncan|:|25|:|82|:|40.6|:|25.5|:|12.7|:|3.7|:|0.7|:|2.5|:|.508|:|.100|:|.799|:|17.8|:|.257
2000-01|:|PHI|:|Allen Iverson|:|25|:|71|:|42.0|:|31.1|:|3.8|:|4.6|:|2.5|:|0.3|:|.420|:|.320|:|.814|:|11.8|:|.190
1999-00|:|LAL|:|Shaquille O'Neal|:|27|:|79|:|40.0|:|29.7|:|13.6|:|3.8|:|0.5|:|3.0|:|.574|:|.000|:|.524|:|18.6|:|.283
1998-99|:|UTA|:|Karl Malone|:|35|:|49|:|37.4|:|23.8|:|9.4|:|4.1|:|1.3|:|0.6|:|.493|:|.000|:|.788|:|9.6|:|.252
1997-98|:|CHI|:|Michael Jordan|:|34|:|82|:|38.8|:|28.7|:|5.8|:|3.5|:|1.7|:|0.5|:|.465|:|.238|:|.784|:|15.8|:|.238
1996-97|:|UTA|:|Karl Malone|:|33|:|82|:|36.6|:|27.4|:|9.9|:|4.5|:|1.4|:|0.6|:|.550|:|.000|:|.755|:|16.7|:|.268
1995-96|:|CHI|:|Michael Jordan|:|32|:|82|:|37.7|:|30.4|:|6.6|:|4.3|:|2.2|:|0.5|:|.495|:|.427|:|.834|:|20.4|:|.317
1994-95|:|SAS|:|David Robinson|:|29|:|81|:|38.0|:|27.6|:|10.8|:|2.9|:|1.7|:|3.2|:|.530|:|.300|:|.774|:|17.5|:|.273
1993-94|:|HOU|:|Hakeem Olajuwon|:|31|:|80|:|41.0|:|27.3|:|11.9|:|3.6|:|1.6|:|3.7|:|.528|:|.421|:|.716|:|14.3|:|.210
1992-93|:|PHO|:|Charles Barkley|:|29|:|76|:|37.6|:|25.6|:|12.2|:|5.1|:|1.6|:|1.0|:|.520|:|.305|:|.765|:|14.4|:|.242
1991-92|:|CHI|:|Michael Jordan|:|28|:|80|:|38.8|:|30.1|:|6.4|:|6.1|:|2.3|:|0.9|:|.519|:|.270|:|.832|:|17.7|:|.274
1990-91|:|CHI|:|Michael Jordan|:|27|:|82|:|37.0|:|31.5|:|6.0|:|5.5|:|2.7|:|1.0|:|.539|:|.312|:|.851|:|20.3|:|.321
1989-90|:|LAL|:|Magic Johnson|:|30|:|79|:|37.2|:|22.3|:|6.6|:|11.5|:|1.7|:|0.4|:|.480|:|.384|:|.890|:|16.5|:|.270
1988-89|:|LAL|:|Magic Johnson|:|29|:|77|:|37.5|:|22.5|:|7.9|:|12.8|:|1.8|:|0.3|:|.509|:|.314|:|.911|:|16.1|:|.267
1987-88|:|CHI|:|Michael Jordan|:|24|:|82|:|40.4|:|35.0|:|5.5|:|5.9|:|3.2|:|1.6|:|.535|:|.132|:|.841|:|21.2|:|.308
1986-87|:|LAL|:|Magic Johnson|:|27|:|80|:|36.3|:|23.9|:|6.3|:|12.2|:|1.7|:|0.5|:|.522|:|.205|:|.848|:|15.9|:|.263
1985-86|:|BOS|:|Larry Bird|:|29|:|82|:|38.0|:|25.8|:|9.8|:|6.8|:|2.0|:|0.6|:|.496|:|.423|:|.896|:|15.8|:|.244
1984-85|:|BOS|:|Larry Bird|:|28|:|80|:|39.5|:|28.7|:|10.5|:|6.6|:|1.6|:|1.2|:|.522|:|.427|:|.882|:|15.7|:|.238
1983-84|:|BOS|:|Larry Bird|:|27|:|79|:|38.3|:|24.2|:|10.1|:|6.6|:|1.8|:|0.9|:|.492|:|.247|:|.888|:|13.6|:|.215
1982-83|:|PHI|:|Moses Malone|:|27|:|78|:|37.5|:|24.5|:|15.3|:|1.3|:|1.1|:|2.0|:|.501|:|.000|:|.761|:|15.1|:|.248
1981-82|:|HOU|:|Moses Malone|:|26|:|81|:|42.0|:|31.1|:|14.7|:|1.8|:|0.9|:|1.5|:|.519|:|.000|:|.762|:|15.4|:|.218
1980-81|:|PHI|:|Julius Erving|:|30|:|82|:|35.0|:|24.6|:|8.0|:|4.4|:|2.1|:|1.8|:|.521|:|.222|:|.787|:|13.8|:|.231
1979-80|:|LAL|:|Kareem Abdul-Jabbar|:|32|:|82|:|38.3|:|24.8|:|10.8|:|4.5|:|1.0|:|3.4|:|.604|:|.000|:|.765|:|14.8|:|.227
1978-79|:|HOU|:|Moses Malone|:|23|:|82|:|41.3|:|24.8|:|17.6|:|1.8|:|1.0|:|1.5|:|.540|:||:|.739|:|14.1|:|.200
1977-78|:|POR|:|Bill Walton|:|25|:|58|:|33.3|:|18.9|:|13.2|:|5.0|:|1.0|:|2.5|:|.522|:||:|.720|:|8.4|:|.209
1976-77|:|LAL|:|Kareem Abdul-Jabbar|:|29|:|82|:|36.8|:|26.2|:|13.3|:|3.9|:|1.2|:|3.2|:|.579|:||:|.701|:|17.8|:|.283
1975-76|:|LAL|:|Kareem Abdul-Jabbar|:|28|:|82|:|41.2|:|27.7|:|16.9|:|5.0|:|1.5|:|4.1|:|.529|:||:|.703|:|17.0|:|.242
1974-75|:|BUF|:|Bob McAdoo|:|23|:|82|:|43.2|:|34.5|:|14.1|:|2.2|:|1.1|:|2.1|:|.512|:||:|.805|:|17.8|:|.242
1973-74|:|MIL|:|Kareem Abdul-Jabbar|:|26|:|81|:|43.8|:|27.0|:|14.5|:|4.8|:|1.4|:|3.5|:|.539|:||:|.702|:|18.4|:|.250
1972-73|:|BOS|:|Dave Cowens|:|24|:|82|:|41.8|:|20.5|:|16.2|:|4.1|:||:||:|.452|:||:|.779|:|12.0|:|.168
1971-72|:|MIL|:|Kareem Abdul-Jabbar|:|24|:|81|:|44.2|:|34.8|:|16.6|:|4.6|:||:||:|.574|:||:|.689|:|25.4|:|.340
1970-71|:|MIL|:|Kareem Abdul-Jabbar|:|23|:|82|:|40.1|:|31.7|:|16.0|:|3.3|:||:||:|.577|:||:|.690|:|22.3|:|.326
1969-70|:|NYK|:|Willis Reed|:|27|:|81|:|38.1|:|21.7|:|13.9|:|2.0|:||:||:|.507|:||:|.756|:|14.6|:|.227
1968-69|:|BAL|:|Wes Unseld|:|22|:|82|:|36.2|:|13.8|:|18.2|:|2.6|:||:||:|.476|:||:|.605|:|10.8|:|.175
1967-68|:|PHI|:|Wilt Chamberlain|:|31|:|82|:|46.8|:|24.3|:|23.8|:|8.6|:||:||:|.595|:||:|.380|:|20.4|:|.255
1966-67|:|PHI|:|Wilt Chamberlain|:|30|:|81|:|45.5|:|24.1|:|24.2|:|7.8|:||:||:|.683|:||:|.441|:|21.9|:|.285
1965-66|:|PHI|:|Wilt Chamberlain|:|29|:|79|:|47.3|:|33.5|:|24.6|:|5.2|:||:||:|.540|:||:|.513|:|21.4|:|.275
1964-65|:|BOS|:|Bill Russell|:|30|:|78|:|44.4|:|14.1|:|24.1|:|5.3|:||:||:|.438|:||:|.573|:|16.9|:|.234
1963-64|:|CIN|:|Oscar Robertson|:|25|:|79|:|45.1|:|31.4|:|9.9|:|11.0|:||:||:|.483|:||:|.853|:|20.6|:|.278
1962-63|:|BOS|:|Bill Russell|:|28|:|78|:|44.9|:|16.8|:|23.6|:|4.5|:||:||:|.432|:||:|.555|:|13.5|:|.185
1961-62|:|BOS|:|Bill Russell|:|27|:|76|:|45.2|:|18.9|:|23.6|:|4.5|:||:||:|.457|:||:|.595|:|15.5|:|.217
1960-61|:|BOS|:|Bill Russell|:|26|:|78|:|44.3|:|16.9|:|23.9|:|3.4|:||:||:|.426|:||:|.550|:|13.0|:|.181
1959-60|:|PHW|:|Wilt Chamberlain|:|23|:|72|:|46.4|:|37.6|:|27.0|:|2.3|:||:||:|.461|:||:|.582|:|17.0|:|.245
1958-59|:|STL|:|Bob Pettit|:|26|:|72|:|39.9|:|29.2|:|16.4|:|3.1|:||:||:|.438|:||:|.759|:|14.8|:|.246
1957-58|:|BOS|:|Bill Russell|:|23|:|69|:|38.3|:|16.6|:|22.7|:|2.9|:||:||:|.442|:||:|.519|:|11.3|:|.206
1956-57|:|BOS|:|Bob Cousy|:|28|:|64|:|36.9|:|20.6|:|4.8|:|7.5|:||:||:|.378|:||:|.821|:|8.8|:|.178
1955-56|:|STL|:|Bob Pettit|:|23|:|72|:|38.8|:|25.7|:|16.2|:|2.6|:||:||:|.429|:||:|.736|:|13.8|:|.236
Data Analysis and Visualizations
After parsing and collecting data, we were now able to analyze and visualize it. We started off by creating two scatterplots to compare and analyze data about the MVP players.We wanted to see if any two factors correlate in regards to the players and their performance, and if it has impact on winning the award.
To create the first scatter plot, we had to use and import matplotlib. From there, we created a function that allowed us to read data from a file and return it. This is through data files after parsing through the data in the previous code.
After this, we were able to obtain numbers such as alpha, beta, and correlation coefficient. We were then able to input the variables into the code used from the lecture for the scatterplot to produce the visualizations for analysis.
#TASK B import matplotlib.pyplot as plt %matplotlib inline import random import numpy as np from scipy import stats
def read_data (filein): year = [] stat = [] world_record = 0.0 with open(filein) as f: for line in f: if not line.startswith("#"): if int(line.strip().split(' ')[0]) and int(line.strip().split(' ')[0]): data = line.strip() data_col = data.split(' ') year.append(int(data_col[0])) stat.append(float(data_col[1])) else: world_record = float(line.strip()[1:]) return year, stat
Scatter Plot 1: Player's Age vs Games Played
#Games played in by player that season filein = 'Data/nba_gp.dat' year_gp, stat_gp = read_data (filein) #Ages of NBA players during MVP season filein = 'Data/nba_age.dat' year_age, stat_age = read_data (filein)
#Games played print ('Results for Games Played:') slope_m, intercept_m, r_value_m, p_value_m, std_err_m = stats.linregress(year_gp, stat_gp) print ('alpha : ', intercept_m) print ('beta : ', slope_m) print ('correlation coefficient : ', r_value_m) #Age of player print ('Results for Player Ages:') slope_w, intercept_w, r_value_w, p_value_w, std_err_w = stats.linregress(year_age, stat_age) print ('alpha : ', intercept_w) print ('beta : ', slope_w) print ('correlation coefficient : ', r_value_w)
Results for Games Played: alpha : 43.869223630312334 beta : 0.017137096774193554 correlation coefficient : 0.05025295352158669 Results for Player Ages: alpha : -35.58696556579622 beta : 0.031634024577572965 correlation coefficient : 0.19713802712711728
This first scatter plot looks at the correlation between games played by the NBA players versus how old they are. Based on the scatterplot, the interpretation shows some of the MVP winners higher in age played fewer games.
However, there were some younger players who missed more or as many. Other factors that can affect the games played is how long the season is, as a couple of the NBA seasons had lockouts which led to shorter seasons and fewer games played.
From the interpretation, the correlation may not be strong enough to be a cause.
plt.figure(figsize=(10,5))
plt.rc('text', usetex=True)
plt.rc('font', size=24, **{'family':'DejaVu Sans','sans-serif':['Helvetica']})
plt.rcParams['xtick.major.pad'] = 8
plt.rcParams['ytick.major.pad'] = 8
#Games played
plt.plot(year_gp,stat_gp, marker='o', color ='blue', markersize=5, linewidth=0)
best_fit_x = np.arange(1950, (2050- 1950 / 10000.0))
best_fit_y = intercept_m + slope_m * best_fit_x
plt.plot(best_fit_x, best_fit_y, color ='blue', markersize=0, linewidth=3, linestyle='-', alpha = 0.5)
#Age
plt.plot(year_age,stat_age, marker='s', color ='red', markersize=5, linewidth=0)
best_fit_x = np.arange(1950, (2052- 1950 / 10000.0))
best_fit_y = intercept_w + slope_w * best_fit_x
plt.plot(best_fit_x, best_fit_y, color ='red', markersize=0, linewidth=3, linestyle='-', alpha = 0.5)
plt.ylabel('Age / Games Played')
plt.xlabel('year')
plt.show()
Scatter Plot 2: Points Per Game vs Field Goal Percentage
#Points per game by NBA player in MVP season filein = 'Data/nba_pts.dat' year_pts, stat_pts = read_data (filein) # Field goal percentage of NBA player during MVP season filein = 'Data/nba_fg.dat' year_fg, stat_fg = read_data (filein)
#Points print ('Results for Games Played:') slope_m, intercept_m, r_value_m, p_value_m, std_err_m = stats.linregress(year_pts, stat_pts) print ('alpha : ', intercept_m) print ('beta : ', slope_m) print ('correlation coefficient : ', r_value_m) #Field goals print ('Results for Player Ages:') slope_w, intercept_w, r_value_w, p_value_w, std_err_w = stats.linregress(year_fg, stat_fg) print ('alpha : ', intercept_w) print ('beta : ', slope_w) print ('correlation coefficient : ', r_value_w)
Results for Games Played: alpha : -101.50359383000512 beta : 0.06416090629800307 correlation coefficient : 0.22211254723148693 Results for Player Ages: alpha : 20.190929019457297 beta : 0.015192972350230389 correlation coefficient : 0.0538293563809513
This second scatter plot takes a look at the correlation between how many points a player averaged during his MVP season versus the field goal percentage they had that season.
The field goal percentage shows how accurate a player is as a scorer. Seeing how field goal percentage correlates with points per game can give us a better idea of how NBA players are picked as MVPs, as these stats play a role into them winning the award.
It also shows us if or how efficient a player in correlation to how many points he scores per game. One player could score many points per game and have a poor field goal percentage, and another vice versa.
The chart shows with the line that average MVP winner averages in the mid-to-high 20s for points per game while hovering around 50% field goal percentage. It can give us an idea of what averages it can take to win MVP in the future.
plt.figure(figsize=(10,5))
plt.rc('text', usetex=True)
plt.rc('font', size=24, **{'family':'DejaVu Sans','sans-serif':['Helvetica']})
plt.rcParams['xtick.major.pad'] = 8
plt.rcParams['ytick.major.pad'] = 8
#Points
plt.plot(year_pts,stat_pts, marker='o', color ='blue', markersize=5, linewidth=0)
best_fit_x = np.arange(1950, (2050- 1950 / 10000.0))
best_fit_y = intercept_m + slope_m * best_fit_x
plt.plot(best_fit_x, best_fit_y, color ='blue', markersize=0, linewidth=3, linestyle='-', alpha = 0.5)
#Field goal
plt.plot(year_fg,stat_fg, marker='s', color ='red', markersize=5, linewidth=0)
best_fit_x = np.arange(1950, (2052- 1950 / 10000.0))
best_fit_y = intercept_w + slope_w * best_fit_x
plt.plot(best_fit_x, best_fit_y, color ='red', markersize=0, linewidth=3, linestyle='-', alpha = 0.5)
#(Points per game / field goal percentage)
plt.ylabel('PPG / FG%')
plt.xlabel('year')
plt.show()
Distributions
For implementing this part, we utilized code from before in regards to the data files. This will be used to make it work with the code to create the distribution histograms.
Utilizing points and games played stats with the "stat_age" and "stat_gp" variables allows us to see distributions and inferences for the NBA MVP player stats.
Along with this, we also added a function that lets us measure the probability distribution. We also had code that allows us to produce these histograms and distribution visualizations.
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#####################################
##Measure probability distribution. computes also average
## value and standard deviation
#####
def measure_probability_distribution (outcomes):
average_value = 0.0
variance = 0.0
pdf = {}
norm = 0.0
##count number of observations
for x in outcomes:
if x not in pdf:
pdf[x] = 0.0
pdf[x] += 1.0
norm += 1.0
average_value += x
variance += x*x
average_value /= norm
variance /= norm
variance = variance - average_value * average_value
##normalize pdf
for x in pdf:
pdf[x] /= norm
return pdf, average_value, variance
#####################################
Distribution 1: NBA Players' Ages
Our intepretation of this is that most NBA players who have won the MVP award have done so around their age 27-28 season. With this, we can expect the star players around this age as the most likely to win the award.
The average age is around 27 years old. This makes sense as NBA players are believed to be in their prime around this age.
from scipy.stats import poisson
pdf, av, var = measure_probability_distribution (stat_age)
##visualize histogram
plt.figure(figsize=(10,10))
plt.rc('text', usetex=True)
plt.rc('font', size=24, **{'family':'DejaVu Sans','sans-serif':['Helvetica']})
plt.rcParams['xtick.major.pad'] = 8
plt.rcParams['ytick.major.pad'] = 8
title = '$\\langle x \\rangle = ' + '% .2f' % av + ' \\quad \\sigma^2 = ' + '% .2f' % var + '$'
plt.title(title, fontsize = 20)
plt.xlabel('NBA players ages')
plt.ylabel('probability distribution')
##construct two lists for visualization
x = []
Px = []
for q in pdf:
x.append(q)
Px.append(pdf[q])
plt.bar(x, Px, color = 'red', align='center', alpha=0.5)
plt.plot(x, poisson.pmf(x, av), linestyle='-', linewidth=0.0,color='k', label='poisson pmf')
plt.show()
Distribution 2: Games Played
Our interpretation of this distribution graph shows that players are expected to play the majority of the season if they want to be in contention for the NBA MVP award.There are some outliers (likely due to lockout seasons when the NBA had only 50 games played or 66 games played during the regular season), but the majority of the NBA players have played more than 70 games.
The average is around 78 games played. There are 82 in a season, in which the majority of the NBA MVP winners have played. With this, playing the majority of all of the season is an important factor in winning.
from scipy.stats import poisson
pdf, av, var = measure_probability_distribution (stat_gp)
##visualize histogram
plt.figure(figsize=(10,10))
plt.rc('text', usetex=True)
plt.rc('font', size=24, **{'family':'DejaVu Sans','sans-serif':['Helvetica']})
plt.rcParams['xtick.major.pad'] = 8
plt.rcParams['ytick.major.pad'] = 8
title = '$\\langle x \\rangle = ' + '% .2f' % av + ' \\quad \\sigma^2 = ' + '% .2f' % var + '$'
plt.title(title, fontsize = 20)
plt.xlabel('Games Played')
plt.ylabel('probability distribution')
##construct two lists for visualization
x = []
Px = []
for q in pdf:
x.append(q)
Px.append(pdf[q])
plt.bar(x, Px, color = 'red', align='center', alpha=0.5)
plt.plot(x, poisson.pmf(x, av), linestyle='-', linewidth=0.0,color='k', label='poisson pmf')
plt.show()
Conclusion
We can conclude from analysis and visualizations that there are factors that play a role in NBA players winning the MVP award, and what factors voters consider into picking who wins.Many of the players average over 20 points per game at around 50 percent shooting. Along with this, the players are healthy and durable in that they must play the majority of the regular season. The majority of the winners did not miss a single game.
Along with this, expect most players to be around 27 or 28 years old, or what is considered their "prime years," when they win the award.
Another factor that we can use for future research is connecting with how many games a player's team won when they won the award. We can find the distribution of this and find the average number of wins an MVP has won with their team.
We can also use more of the player stats we downloaded when parsing their URLs and pages. We could compare other stats such as weight, height, and more.
Overall, we can expect that future NBA MVP winners are players in their prime years averaging over 20 points a game at around 50 percent shooting, who also end up playing majority or all of the season's games.
In additon to this, it's likely the player's team had a significant number of victories as well. This criterion can help shape who wins this year's NBA MVP award, which likely comes down to Milwaukee Bucks' Giannis Antetokounmpo and Houston Rockets' James Harden.
UPDATE 2020
Giannis ended up winning the MVP award over Harden. Let's see how their stats compare and how it correlates with our results.
| Rk | Player | Season | Age | G | GS | MP | FG | FGA | FG% | 3P | 3PA | 3P% | 2P | 2PA | 2P% | eFG% | FT | FTA | FT% | ORB | DRB | TRB | AST | STL | BLK | TOV | PF | PTS |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | Giannis Antetokounmpo | 2018-19 | 24 | 72 | 72 | 32.8 | 10.0 | 17.3 | .578 | 0.7 | 2.8 | .256 | 9.3 | 14.5 | .641 | .599 | 6.9 | 9.5 | .729 | 2.2 | 10.3 | 12.5 | 5.9 | 1.3 | 1.5 | 3.7 | 3.2 | 27.7 |
| 2 | James Harden | 2018-19 | 29 | 78 | 78 | 36.8 | 10.8 | 24.5 | .442 | 4.8 | 13.2 | .368 | 6.0 | 11.3 | .528 | .541 | 9.7 | 11.0 | .879 | 0.8 | 5.8 | 6.6 | 7.5 | 2.0 | 0.7 | 5.0 | 3.1 | 36.1 |
Giannis shot nearly 58% from the field while averaging about 28 points per game, compared to Harden's 44% shooting on 36 points per game. Harden averaged many more points per game, but Giannis was way more efficient.
This falls in line with most of the MVP winners averaging over 20 points per game with 50% or better shooting, like Giannis. Harden did exceed the points part, but was below-average in shooting percentage compared to the MVP winners.
Harden, however, did beat out Giannis in games played. Harden fell right at the average, while Giannis was slightly below the average. What helped Giannis is that he averaged more rebounds, close to the assist mark, and was more efficient.
We'll see how these stats and trends compare for future NBA MVP award winners and voting.





