Skip to content

dyep49/Umpire-Auditor

Repository files navigation

#Umpire Auditor

###Umpire Auditor has been heavily refactored and is now maintained at https://github.com/dyep49/Angular-Umpire-Auditor

After every game, the MLB releases an incredible amount of data. In fact, every single pitch brings back nearly 30 different characteristics. Umpire Auditor uses this data to track (or audit) the performance of MLB umpires, primarily by calculating the rate at which these umpires correctly calculate balls and strikes.

At it's most basic, the application returns the worst call of the night, every night, chosen as such for being the ball, called strike, furthest from the strike zone. In addition, umpire performance statistics exist in the application for every game and cumulatively over the entire season.

This application made extensive use of the 'gameday_api' gem and 'nokogiri' to download (gameday_api gem) and parse ('nokogiri') the xml provided by the MLB's API.

Becuase the data released is so extensive, it was not practical to hit the MLB API everytime information was needed. As a result, the necessary files were downloaded by the game_day_api gem, parsed, and added to a Postgres database. Because there were so many files (500,000+ per season), it was necessary to parse the xml into a Ruby hash and convert that to csv. From there, the data was inserted into the database using Postgres. There were about one million rows inserted per season.

To ensure faster response time, some resource intensive calls were generated in a seed task, run daily, and stored in a csv file.

def strike?
    if self.width_strike? && self.height_strike?
        "Called Strike"
    else
        "Ball"
    end
end

def correct_call?
    self.strike? == self.description
end

def width_strike?
    half_plate_width = (17.5/12)/2
    self.x_location.abs < half_plate_width 
end

def height_strike?
    (self.y_location < self.sz_top) && (self.y_location > self.sz_bottom)
end

def distance_miss
    half_plate_width = (17.5/12)/2
    if self.y_location > self.sz_top
        self.distance_missed_y = (self.y_location - self.sz_top).round(2)
    elsif self.y_location < self.sz_bottom 
        self.distance_missed_y = (self.sz_bottom - self.y_location).round(2)
        else
        self.distance_missed_y = 0
    end

    if self.x_location.abs > half_plate_width
        self.distance_missed_x = (self.x_location.abs - half_plate_width).round(2)
    else
        self.distance_missed_x = 0
    end
    self.total_distance_missed = self.distance_missed_y + self.distance_missed_x
 end