Thursday, January 20, 2011

Project Chadwick Update

I had hoped to crank out Project Chadwick posts about once a week but as you can tell that hasn’t happened.  One of the reasons is I was a little too ambitious writing them in four different languages especially since I’m learning the languages as I go (except for ruby).  Plus I’ve been working on a few side projects that have taken more time than I had anticipated.  So, what I’ve decided to do is to continue with the series using only two languages F# and Clojure. 

Why these two languages?

Basically, I’ve become very curious about functional languages so why not use this series as a starting point.  One of the reasons I’m staying with F# is it as a CLR based language which means that I may be able use it in future projects at my day job. I’m replacing Erlang with Clojure simply because I went to a Raleigh.rb, the local ruby meetup group, meeting where they had talk on Clojure.  The speaker made Clojure sound fun so I thought I’d give it a try.  I will be using the port of Clojure that runs on the CLR simply for ease of development for me.

Up Next…

I will be adding a few more problems to the Problems Page in addition to going back to the beginning and writing solutions in Clojure.  I’m looking forward to delving into the world of Clojure and functional programming in general.

Tuesday, January 11, 2011

Project Chadwick #2–Top 5 SF Giants OBP (Ruby version)

Before I get started on this post if you aren't familiar with Project Chadwick here's a quick overview. The data for this problem can be downloaded from here

The Problem

The On Base Percentage or OBP is the percentage of time the player reaches base. It is calculated using the following formula:
OBP = (H + BB + HBP) / (AB + BB + HBP + SF)

H   = Hits
BB  = Walks
HBP = Hit By Pitch
AB  = At Bats
SF  = Sacrifice Flies

The batter should have had at least 200 at bats to be eligible. The results should be printed out with in the following format: players name, season, and OBP.


The Solution



New Ruby Concepts

Ruby Class

The first ‘new’ thing you see in this script is a class. There are three items I'd like to discuss about this class:  attr_accessor, initialize and to_s methods.


The attr_accessor is a method that is used to indicate which instance variables, also known as attributes, are available outside of the class. All of the variables declared in the attr_accessor call can be read and updated from outside of the class. You can also set up attributes that are read-only by calling attr_reader. To set up a write-only attributes by calling the attr_writer. When attributes are used within a class they are prefaced with @ sign.

Another feature of a Ruby class is the initialize method which is the class’s constructor. In this class there isn’t much going on here other than taking the stats and putting them in a variable that makes it easier to read the code.



Well, there is a little more going on then a simple assignment. In the stats fields the ||= says that if the value on the left is nil then assign 0.0 to it. The value is then being converted to float so we can do division.

The last method I want to discuss is the to_s method. This method is overriding the base class’s to_s which is the a to string class. In this method I’m just formatting the output of the class so my loop is a little cleaner.


Arrays

One of my favorite things with Ruby is how arrays can be manipulated and used. The first example I’m adding the newly created Batter object to the end of the all_obps array. In the second line I'm sorting the array by the obp value. What I'd like to point out here is the ! at the end of sort. The ! indicates that the sorting will be done in place, in other words it changes the value of the array I’m sorting. If I left the ! off the sort would create a new array that was sorted leaving me with the original array AND a new, sorted array. Finally, the reverse! line has the [1,5] added to it. Which means I want the first through the fifth elements. In our case that is how I grab the top five OBP for the SF Giants.

An Overview of My Solution


In this script I’ve opted to write code that was easier to read instead of the fewest lines that’s why I created the Batter class. This way we can access the stats needed to calculate the OBP in a more straight forward way. Since I’ve already pointed out some of the nuances of Ruby classes and the calc_obp method being straight forward I’m not going to going to dissect the class any further here.



What I will talk about how the script reads and processes the data.  The first line in the snippet reads all lines of the file and then loops over it. I then create the Batter object and check to see if the batter had at least 200 at bats. If not I move on to the next line. If the batter had at least 200 at bats I calculate the OBP and store the Batter object in the all_obps array. The rest of the script sorts, reverses and prints the top five OBP for the San Francisco Giants.

That’s it, nothing to the Ruby script when you compare it to the F# script.  This may be due to the fact that I’ve worked with Ruby more than I have F# but I believe Ruby is just a little more concise than the F#.  I may change my mind after writing more F# code but for now that’s the way it seems to me.

