Showing posts with label other sports. Show all posts
Showing posts with label other sports. Show all posts

Tuesday, February 12, 2013

Baseball effect on hockey

In case you missed it, there is a website named Open Source Sports which contains databases for various sports, including the Lahman's for baseball.

Since in this blog, other than baseball I have dealt with basketball, soccer and football, it's time to do a short post on hockey. (The fact that the Hockey DB is one of the currently available at OSS helps too.)

This post is based on a single query on the Master table, the one containing players' bio info.
And reports something that I believe is widely known—so it's just a warm-up on the hockey database.

Percentage of left-shooting skaters by country

Slovakia       80
Sweden         78
Finland        76
Russia         75
Czech Republic 68
Canada         63
USA            55

The above numbers are for countries with at least 40 skaters in the database.

So, while for the Europeans the percentage of righty shooters is slightly above the population of lefthanded people (which should be in the order of 15%), the North-Americans lean way more on the right.

One likely explanation is Americans grow up playing baseball where the righthanded batter position is on the same side of the right-shooting hockey player. USA being more extreme than Canada would support this.

An American friend of mine who coached Team Sweden (baseball) said everyone seemed to bat lefthanded over there—which would support the case the other way around.

Wednesday, January 16, 2013

Icing the kicker?

What do I do when there's no baseball around?
Sometimes I do like Rogers Hornsby and just stare out of the window, waiting for Spring. Other times I watch hockey (KHL so far this year) or even football.

Last weekend I happened to watch the Seahawks @ Falcons game and couldn't help but noticing the timeout called by Seattle's head coach just before Atlanta kicked the decisive field goal.

After I understood that it was done just to disrupt the kicker's concentration (I'm not a football expert,) I decided I could have a statistical look at the issue (as stats is something I know better.)

The data

I found the following sources for play-by-play NFL data, both going back to 2002:
  • http://www.advancednflstats.com/2010/04/play-by-play-data.html
  • http://www.armchairanalysis.com/nfl-play-by-play-data.php

but neither had explicit information on when timeouts were called.
However, the play-by-play at the latter link is somewhat parsed and more ready to use, so I went with that.

Preparation

In order to identify when a timeout was called by the defensive team before a field goal, I looked at the remaining timeouts on the field goal plays and the remaining timeouts on plays immediately preceding them. When there was a difference, I classified the action as an "icing the kicker". Note that in some instances, the difference in timeouts left might have been due to a lost challenge on the previous play.

I wanted to use the stadium as one of the predictors of field goal success, but the data I used had them named in many different ways (with typos included,) thus I decided to use the home-team/season combination instead of it. Note that this will lead to considering the games played at Wembley no differently from those played at home by the Dolphins, the Saints, the Buccos or the 49ers.

Variables tested

