<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/using-r-to-study-tennis-players/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://msperlin.github.io/2017-02-13-R-and-Tennis-Players/"> R and Finance</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p> Looking at winning records of ATP top players and Brazilian tennists – </p>
<p>In the <a target="_blank" rel="nofollow" href="https://msperlin.github.io/2017-02-05-R-and-Tennis/">previous post about tennis</a>, we studied how changes in ball’s composition in hard and grass courts affected the game back in 2000. In this post, we will analyse a different dataset from the same repository, and look at the players winning records in ATP matches. We will again separate the result by the type of court.</p>
<h2>The data</h2>
<p>I’m again using the great repository of tennis data of <a target="_blank" rel="nofollow" href="https://github.com/JeffSackmann/">Jeff<br>
Sackmann</a>. In this case, however, I’m<br>
using the <a target="_blank" rel="nofollow" href="https://github.com/JeffSackmann/tennis_atp">ATP repository</a><br>
that contains ATP match data since 1968 until 2017. Again, I thank Jeff<br>
Sackmann for making this dataset publicly available.</p>
<p>First, let’s download and unzip the dataset. This is a large file with<br>
35MB and it takes some time.</p>
<div>
<pre><code>zip.file &lt;- 'TennisData_ATP.zip'

# download file
if (!file.exists(zip.file)){
  download.file('https://github.com/JeffSackmann/tennis_atp/archive/master.zip', destfile = zip.file)
  
}

# unzip it
dir.out &lt;- 'tennis_atp-master/'
if (!dir.exists(dir.out)) unzip(zip.file)
</code></pre>
</div>
<p>Lets have a look at the contents of the zip file.</p>
<div>
<pre><code>my.f &lt;- list.files(dir.out, pattern = '*.csv', full.names = T)
print(my.f)