I really enjoy writing Ruby code, it allows me to concentrate on what I need to do more than 'how do I do this in Ruby'. I guess what I'm trying to say it feels more natural than other languages such as C#.

Up Next...


I'm still working on getting more problems up for those of you who are interested in continuing on the baseball stats path. I'll write the Erlang version next and then wrap up the second problem with the Objective-C code.

Thanks for stopping by.

Sunday, December 12, 2010

Project Chadwick #2–Top 5 SF Giants OBP (F# Version)

Before I get started on this post if you aren't familiar with Project Chadwick here's a quick overview.

The data for this problem can be downloaded from here

In this problem we are going to find the Top 5 On Base Percentage Seasons since the Giants moved to San Francisco.  While I’m not convinced that I’m fully thinking like a functional programmer but I think I’m starting to ‘get it’.  With that said, lets get started.

New F# Concepts

In my second F# script, I’m using a few concepts that I didn’t use in the first solution, namely record and multi-lined functions.

The Record Type

type Batter = { Last : string; First : string; Season : int; AB : float; OBP : float }

So what is a record?  It looks like a different way to declare a class.  Well, it may look that way but records are not the same as classes.  Records allow you to group data into types and access the data using fields. Fields in records are immutable whereas classes do not offer the same type safety.  Also, records cannot be inherited.  There are other differences that are beyond the scope of my current F# knowledge but as my F# knowledge expands we may delve into the remaining differences.

Functions

A function is declared using the let statement. The keyword let is followed by the name of the function, a list of space delimited parameters, and optionally a return type.  The body of the function is determined by white space.  All lines that are indented after the declaration are considered part of the function’s body until a line is encountered at the same ‘level’ of indention as the let statement. The return value of a function is the result of the last line executed.

Seq.toList, Pipe Forward Operator and List.Map

When we read in the content of the data file using the ReadAllLines method the file content is returned as a string array.  In F# it is easier to work with lists in than arrays, least with what F# knowledge I have.  So to convert our file content into a list I used the Seq.toList method. The pipe forward operator, |>, is used to send the output of the ReadAllLines call to send or ‘pipe’ it to the Seq.toList method as its parameter. You can think of the pipe forward operator similar to the pipe utility UNIX command line.  The results of those commands are stored as a list<Batter> in the stats variable.

let stats = File.ReadAllLines(@".\data\sf_giants_batting.csv") |> Seq.toList

The List.map operation allows us to take a list and pass each item as a parameter to a function in one line.  In addition to calling the function it creates a new list with the results of each column, in this case we aren’t using the returned list.  In my solution I’m using it like a one line foreach call.  I’m calling the create_batters function passing in the tail of the stats list that I read in. Why just the tail, because the head is the line that contains the column headings.

List.map create_batters stats.Tail

An Overview of My Solution

Since I’m just getting started with F#, I find myself writing F# code that looks like C#.  I think my functions reflect that.  However, the last line makes me think that I’m starting to make the turn on understanding functional programming and how I can use it.  Here is the last line:

List.map print_batter (Seq.take 5 all_obps |> Seq.toList)

In my first go round of this script I had a for loop that went from 0 to 4 to print the first five items in the list.  As I was writing this post up I started looking at the loop thinking I could improve it.  I remembered reading about the Seq.take method that takes the number of  items specified from the given sequence.  So I removed the for loop and plopped in the following code in its place:

List.map print_batter (Seq.take 5 all_obps)

When I ran the new and improved script I received the following error:

chadwick-2-top5-obp.fsx(64,24): error FS0001: This expression was expected to have type Batter list but here has type seq<'a>

I noticed that the error message specifically stated that it was given a sequence but it expected a list.  So I tacked on the |> Seq.toList call and was able to get it to work.  That type of code is what gets me excided about functional programming.  I’m looking forward to getting to the point where I can truly use the functional programming aspects of F#.

Here is my entire solution:

I enjoyed working on this solution, while its nothing big in the grand scheme of things but it was my first ‘real’ F# script.  As always, any critiques, nudges or hints would be greatly appreciated.  My number one goal of going through this process is to learn the 4 languages.

Up Next…

I will be adding more problems to the list shortly and solving this problem in either ruby or objective-c next.