I threw the following variables into my model (for those interested a multilevel multivariable logistic regression.)
  • the identity of the kicker;
  • distance (modeled linearly: it's a lazy choice, but not completely off the charts);
  • wind speed (no direction, as I would have needed to know the orientation of the field);
  • temperature;
  • being at home (for the kicker);
  • the "icing the kicker" dummy variable.


Results

Here's what I got. 
  • A 13% success reduction every 5 added yards of distance.
  • A 3% success reduction every additional 5mph of wind.
  • Around 1% success increase every 5 degrees (F) of temperature.
  • No effect for being at home
All the above seem too make sense. Also here are the best and worst kickers according to the model.

Best:
  1. Stover, Matt
  2. Gould, Robbie
  3. Kasay, John
  4. Akers, David
  5. Graham, Shayne
Worst:
  1. Peterson, Todd
  2. Hall, John
  3. Christie, Steve
  4. Gramatica, Martin
  5. Tynes, Lawrence
An here I need the help of knowledgeable NFL fans, to know whether the two lists pass the sniff test (though, for what I know, the first name seems OK out there.)

 The "icing"

Finally, what about the "icing the kicker"?
Though the point estimate would hint to a possible effect (-3%,) the variability is a bit large (from -8% to +1%.)

For now I would dismiss it having any influence on the outcome, but some further analysis could be in order for looking at the effect on particular kickers.

But, hey, the baseball season is approaching, so maybe someone else should look at this...

Tuesday, September 25, 2012

More on parsing data in R

Ask and you shall receive.

I pointed to the great guys at MCFC Analytics and Opta that having the table they provided in the appendix as Excel files (or whatever manageable format) would be a great time saver.
And they promptly provided me with what I asked for.

I'm not sure about the policy about putting that Excel file here, thus I won't do that.
However I'm pretty sure you can obtain it from them.

Below, an updated version of my code.

A few notes.

  1. I converted the .xlsx file Opta sent me to an .xls file, because I had some problem with the XLSX R package.
  2. The code can be run without the Excel file: I noted the code you should skip in that case.
  3. The code now parses some match info, like the teams, the players (as suggested in a comment), the scoring order. It does not grab everything in the F7 dataset, but it should be easily modifiable (or just ask in the comments).
  4. I wrote some code to add info to the events data set, like what team is involved and the score at that moment. Due to my familiarity with US sport it's away first... I know in soc... ahem... football should be the other way around.
Enjoy!

library(XML)
library(plyr)
library(reshape)
library(gdata)
 
f7 <- "c:/download/mcfc/Bolton_ManCityF7.xml" #file path & name (f7)
f24 <- "c:/download/mcfc/Bolton_ManCityF24.xml" #(f24)
#in case you have event and qualifier descriptions in xls file... (otherwhise comment the following 2 lines)
evNames <- read.xls("c:/download/mcfc/Event Definitions - Excel file.xls", sheet=1, as.is=T)
quNames <- read.xls("c:/download/mcfc/Event Definitions - Excel file.xls", sheet=2, as.is=T)
 
#utility function
grabAll <- function(XML.parsed, field){
  parse.field <- xpathSApply(XML.parsed, paste("//", field, "[@*]", sep=""))
  results <- t(sapply(parse.field, function(x) xmlAttrs(x)))
  if(typeof(results)=="list"){
    do.call(rbind.fill, lapply(lapply(results, t), data.frame, stringsAsFactors=F))
  } else {
    as.data.frame(results, stringsAsFactors=F)
  }
}
 
#team parsing
gameParse <- xmlInternalTreeParse(f7)
teamParse <- xpathSApply(gameParse, "//TeamData")
teamParse2 <- xpathSApply(gameParse, "//Team/Name")
 
teamInfo <- data.frame(
  team_id = sapply(teamParse, function(x) xmlGetAttr(node=x, "TeamRef"))
  , team_side = sapply(teamParse, function(x) xmlGetAttr(node=x, "Side"))
  , team_name = sapply(teamParse2, function(x) xmlValue(x))
  , stringsAsFactors=F
)
 
#players parsing
playerParse <- xpathSApply(gameParse, "//Team/Player")
lineupParse <- xpathSApply(gameParse, "//Team")
 
NPlayers <- sapply(lineupParse, function(x) sum(names(xmlChildren(x)) == "Player"))
 
playerInfo <- data.frame(
  player_id = sapply(playerParse, function(x) xmlGetAttr(node=x, "uID"))
  , team_id = c(rep(teamInfo$team_id[1], NPlayers[1]), rep(teamInfo$team_id[2], NPlayers[2]))
  , position = sapply(playerParse, function(x) xmlGetAttr(node=x, "Position"))
  , first_name = sapply(playerParse, function(x) xmlValue(xmlChildren(xmlChildren(x)$PersonName)$First))
  , last_name = sapply(playerParse, function(x) xmlValue(xmlChildren(xmlChildren(x)$PersonName)$Last))
)
 
#scoring order
goalInfo <- grabAll(teamParse[[1]], "Goal")
 
goalInfo$TimeStamp <- as.POSIXct(goalInfo$TimeStamp, format="%Y%m%dT%H%M%S")
 
scoringOrderInfo <- goalInfo[order(goalInfo$TimeStamp), c("TimeStamp", "uID")]
scoringOrderInfo$team_id <- substr(gsub("g", "t", scoringOrderInfo$uID), 1, 3)
scoringOrderInfo <- merge(scoringOrderInfo, teamInfo)
scoringOrderInfo$Away <- 0
scoringOrderInfo$Home <- 0
for(i in 1: dim(scoringOrderInfo)[1]){
  dt <- subset(scoringOrderInfo, TimeStamp <= scoringOrderInfo$TimeStamp[i])
  scoringOrderInfo[i,c("Away", "Home")] <- table(dt$team_side)
}
scoringOrderInfo$Score <- paste(scoringOrderInfo$Away, scoringOrderInfo$Home, sep="-")
scoringOrderInfo <- scoringOrderInfo[order(scoringOrderInfo$TimeStamp),]
 
 
#Play-by-Play Parsing
pbpParse <- xmlInternalTreeParse(f24)
eventInfo <- grabAll(pbpParse, "Event")
eventParse <- xpathSApply(pbpParse, "//Event")
NInfo <- sapply(eventParse, function(x) sum(names(xmlChildren(x)) == "Q"))
QInfo <- grabAll(pbpParse, "Q")
EventsExpanded <- as.data.frame(lapply(eventInfo[,1:2], function(x) rep(x, NInfo)), stringsAsFactors=F)
QInfo <- cbind(EventsExpanded, QInfo)
names(QInfo)[c(1,3)] <- c("Eid", "Qid")
QInfo$value <- ifelse(is.na(QInfo$value), -1, QInfo$value)
Qual <- cast(QInfo, Eid ~ qualifier_id)
 
#comment the following loop if you have commented the xls files loading at the beginning
for(i in names(Qual)[-1]){
  txt <- quNames[which(quNames$id==as.integer(i)), "name"]
  txt <- gsub('[[:space:]]+$', '', txt)
  lbl <- tolower(gsub("-", "_", gsub(" ", "_", txt, fixed=T), fixed=T))
  names(Qual)[which(names(Qual)==i)] <- lbl
}
 
#final data set
events <- merge(eventInfo, Qual, by.x="id", by.y="Eid", all.x=T, suffixes=c("", "Q"))
 
#adjustment of variables
events$TimeStamp <- as.POSIXct(events$timestamp, format="%Y-%m-%dT%H:%M:%S")
events$x <- as.double(events$x)
events$y <- as.double(events$y)
events$Score <- cut(events$TimeStamp, c(min(events$TimeStamp), scoringOrderInfo$TimeStamp, max(events$TimeStamp)+1), c("0-0", scoringOrderInfo$Score))
events$team_id <- paste("t", events$team_id, sep="")
events <- merge(events, teamInfo)
Created by Pretty R at inside-R.org

Saturday, March 7, 2009

MoneyBasketBall

I believe I'm in good company, among stats oriented baseball fans, having read Michael Lewis' article on Shane Battier on February 13th.
Michael tells a fascinating story, but numbers don't appear in his writing (and I think they shouldn't). So I was curios and I did some checking, thanks to data provided at basketballvalue.com.
It's a quick and dirty work, but I think it's worth a look.