##   [1] &quot;tennis_atp-master/atp_matches_1968.csv&quot;           
##   [2] &quot;tennis_atp-master/atp_matches_1969.csv&quot;           
##   [3] &quot;tennis_atp-master/atp_matches_1970.csv&quot;           
##   [4] &quot;tennis_atp-master/atp_matches_1971.csv&quot;           
##   [5] &quot;tennis_atp-master/atp_matches_1972.csv&quot;           
##   [6] &quot;tennis_atp-master/atp_matches_1973.csv&quot;           
##   [7] &quot;tennis_atp-master/atp_matches_1974.csv&quot;           
##   [8] &quot;tennis_atp-master/atp_matches_1975.csv&quot;           
##   [9] &quot;tennis_atp-master/atp_matches_1976.csv&quot;           
##  [10] &quot;tennis_atp-master/atp_matches_1977.csv&quot;           
##  [11] &quot;tennis_atp-master/atp_matches_1978.csv&quot;           
##  [12] &quot;tennis_atp-master/atp_matches_1979.csv&quot;           
##  [13] &quot;tennis_atp-master/atp_matches_1980.csv&quot;           
##  [14] &quot;tennis_atp-master/atp_matches_1981.csv&quot;           
##  [15] &quot;tennis_atp-master/atp_matches_1982.csv&quot;           
##  [16] &quot;tennis_atp-master/atp_matches_1983.csv&quot;           
##  [17] &quot;tennis_atp-master/atp_matches_1984.csv&quot;           
##  [18] &quot;tennis_atp-master/atp_matches_1985.csv&quot;           
##  [19] &quot;tennis_atp-master/atp_matches_1986.csv&quot;           
##  [20] &quot;tennis_atp-master/atp_matches_1987.csv&quot;           
##  [21] &quot;tennis_atp-master/atp_matches_1988.csv&quot;           
##  [22] &quot;tennis_atp-master/atp_matches_1989.csv&quot;           
##  [23] &quot;tennis_atp-master/atp_matches_1990.csv&quot;           
##  [24] &quot;tennis_atp-master/atp_matches_1991.csv&quot;           
##  [25] &quot;tennis_atp-master/atp_matches_1992.csv&quot;           
##  [26] &quot;tennis_atp-master/atp_matches_1993.csv&quot;           
##  [27] &quot;tennis_atp-master/atp_matches_1994.csv&quot;           
##  [28] &quot;tennis_atp-master/atp_matches_1995.csv&quot;           
##  [29] &quot;tennis_atp-master/atp_matches_1996.csv&quot;           
##  [30] &quot;tennis_atp-master/atp_matches_1997.csv&quot;           
##  [31] &quot;tennis_atp-master/atp_matches_1998.csv&quot;           
##  [32] &quot;tennis_atp-master/atp_matches_1999.csv&quot;           
##  [33] &quot;tennis_atp-master/atp_matches_2000.csv&quot;           
##  [34] &quot;tennis_atp-master/atp_matches_2001.csv&quot;           
##  [35] &quot;tennis_atp-master/atp_matches_2002.csv&quot;           
##  [36] &quot;tennis_atp-master/atp_matches_2003.csv&quot;           
##  [37] &quot;tennis_atp-master/atp_matches_2004.csv&quot;           
##  [38] &quot;tennis_atp-master/atp_matches_2005.csv&quot;           
##  [39] &quot;tennis_atp-master/atp_matches_2006.csv&quot;           
##  [40] &quot;tennis_atp-master/atp_matches_2007.csv&quot;           
##  [41] &quot;tennis_atp-master/atp_matches_2008.csv&quot;           
##  [42] &quot;tennis_atp-master/atp_matches_2009.csv&quot;           
##  [43] &quot;tennis_atp-master/atp_matches_2010.csv&quot;           
##  [44] &quot;tennis_atp-master/atp_matches_2011.csv&quot;           
##  [45] &quot;tennis_atp-master/atp_matches_2012.csv&quot;           
##  [46] &quot;tennis_atp-master/atp_matches_2013.csv&quot;           
##  [47] &quot;tennis_atp-master/atp_matches_2014.csv&quot;           
##  [48] &quot;tennis_atp-master/atp_matches_2015.csv&quot;           
##  [49] &quot;tennis_atp-master/atp_matches_2016.csv&quot;           
##  [50] &quot;tennis_atp-master/atp_matches_2017.csv&quot;           
##  [51] &quot;tennis_atp-master/atp_matches_futures_1991.csv&quot;   
##  [52] &quot;tennis_atp-master/atp_matches_futures_1992.csv&quot;   
##  [53] &quot;tennis_atp-master/atp_matches_futures_1993.csv&quot;   
##  [54] &quot;tennis_atp-master/atp_matches_futures_1994.csv&quot;   
##  [55] &quot;tennis_atp-master/atp_matches_futures_1995.csv&quot;   
##  [56] &quot;tennis_atp-master/atp_matches_futures_1996.csv&quot;   
##  [57] &quot;tennis_atp-master/atp_matches_futures_1997.csv&quot;   
##  [58] &quot;tennis_atp-master/atp_matches_futures_1998.csv&quot;   
##  [59] &quot;tennis_atp-master/atp_matches_futures_1999.csv&quot;   
##  [60] &quot;tennis_atp-master/atp_matches_futures_2000.csv&quot;   
##  [61] &quot;tennis_atp-master/atp_matches_futures_2001.csv&quot;   
##  [62] &quot;tennis_atp-master/atp_matches_futures_2002.csv&quot;   
##  [63] &quot;tennis_atp-master/atp_matches_futures_2003.csv&quot;   
##  [64] &quot;tennis_atp-master/atp_matches_futures_2004.csv&quot;   
##  [65] &quot;tennis_atp-master/atp_matches_futures_2005.csv&quot;   
##  [66] &quot;tennis_atp-master/atp_matches_futures_2006.csv&quot;   
##  [67] &quot;tennis_atp-master/atp_matches_futures_2007.csv&quot;   
##  [68] &quot;tennis_atp-master/atp_matches_futures_2008.csv&quot;   
##  [69] &quot;tennis_atp-master/atp_matches_futures_2009.csv&quot;   
##  [70] &quot;tennis_atp-master/atp_matches_futures_2010.csv&quot;   
##  [71] &quot;tennis_atp-master/atp_matches_futures_2011.csv&quot;   
##  [72] &quot;tennis_atp-master/atp_matches_futures_2012.csv&quot;   
##  [73] &quot;tennis_atp-master/atp_matches_futures_2013.csv&quot;   
##  [74] &quot;tennis_atp-master/atp_matches_futures_2014.csv&quot;   
##  [75] &quot;tennis_atp-master/atp_matches_futures_2015.csv&quot;   
##  [76] &quot;tennis_atp-master/atp_matches_futures_2016.csv&quot;   
##  [77] &quot;tennis_atp-master/atp_matches_futures_2017.csv&quot;   
##  [78] &quot;tennis_atp-master/atp_matches_qual_chall_1991.csv&quot;
##  [79] &quot;tennis_atp-master/atp_matches_qual_chall_1992.csv&quot;
##  [80] &quot;tennis_atp-master/atp_matches_qual_chall_1993.csv&quot;
##  [81] &quot;tennis_atp-master/atp_matches_qual_chall_1994.csv&quot;
##  [82] &quot;tennis_atp-master/atp_matches_qual_chall_1995.csv&quot;
##  [83] &quot;tennis_atp-master/atp_matches_qual_chall_1996.csv&quot;
##  [84] &quot;tennis_atp-master/atp_matches_qual_chall_1997.csv&quot;
##  [85] &quot;tennis_atp-master/atp_matches_qual_chall_1998.csv&quot;
##  [86] &quot;tennis_atp-master/atp_matches_qual_chall_1999.csv&quot;
##  [87] &quot;tennis_atp-master/atp_matches_qual_chall_2000.csv&quot;
##  [88] &quot;tennis_atp-master/atp_matches_qual_chall_2001.csv&quot;
##  [89] &quot;tennis_atp-master/atp_matches_qual_chall_2002.csv&quot;
##  [90] &quot;tennis_atp-master/atp_matches_qual_chall_2003.csv&quot;
##  [91] &quot;tennis_atp-master/atp_matches_qual_chall_2004.csv&quot;
##  [92] &quot;tennis_atp-master/atp_matches_qual_chall_2005.csv&quot;
##  [93] &quot;tennis_atp-master/atp_matches_qual_chall_2006.csv&quot;
##  [94] &quot;tennis_atp-master/atp_matches_qual_chall_2007.csv&quot;
##  [95] &quot;tennis_atp-master/atp_matches_qual_chall_2008.csv&quot;
##  [96] &quot;tennis_atp-master/atp_matches_qual_chall_2009.csv&quot;
##  [97] &quot;tennis_atp-master/atp_matches_qual_chall_2010.csv&quot;
##  [98] &quot;tennis_atp-master/atp_matches_qual_chall_2011.csv&quot;
##  [99] &quot;tennis_atp-master/atp_matches_qual_chall_2012.csv&quot;
## [100] &quot;tennis_atp-master/atp_matches_qual_chall_2013.csv&quot;
## [101] &quot;tennis_atp-master/atp_matches_qual_chall_2014.csv&quot;
## [102] &quot;tennis_atp-master/atp_matches_qual_chall_2015.csv&quot;
## [103] &quot;tennis_atp-master/atp_matches_qual_chall_2016.csv&quot;
## [104] &quot;tennis_atp-master/atp_matches_qual_chall_2017.csv&quot;
## [105] &quot;tennis_atp-master/atp_players.csv&quot;                
## [106] &quot;tennis_atp-master/atp_rankings_00s.csv&quot;           
## [107] &quot;tennis_atp-master/atp_rankings_10s.csv&quot;           
## [108] &quot;tennis_atp-master/atp_rankings_70s.csv&quot;           
## [109] &quot;tennis_atp-master/atp_rankings_80s.csv&quot;           
## [110] &quot;tennis_atp-master/atp_rankings_90s.csv&quot;           
## [111] &quot;tennis_atp-master/atp_rankings_current.csv&quot;
</code></pre>
</div>
<p>Again, same as with the other post, we see a lot of files. The names are<br>
quite suggesting and it is clear that not all files contains matches<br>
data. Let’s restrict the analysis just for the files with the string<br>
<code>atp_matches</code>. This includes main matches, qualifications and futures<br>
games.</p>
<div>
<pre><code>library(stringr)

