Global warming proof in F#
Introduction + science behind topic
Recently, when I wanted to sharpen my F# skill I come out with idea for small program. Its task is to proof global warming using ice drilling data. Keep in mind it’s not entirely 100% accurate, it’s more like training F# in interesting topic. Ice drilling is a technique in which you use deep stored ice to take its properties. You can determine CO2 levels and temperature what is needed to see correlation between them. More information here. This idea was very interesting to me also because in this small program I could use quite a few mechanism unique to F#.
Loading the data with type providers
For loading CO2 and temperature data I’m using mechanism called type providers. It is mechanism that allows us to connect to data in much easier way and also with creates for us, behind the scenes whole type hierarchy representing the data.
type co2Csv = CsvProvider< "co2.csv", "\t" > let co2Data = co2Csv.Load("co2.csv").Rows
For example here by connecting to csv files, by providing path to them and data separator, when I turn on intellisense I immediately get the list of columns in csv file, I don’t need to create my own types and do the parsing of file, and attach columns to their valid names. Important to mention is also fact, that F# allows to write function (and other language construct) with spaces using
syntax like you can observe with
. Important to mention for type providers is also fact, that they can be used in many various types of data like sql, csv, json and even html to browse DOM.
Correlation is computed using Pearson equation:
which translates to F# code:
let computeCorrelation (first : float list) (second : float list) = if first.Length <> second.Length then failwith "Collections needs to be same size" let firstAvg = List.average first let secondAvg = List.average second let sum = List.zip first second |> List.sumBy (fun x -> (fst x - firstAvg) * (snd x - secondAvg)) sum / (float first.Length * standardDevation first * standardDevation second)
To better illustrate correlation I replace number with string explanation. I use pattern matching to do that in getCorrelationMeaning function:
let getCorrelationMeaning = function | 0.0 -> "No correlation" | x when Math.Abs(x) < 0.2 -> "Very minor correlation" | x when Math.Abs(x) < 0.4 -> "minor correlation" | x when Math.Abs(x) < 0.7 -> "Medium correlation" | x when Math.Abs(x) < 0.9 -> "Major correlation" | x when Math.Abs(x) < 1.0 -> "Very major correlation" | _ -> "Error - correlation must be between -1 and 1"
Pattern matching can be best described in my opinion as “switch on steroids” although the syntax is quite different it is more concise and allows i.e. do more filtration. Also in this example I use special “function” syntax to write pattern matching function with one default argument, here called “x”.
To draw chart I’m using FSharp.Charting library, it’s not ideal (problem in this case, is inability to draw to Y-Axis on the same chart) but it’s enough for learning program. So, to create chart I first create timeseries with CO2 and temperature levels:
let co2Series = co2Data |> Seq.map (fun x -> (convertBPtoThousandsYears x.<code></code>Gas age<code></code>, x.<code></code>CO2 (ppmv)<code></code>)) let tempSeries = tempData |> Seq.map (fun x -> (convertBPtoThousandsYears x.<code></code>Ice age (GT4)<code></code>, x.DeltaTS))
Then I create line chart for each of them:
let co2Chart = Chart.Line(co2Series, "CO2 [ppm]", Color = Color.Red) let tempChart = Chart.Line(tempSeries, "Temperature [C]", Color = Color.Blue)
And in the end I combine them in one chart and display on the screen
Chart.Combine([ co2Chart; tempChart ]) |> Chart.WithXAxis(Title = "Thousands of years") |> Chart.WithLegend() |> Chart.Show
Here are the results, as you can see, the inability to draw second Y-axis makes the results hard to read, but you can observe peaks in the same timeframe.
Result from program is major correlation. As I mention before this isn’t a completely valid research, I created this program mainly to continue learning F# and I think as that its fulfilling its role just right.