The following table shows how the Lakers perform with Kobe on the court, with Kobe off the court and with Kobe on the court against Battier and the Rockets (data from the full 2007/08 season).

Lakers production


pts/min off reb / min def reb / min poss/min pts/poss
with Bryant 2.29 0.27 0.74 2.01 1.14
w/o Bryant 2.08 0.29 0.70 1.94 1.07
with Briant
vs. Battier
1.79 0.32 0.70 1.90 0.94


Lakers scoring drops by 0.2 points per minnute when Kobe is sitting on the bench. Their possessions per minute drop to some extent too: this can be something done intentionally by the team (their best player is off the court, so they slow down the game pace to minimize the effect of the absence).
Something else may be going on, too: difficult shots that a superstar player can take (and make) are not taken by other players, thus needing a longer time for the team to find a shoting opportunity.
The slower pace when Bryant is off the court is not enterily responsible of the drop in points, as the points per possessions also go down a bit; the fact that LA grabs more rebounds under the opponents board when their star is out is likely due to worse shoting percentage.
When Battier is playing against the Lakers, and Bryant is on the court, LA sees a substantial drop, performing even worse than in other games with Bryant sitting on the bench (LA offensive rebounds rise, perhaps due to lower shoting percentages).

I add another comparison table.
Here is Lakers with Bryant vs Rockets with Battier compared to Lakers with Bryant vs Rockets without Battier.

Lakers (with Bryant) production VS Rockets


pts/min off reb / min def reb / min poss/min pts/poss
w/o Battier 2.02 0.26 0.74 1.97 1.03
with Battier 1.79 0.32 0.70 1.90 0.94


We see that LA (with Kobe playing) scores less against Houston (compared to what they do against the league), but Battier's presence on the court is what seems to bring Lakers offense down most.
Since basketball has a lot more interaction between players than baseball, we can't conclude that Lakers scoring less when Shane is playing is entirely Shane's responsibility. Maybe Battier is always playing together with a very good defenseman and they get benched together.

I only looked at scoring (with a quick glance at rebounding) because those were the data readily available at basketballvalue.com; there's another wonderful source of basketball play-by-play data (basketballgeek.com), where one can look deeper at the issues I presented.