# restrict just for main atp matches
my.f &lt;- my.f[str_detect(my.f, 'matches')]
my.f

##   [1] &quot;tennis_atp-master/atp_matches_1968.csv&quot;           
##   [2] &quot;tennis_atp-master/atp_matches_1969.csv&quot;           
##   [3] &quot;tennis_atp-master/atp_matches_1970.csv&quot;           
##   [4] &quot;tennis_atp-master/atp_matches_1971.csv&quot;           
##   [5] &quot;tennis_atp-master/atp_matches_1972.csv&quot;           
##   [6] &quot;tennis_atp-master/atp_matches_1973.csv&quot;           
##   [7] &quot;tennis_atp-master/atp_matches_1974.csv&quot;           
##   [8] &quot;tennis_atp-master/atp_matches_1975.csv&quot;           
##   [9] &quot;tennis_atp-master/atp_matches_1976.csv&quot;           
##  [10] &quot;tennis_atp-master/atp_matches_1977.csv&quot;           
##  [11] &quot;tennis_atp-master/atp_matches_1978.csv&quot;           
##  [12] &quot;tennis_atp-master/atp_matches_1979.csv&quot;           
##  [13] &quot;tennis_atp-master/atp_matches_1980.csv&quot;           
##  [14] &quot;tennis_atp-master/atp_matches_1981.csv&quot;           
##  [15] &quot;tennis_atp-master/atp_matches_1982.csv&quot;           
##  [16] &quot;tennis_atp-master/atp_matches_1983.csv&quot;           
##  [17] &quot;tennis_atp-master/atp_matches_1984.csv&quot;           
##  [18] &quot;tennis_atp-master/atp_matches_1985.csv&quot;           
##  [19] &quot;tennis_atp-master/atp_matches_1986.csv&quot;           
##  [20] &quot;tennis_atp-master/atp_matches_1987.csv&quot;           
##  [21] &quot;tennis_atp-master/atp_matches_1988.csv&quot;           
##  [22] &quot;tennis_atp-master/atp_matches_1989.csv&quot;           
##  [23] &quot;tennis_atp-master/atp_matches_1990.csv&quot;           
##  [24] &quot;tennis_atp-master/atp_matches_1991.csv&quot;           
##  [25] &quot;tennis_atp-master/atp_matches_1992.csv&quot;           
##  [26] &quot;tennis_atp-master/atp_matches_1993.csv&quot;           
##  [27] &quot;tennis_atp-master/atp_matches_1994.csv&quot;           
##  [28] &quot;tennis_atp-master/atp_matches_1995.csv&quot;           
##  [29] &quot;tennis_atp-master/atp_matches_1996.csv&quot;           
##  [30] &quot;tennis_atp-master/atp_matches_1997.csv&quot;           
##  [31] &quot;tennis_atp-master/atp_matches_1998.csv&quot;           
##  [32] &quot;tennis_atp-master/atp_matches_1999.csv&quot;           
##  [33] &quot;tennis_atp-master/atp_matches_2000.csv&quot;           
##  [34] &quot;tennis_atp-master/atp_matches_2001.csv&quot;           
##  [35] &quot;tennis_atp-master/atp_matches_2002.csv&quot;           
##  [36] &quot;tennis_atp-master/atp_matches_2003.csv&quot;           
##  [37] &quot;tennis_atp-master/atp_matches_2004.csv&quot;           
##  [38] &quot;tennis_atp-master/atp_matches_2005.csv&quot;           
##  [39] &quot;tennis_atp-master/atp_matches_2006.csv&quot;           
##  [40] &quot;tennis_atp-master/atp_matches_2007.csv&quot;           
##  [41] &quot;tennis_atp-master/atp_matches_2008.csv&quot;           
##  [42] &quot;tennis_atp-master/atp_matches_2009.csv&quot;           
##  [43] &quot;tennis_atp-master/atp_matches_2010.csv&quot;           
##  [44] &quot;tennis_atp-master/atp_matches_2011.csv&quot;           
##  [45] &quot;tennis_atp-master/atp_matches_2012.csv&quot;           
##  [46] &quot;tennis_atp-master/atp_matches_2013.csv&quot;           
##  [47] &quot;tennis_atp-master/atp_matches_2014.csv&quot;           
##  [48] &quot;tennis_atp-master/atp_matches_2015.csv&quot;           
##  [49] &quot;tennis_atp-master/atp_matches_2016.csv&quot;           
##  [50] &quot;tennis_atp-master/atp_matches_2017.csv&quot;           
##  [51] &quot;tennis_atp-master/atp_matches_futures_1991.csv&quot;   
##  [52] &quot;tennis_atp-master/atp_matches_futures_1992.csv&quot;   
##  [53] &quot;tennis_atp-master/atp_matches_futures_1993.csv&quot;   
##  [54] &quot;tennis_atp-master/atp_matches_futures_1994.csv&quot;   
##  [55] &quot;tennis_atp-master/atp_matches_futures_1995.csv&quot;   
##  [56] &quot;tennis_atp-master/atp_matches_futures_1996.csv&quot;   
##  [57] &quot;tennis_atp-master/atp_matches_futures_1997.csv&quot;   
##  [58] &quot;tennis_atp-master/atp_matches_futures_1998.csv&quot;   
##  [59] &quot;tennis_atp-master/atp_matches_futures_1999.csv&quot;   
##  [60] &quot;tennis_atp-master/atp_matches_futures_2000.csv&quot;   
##  [61] &quot;tennis_atp-master/atp_matches_futures_2001.csv&quot;   
##  [62] &quot;tennis_atp-master/atp_matches_futures_2002.csv&quot;   
##  [63] &quot;tennis_atp-master/atp_matches_futures_2003.csv&quot;   
##  [64] &quot;tennis_atp-master/atp_matches_futures_2004.csv&quot;   
##  [65] &quot;tennis_atp-master/atp_matches_futures_2005.csv&quot;   
##  [66] &quot;tennis_atp-master/atp_matches_futures_2006.csv&quot;   
##  [67] &quot;tennis_atp-master/atp_matches_futures_2007.csv&quot;   
##  [68] &quot;tennis_atp-master/atp_matches_futures_2008.csv&quot;   
##  [69] &quot;tennis_atp-master/atp_matches_futures_2009.csv&quot;   
##  [70] &quot;tennis_atp-master/atp_matches_futures_2010.csv&quot;   
##  [71] &quot;tennis_atp-master/atp_matches_futures_2011.csv&quot;   
##  [72] &quot;tennis_atp-master/atp_matches_futures_2012.csv&quot;   
##  [73] &quot;tennis_atp-master/atp_matches_futures_2013.csv&quot;   
##  [74] &quot;tennis_atp-master/atp_matches_futures_2014.csv&quot;   
##  [75] &quot;tennis_atp-master/atp_matches_futures_2015.csv&quot;   
##  [76] &quot;tennis_atp-master/atp_matches_futures_2016.csv&quot;   
##  [77] &quot;tennis_atp-master/atp_matches_futures_2017.csv&quot;   
##  [78] &quot;tennis_atp-master/atp_matches_qual_chall_1991.csv&quot;
##  [79] &quot;tennis_atp-master/atp_matches_qual_chall_1992.csv&quot;
##  [80] &quot;tennis_atp-master/atp_matches_qual_chall_1993.csv&quot;
##  [81] &quot;tennis_atp-master/atp_matches_qual_chall_1994.csv&quot;
##  [82] &quot;tennis_atp-master/atp_matches_qual_chall_1995.csv&quot;
##  [83] &quot;tennis_atp-master/atp_matches_qual_chall_1996.csv&quot;
##  [84] &quot;tennis_atp-master/atp_matches_qual_chall_1997.csv&quot;
##  [85] &quot;tennis_atp-master/atp_matches_qual_chall_1998.csv&quot;
##  [86] &quot;tennis_atp-master/atp_matches_qual_chall_1999.csv&quot;
##  [87] &quot;tennis_atp-master/atp_matches_qual_chall_2000.csv&quot;
##  [88] &quot;tennis_atp-master/atp_matches_qual_chall_2001.csv&quot;
##  [89] &quot;tennis_atp-master/atp_matches_qual_chall_2002.csv&quot;
##  [90] &quot;tennis_atp-master/atp_matches_qual_chall_2003.csv&quot;
##  [91] &quot;tennis_atp-master/atp_matches_qual_chall_2004.csv&quot;
##  [92] &quot;tennis_atp-master/atp_matches_qual_chall_2005.csv&quot;
##  [93] &quot;tennis_atp-master/atp_matches_qual_chall_2006.csv&quot;
##  [94] &quot;tennis_atp-master/atp_matches_qual_chall_2007.csv&quot;
##  [95] &quot;tennis_atp-master/atp_matches_qual_chall_2008.csv&quot;
##  [96] &quot;tennis_atp-master/atp_matches_qual_chall_2009.csv&quot;
##  [97] &quot;tennis_atp-master/atp_matches_qual_chall_2010.csv&quot;
##  [98] &quot;tennis_atp-master/atp_matches_qual_chall_2011.csv&quot;
##  [99] &quot;tennis_atp-master/atp_matches_qual_chall_2012.csv&quot;
## [100] &quot;tennis_atp-master/atp_matches_qual_chall_2013.csv&quot;
## [101] &quot;tennis_atp-master/atp_matches_qual_chall_2014.csv&quot;
## [102] &quot;tennis_atp-master/atp_matches_qual_chall_2015.csv&quot;
## [103] &quot;tennis_atp-master/atp_matches_qual_chall_2016.csv&quot;
## [104] &quot;tennis_atp-master/atp_matches_qual_chall_2017.csv&quot;
</code></pre>
</div>
<p>As you can see, I used string matching function <code>str_detect</code> from<br>
<code>stringr</code> to find and keep just the csv files with the string <em>matches</em><br>
in its name. Now, let’s load all files into a single dataframe.</p>
<div>
<pre><code>library(readr)
library(dplyr)

# set cols (missing some)
my.cols &lt;- cols(
  .default = col_integer(),
  tourney_id = col_character(),
  tourney_name = col_character(),
  surface = col_character(),
  tourney_level = col_character(),
  winner_entry = col_character(),
  winner_name = col_character(),
  winner_hand = col_character(),
  winner_ioc = col_character(),
  winner_age = col_double(),
  loser_entry = col_character(),
  loser_name = col_character(),
  loser_hand = col_character(),
  loser_ioc = col_character(),
  loser_age = col_double(),
  score = col_character(),
  round = col_character()
)

# load all files with lapply and do.call (some cols don't match in all files)
df.matches &lt;- do.call(bind_rows,lapply(my.f, read_csv, col_types = my.cols))

# create year column
df.matches$Date &lt;- as.Date(as.character(df.matches$tourney_date),'%Y%m%d')
df.matches$Year &lt;- format(df.matches$Date,'%Y')
</code></pre>
</div>
<p>Let’s see what the data offers.</p>
<div>
<pre><code>str(df.matches)

## Classes 'tbl_df', 'tbl' and 'data.frame':    667965 obs. of  51 variables:
##  $ tourney_id        : chr  &quot;1968-580&quot; &quot;1968-580&quot; &quot;1968-580&quot; &quot;1968-580&quot; ...
##  $ tourney_name      : chr  &quot;Australian Chps.&quot; &quot;Australian Chps.&quot; &quot;Australian Chps.&quot; &quot;Australian Chps.&quot; ...
##  $ surface           : chr  &quot;Grass&quot; &quot;Grass&quot; &quot;Grass&quot; &quot;Grass&quot; ...
##  $ draw_size         : int  64 64 64 64 64 64 64 64 64 64 ...
##  $ tourney_level     : chr  &quot;G&quot; &quot;G&quot; &quot;G&quot; &quot;G&quot; ...
##  $ tourney_date      : int  19680119 19680119 19680119 19680119 19680119 19680119 19680119 19680119 19680119 19680119 ...
##  $ match_num         : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ winner_id         : int  110023 109803 100257 100105 109966 107759 100101 100025 108519 109799 ...
##  $ winner_seed       : int  NA NA NA 5 NA NA 12 3 NA NA ...
##  $ winner_entry      : chr  NA NA NA NA ...
##  $ winner_name       : chr  &quot;Richard Coulthard&quot; &quot;John Brown&quot; &quot;Ross Case&quot; &quot;Allan Stone&quot; ...
##  $ winner_hand       : chr  &quot;R&quot; &quot;R&quot; &quot;R&quot; &quot;R&quot; ...
##  $ winner_ht         : int  NA NA NA NA NA NA NA 173 NA NA ...
##  $ winner_ioc        : chr  &quot;AUS&quot; &quot;AUS&quot; &quot;AUS&quot; &quot;AUS&quot; ...
##  $ winner_age        : num  NA 27.5 16.2 22.3 29.9 ...
##  $ winner_rank       : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ winner_rank_points: int  NA NA NA NA NA NA NA NA NA NA ...
##  $ loser_id          : int  107760 106964 110024 110025 110026 110027 110028 108430 110029 110030 ...
##  $ loser_seed        : int  NA NA 15 NA NA NA NA NA NA NA ...
##  $ loser_entry       : chr  NA NA NA NA ...
##  $ loser_name        : chr  &quot;Max Senior&quot; &quot;Ernie Mccabe&quot; &quot;Gondo Widjojo&quot; &quot;Robert Layton&quot; ...
##  $ loser_hand        : chr  &quot;R&quot; &quot;R&quot; &quot;R&quot; &quot;R&quot; ...
##  $ loser_ht          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ loser_ioc         : chr  &quot;AUS&quot; &quot;AUS&quot; &quot;INA&quot; &quot;AUS&quot; ...
##  $ loser_age         : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ loser_rank        : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ loser_rank_points : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ score             : chr  &quot;12-10 7-5 4-6 7-5&quot; &quot;6-3 6-2 6-4&quot; &quot;6-4 3-6 6-3 7-5&quot; &quot;6-4 6-2 6-1&quot; ...
##  $ best_of           : int  5 5 5 5 5 5 5 5 5 5 ...
##  $ round             : chr  &quot;R64&quot; &quot;R64&quot; &quot;R64&quot; &quot;R64&quot; ...
##  $ minutes           : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_ace             : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_df              : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_svpt            : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_1stIn           : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_1stWon          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_2ndWon          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_SvGms           : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_bpSaved         : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ w_bpFaced         : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_ace             : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_df              : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_svpt            : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_1stIn           : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_1stWon          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_2ndWon          : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_SvGms           : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_bpSaved         : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ l_bpFaced         : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ Date              : Date, format: &quot;1968-01-19&quot; &quot;1968-01-19&quot; ...
##  $ Year              : chr  &quot;1968&quot; &quot;1968&quot; &quot;1968&quot; &quot;1968&quot; ...
</code></pre>
</div>
<p>Again, lots of information. Looks like the games are separated by rows,<br>
where the columns have a lot of information about the matches. This<br>
dataset is not as detailed as the last one with point by point data, but<br>
still quite impressive.</p>
<h1>Looking at top players winning percentages</h1>
<p>For our first analysis, lets look at the winning percentages of the top<br>
10 players from the ATP rankings. For that, I will use package <code>rvest</code><br>
to scrape the information about the top ATP players from the <a target="_blank" rel="nofollow" href="http://www.atpworldtour.com/en/rankings/singles">ATP<br>
website</a>.</p>
<div>
<pre><code>library(rvest)

## Loading required package: xml2

## 
## Attaching package: 'rvest'

## The following object is masked from 'package:readr':
## 
##     guess_encoding

library(stringr)

n.players &lt;- 10

my.url &lt;- 'http://www.atpworldtour.com/en/rankings/singles'

atp.players &lt;- read_html(my.url) %>%
  html_nodes(&quot;.player-cell&quot;) %>%
  html_text() %>%
  str_replace_all('\\n','') %>%
  str_trim()

name.player &lt;- atp.players[1:n.players]
print(name.player)

##  [1] &quot;Andy Murray&quot;    &quot;Novak Djokovic&quot; &quot;Stan Wawrinka&quot;  &quot;Milos Raonic&quot;  
##  [5] &quot;Kei Nishikori&quot;  &quot;Rafael Nadal&quot;   &quot;Marin Cilic&quot;    &quot;Dominic Thiem&quot; 
##  [9] &quot;Roger Federer&quot;  &quot;Gael Monfils&quot;
</code></pre>
</div>
<p>As you can see, we have to usual suspects. Andy Murray is now leading in<br>
the first position, which was held previously by Djokovic for a long<br>
period of time. I really like to see Dominic Thiem in the top ten as he<br>
is the youngest with 23 year, a solid game, and lots of potential.<br>
Federer is the oldest of the list, with 35 years old, but the most<br>
talented. It is amazing how he can still stay competitive given the age<br>
difference.</p>
<p>Back to the R analysis, a problem with this approach of scraping the<br>
names from the ATP website is that they don’t necessarily match the<br>
names in the ATP files. As an example, the swiss player <em>Stan Wawrinka</em><br>
is named <em>Stanislas Wawrinka</em> in the csv files, while in the ATP website<br>
is <em>Stan Wawrinka</em>. This means that directly trying to match the names<br>
in <code>name.player</code> with the names in <code>df.matches</code> may not work. This is<br>
classic case of data from difference sources that don’t share the same<br>
unique identifiers.</p>
<p>I usually solve this problem using a lookup table built manually in a<br>
csv file, where I store the matching identifiers in the different<br>
datasets. If the number of unique cases is small, it is quite doable.<br>
For this analysis, however, we have 12325 players, which is definitely<br>
too much. Manually creating a lookup table would be very demanding.</p>
<p>The solution I often in this case is to make the computer look for the<br>
best <em>imperfect match</em> among the different identifiers (names). This is<br>
also known as calculating <strong>string distances</strong> – the number of require<br>
edits so that a string matches other, and can be accomplished in many<br>
different ways. In this example I’ll use function <code>amatch</code> from package<br>
<code>stringdist</code>, with the basic options.</p>
<div>
<pre><code>library(stringdist)

# get unique names from losers and winners
unique.players &lt;- unique(c(df.matches$winner_name, 
                           df.matches$loser_name ))

# find the index of the closest string for each name in name.player
idx &lt;- amatch(name.player, unique.players, maxDist = 5)
</code></pre>
</div>
<p>Lets look at the result:</p>
<div>
<pre><code>print(data.frame(name.from.web = name.player,
                 name.from.atp = unique.players[idx] ))

##     name.from.web      name.from.atp
## 1     Andy Murray        Andy Murray
## 2  Novak Djokovic     Novak Djokovic
## 3   Stan Wawrinka Stanislas Wawrinka
## 4    Milos Raonic       Milos Raonic
## 5   Kei Nishikori      Kei Nishikori
## 6    Rafael Nadal       Rafael Nadal
## 7     Marin Cilic        Marin Cilic
## 8   Dominic Thiem      Dominic Thiem
## 9   Roger Federer      Roger Federer
## 10   Gael Monfils       Gael Monfils
</code></pre>
</div>
<p>Beautiful! For our case of just 10 players, it worked perfectly. The<br>
name of Stan Wawrinka_ was matched correctly. Be aware, however, that<br>
this procedure of string matching is not guaranteed to work 100% of the<br>
cases. You could also set NA values using the options in <code>amatch</code> but it<br>
is still not guaranteed to work well. You should always manually check<br>
the result.</p>
<p>Going forward, let’s copy the players name from one to the other and use<br>
a loop and <code>dplyr</code> to calculate yearly winning percentages of each<br>
player, also separating by the type of surface. Using a loop here might<br>
look odd, but this was the simplest solution I’ve found as you cannot<br>
use <code>dplyr</code> directly. The dataframe <code>df.matches</code> is unique in the sense<br>
that it has two informations in each row, you have a win for someone and<br>
a loss to another player (see columns <code>winner_name</code> and <code>loser_name</code>).<br>
If I use <code>dplyr</code> directly, I would miss the games where two players in<br>
the list played each other. There is probably a way to adjust the<br>
dataframe, but I just find it easier to loop over the players.</p>
<div>
<pre><code># copy players name
name.player &lt;- unique.players[idx]

# create table with players
my.tab &lt;- tibble()
for (i.player in name.player) {
  
  temp &lt;- filter(df.matches, (winner_name==i.player)|(loser_name==i.player))
  temp$Name &lt;- i.player
  temp.tab &lt;- temp %>% 
    group_by(Name, Year,surface) %>%
    summarise(`Percentage of wins` = sum(winner_name == Name)/n(),
              `Number of matches` = n()) %>%
    filter(`Number of matches` > 0 ) %>%
    filter(surface %in% c('Hard','Clay'))
  
  my.tab &lt;- bind_rows(my.tab,
                      temp.tab)
    
}

# use atp ranking in names e.g. Andy Murray (1)
my.tab$Name &lt;- paste0(my.tab$Name, 
                      ' (', 
                      match(my.tab$Name, name.player),
                      ')' )

my.tab &lt;- my.tab[complete.cases(my.tab), ]
</code></pre>
</div>
<p>Lets plot it!</p>
<div>
<pre><code>library(ggplot2)

p &lt;- ggplot(my.tab, aes(x = as.numeric(Year), y = `Percentage of wins`, color=surface))
p &lt;- p + geom_point() + geom_smooth()
p &lt;- p + facet_grid(surface~Name)
p &lt;- p + ylim(c(0.25,1)) + xlim(c(2005,2016))
print(p)
</code></pre>
</div>
<p><img alt="" src="https://i1.wp.com/msperlin.github.io/img/2017-02-13-R-and-Tennis-Players_files/figure-markdown_strict/unnamed-chunk-10-1.png?w=456" data-recalc-dims="1"></p>
<p>We can see a few patterns. First, the winning consistency of top ten<br>
player is higher in hard courts. For example, look at Murray and<br>
Djokovic. It is easier for them to keep the same proportion of wins in<br>
hard courts than it is in clay. My best guess is that hard courts are<br>
more predictable and the ball is faster and bounces lower, making it<br>
easier for top players to hit winners and other point-finishing strokes<br>
such as drop shots. Be aware that this could also be due to the<br>
different number of matches in each court. We could test the difference<br>
of volatility statistically but I rather keep the analysis simple and<br>
visual.</p>
<p>Also, not surprisingly, Nadal, <a target="_blank" rel="nofollow" href="https://www.youtube.com/watch?v=7mknZrjakM8">the king of<br>
clay</a>, presents the highest<br>
winning percentage in clay, before 2012. His game strategy uses strength<br>
and heavy top spin balls that are difficult to counter. See<br>
<a target="_blank" rel="nofollow" href="https://www.quora.com/Why-is-Nadal-so-dominant-on-clay">here</a> for a<br>
more detailed analysis on why he is so dominant on clay. The bad side of<br>
his strategy and type of play is that it is based heavily on his<br>
muscular strength. As his age increases, it is difficult to maintain the<br>
same level. This explains the increased proportion of defeats after<br>
2012.</p>
<p>The effect of age is also perceived for Roger Federer. But, given that<br>
his style of play is not based just on strength, I think that he can<br>
still beat a lot of players. Just look at the his recent title win at<br>
the 2017 Australian open.</p>
<p>Now, look how Dojokovic is consistent in clay and hard courts. He is<br>
definitely the player with the best stats. I predict that, if he works<br>
for it, he will have no problem in taking the #1 spot once again from<br>
Murray.</p>
<h1>Looking at Brazilian tennis players</h1>
<p>In this section we will analyse the stats of Brazilian tennis players in<br>
ATP rankings. The following code can be easily executed for any country<br>
as the data is scraped from the ATP website. Just change the object<br>
<code>my.country</code> for your case.</p>
<div>
<pre><code>my.country &lt;- 'BRA'
n.players &lt;- 5
my.url &lt;- paste0('http://www.atpworldtour.com/en/rankings/singles?rankDate=2017-02-06&amp;rankRange=0-500&amp;countryCode=',my.country)

atp.players &lt;- read_html(my.url) %>%
  html_nodes(&quot;.player-cell&quot;) %>%
  html_text() %>%
  str_replace_all('\\n','') %>%
  str_trim()

name.player &lt;- atp.players[1:n.players]
name.player

## [1] &quot;Thiago Monteiro&quot;     &quot;Rogerio Dutra Silva&quot; &quot;Thomaz Bellucci&quot;    
## [4] &quot;Joao Souza&quot;          &quot;Andre Ghem&quot;
</code></pre>
</div>
<p>The top five Brazilian players in ATP are Thiago Monteiro, Rogerio Dutra<br>
Silva, Thomas Belluci, João Souza and Andre Ghem, in that order. We<br>
should be proud of all of them. I can only imagine the dedication and<br>
effort necessary to be a professional tennis player. You can see more<br>
details about each<br>
<a target="_blank" rel="nofollow" href="http://www.atpworldtour.com/en/rankings/singles?rankDate=2017-02-06&rankRange=1-5000&countryCode=BRA">here</a>.</p>
<p>At this point, it makes sense to create a function to analyse the<br>
dataframe, as we will use it again later.</p>
<div>
<pre><code>plot.winning.perc &lt;- function(name.player, 
                              df.matches, 
                              min.games.per.year = 0,
                              min.year = 2005,
                              max.year = 2016){
  require(stringdist)
  require(stringr)
  require(dplyr)
  require(ggplot2)
  
  # create year column
  df.matches$Date &lt;- as.Date(as.character(df.matches$tourney_date),'%Y%m%d')
  df.matches$Year &lt;- format(df.matches$Date,'%Y')
  
  # get unique names from losers and winners
  unique.players &lt;- unique(c(df.matches$winner_name, 
                             df.matches$loser_name ))
  
  # find the index of the closest string for each name in name.player
  idx &lt;- amatch(name.player, unique.players, maxDist = 5)
  #print(data.frame(name.from.web = name.player,
   #                name.from.atp = unique.players[idx] ))
  
  my.tab &lt;- tibble()
  for (i.player in name.player) {
    
    temp &lt;- filter(df.matches, (winner_name==i.player)|(loser_name==i.player))
    temp$Name &lt;- i.player
    temp.tab &lt;- temp %>% 
      group_by(Name, Year,surface) %>%
      summarise(`Percentage of wins` = sum(winner_name == Name)/n(),
                `Number of matches` = n()) %>%
      filter(`Number of matches` > min.games.per.year ) %>%
      filter(surface %in% c('Hard','Clay'))
    
    my.tab &lt;- bind_rows(my.tab,
                        temp.tab)
    
  }
  
  p &lt;- ggplot(my.tab, aes(x = as.numeric(Year), y = `Percentage of wins`, color=surface))
  p &lt;- p + geom_point() + geom_smooth()
  p &lt;- p + facet_grid(surface~Name)
  p &lt;- p + ylim(c(0.25,1)) + xlim(c(min.year,max.year))
  
  return(p)
  
}
</code></pre>
</div>
<p>Now, we use the previous function for the new names of players.</p>
<div>
<pre><code># plot winnign percentages
p &lt;- plot.winning.perc(name.player, df.matches)
print(p)
</code></pre>
</div>
<p><img alt="" src="https://i2.wp.com/msperlin.github.io/img/2017-02-13-R-and-Tennis-Players_files/figure-markdown_strict/brplayers-1.png?w=456" data-recalc-dims="1"></p>
<p>From this list, the youngest Brazilian player, and with most potential<br>
in my opinion, is Thiago Monteiro. He is 22 and has lots of time to<br>
improve his game. In 2016 he beated Tsonga in a great match <a target="_blank" rel="nofollow" href="http://www.atpworldtour.com/en/news/monteiro-upsets-tsonga-in-rio-de-janeiro">here in<br>
Brazil</a>.</p>
<h2>The records of Guga (Gustavo Kurten)</h2>
<p>For last, lets look at stats of the the best and most cherished singles<br>
player from Brazil, <a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Gustavo_Kuerten">Gustavo Kuerten –<br>
Guga</a>. Guga is<br>
internationally famous and reached #1 in the ATP ranking in 2000. A<br>
very charismatic player, with a fantastic backhand. It is not far<br>
fetched to say that Guga brought Tennis to Brazil, making it a more<br>
popular sport.</p>
<p>Guga had a hip injury back in 2001. He tried surgery, but it didn’t<br>
worked out and he wasn’t able to maintain the higher level of tennis<br>
that is necessary in the professional circuit. He retired in february of<br>
2008. His story is very inspiring, growing up in the state of Santa<br>
Catarina, in a time where tennis was not a popular sport in Brazil and<br>
funding opportunities were scarce. His <a target="_blank" rel="nofollow" href="https://www.amazon.com/Gustavo-Kuerten/e/B00VOUXHS2">biography (in<br>
portuguese)</a> is an<br>
excellent read.</p>
<p>Let’s have a look in the data.</p>
<div>
<pre><code>name.player &lt;- 'Gustavo Kuerten'

p &lt;- plot.winning.perc(name.player, df.matches, min.year = 1990)
print(p)
</code></pre>
</div>
<p><img alt="" src="https://i2.wp.com/msperlin.github.io/img/2017-02-13-R-and-Tennis-Players_files/figure-markdown_strict/guga-1.png?w=456" data-recalc-dims="1"></p>
<p>As expected, a winning journey until 2001, when losses start to<br>
accumulate.</p>
<h2>Conlusion</h2>
<p>The data repository of Jeff Sackmann is great. I really only scratched<br>
the surface with some simple graphical analysis. I think there is a lot<br>
of space for modeling as well, that is, creating a model that can<br>
predict the winning records of a player. I’m thinking about an<br>
econometric model using historical statistics of players such as past<br>
winning records, forehand/backhand winners, and so on. But I’m sure you<br>
can use other approaches as well.</p>
<p>From the computational side, it would be interesting to create a CRAN<br>
package to analyse this dataset. Just like in this post, all data could<br>
be fetched from the ATP website and the repository of Jeff. One could<br>
check the winning records of players with just a simple function call. I<br>
just checked and there is nothing like it in CRAN. A shiny app would<br>
also be interesting. I’ll keep it in mind for the future.</p>
<p>I hope you liked this post. Any comments or suggestions, please share in<br>
the comments section.</p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://msperlin.github.io/2017-02-13-R-and-Tennis-Players/"> R and Finance</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/lcw2ksRzDMM"></a></div>