Getting started

Back to the index

BinderScriptNotebook

Getting started

Glad to see you here! Now that you found out and learned about FsLab, this section aims to illustrate how FsLab packages synergize and can be used to tackle practical data science challenges. Note that every package used througout the tutorial has its own documentation so if you are interested in Deedle (link), FSharp.Stats or Plotly.Net feel free to take a deeper dive.

Referencing packages

FsLab is a meant to be a project incubation space and can be thought of as a safe heaven for both, package developers and package users by providing guidelines and tutorials. Packages provided by the community can be used on their own, in combination with other FsLab packages but also in combination with any other .netstandard 2.0 compatible package. From F# 5.0 on packages can be referenced using the following notation:

// Packages hosted by the Fslab community
#r "nuget: Deedle"
#r "nuget: FSharp.Stats"
// third party .net packages 
#r "nuget: Plotly.NET, 2.0.0-preview.12"
#r "nuget: Plotly.NET.Interactive, 2.0.0-preview.12"
#r "nuget: FSharp.Data"

after referencing the packages one can access their namespaces and use provided functions. In the following example we will reference the top level namespaces and then use a function provided by the FSharp.Stats package to calculate a factorial:

open FSharp.Stats

let factorialOf3 = SpecialFunctions.Factorial.factorial 3
6.0

Data access

Equipped with these packages we are now ready to tackle promises made in the first paragraph: solving a practical data science problem. We will start by retrieving the data using the FSharp.Data package, subsequently we will use Deedle (link), a powerful data frame library that makes tabular data accessible by data frame programming. (Note that the chosen names give insight on their type, however thanks to FSharp being a strongly typed language and the we can at any time hower over single values to see the assigned type.)

open FSharp.Data
open Deedle

// Retrieve data using the FSharp.Data package
let rawData = Http.RequestString @"https://raw.githubusercontent.com/dotnet/machinelearning/master/test/data/housing.txt"

// And create a data frame object using the ReadCsvString method provided by Deedle.
// Note: Of course you can directly provide the path to a local source.
let df = Frame.ReadCsvString(rawData,hasHeaders=true,separators="\t")

// Using the Print() method, we can use the Deedle pretty printer to have a look at the data set.
df.Print()
MedianHomeValue CrimesPerCapita PercentResidental PercentNonRetail CharlesRiver NitricOxides RoomsPerDwelling PercentPre40s EmploymentDistance HighwayDistance TaxRate TeacherRatio BlackIndex PercentLowIncome 
0   -> 24.00           0.00632         18.00             2.310            0            0.5380       6.5750           65.20         4.0900             1               296.0   15.30        396.90     4.98             
1   -> 21.60           0.02731         0.00              7.070            0            0.4690       6.4210           78.90         4.9671             2               242.0   17.80        396.90     9.14             
2   -> 34.70           0.02729         0.00              7.070            0            0.4690       7.1850           61.10         4.9671             2               242.0   17.80        392.83     4.03             
3   -> 33.40           0.03237         0.00              2.180            0            0.4580       6.9980           45.80         6.0622             3               222.0   18.70        394.63     2.94             
4   -> 36.20           0.06905         0.00              2.180            0            0.4580       7.1470           54.20         6.0622             3               222.0   18.70        396.90     5.33             
5   -> 28.70           0.02985         0.00              2.180            0            0.4580       6.4300           58.70         6.0622             3               222.0   18.70        394.12     5.21             
6   -> 22.90           0.08829         12.50             7.870            0            0.5240       6.0120           66.60         5.5605             5               311.0   15.20        395.60     12.43            
7   -> 27.10           0.14455         12.50             7.870            0            0.5240       6.1720           96.10         5.9505             5               311.0   15.20        396.90     19.15            
8   -> 16.50           0.21124         12.50             7.870            0            0.5240       5.6310           100.00        6.0821             5               311.0   15.20        386.63     29.93            
9   -> 18.90           0.17004         12.50             7.870            0            0.5240       6.0040           85.90         6.5921             5               311.0   15.20        386.71     17.10            
10  -> 15.00           0.22489         12.50             7.870            0            0.5240       6.3770           94.30         6.3467             5               311.0   15.20        392.52     20.45            
11  -> 18.90           0.11747         12.50             7.870            0            0.5240       6.0090           82.90         6.2267             5               311.0   15.20        396.90     13.27            
12  -> 21.70           0.09378         12.50             7.870            0            0.5240       5.8890           39.00         5.4509             5               311.0   15.20        390.50     15.71            
13  -> 20.40           0.62976         0.00              8.140            0            0.5380       5.9490           61.80         4.7075             4               307.0   21.00        396.90     8.26             
14  -> 18.20           0.63796         0.00              8.140            0            0.5380       6.0960           84.50         4.4619             4               307.0   21.00        380.02     10.26            
:      ...             ...             ...               ...              ...          ...          ...              ...           ...                ...             ...     ...          ...        ...              
491 -> 13.60           0.10574         0.00              27.740           0            0.6090       5.9830           98.80         1.8681             4               711.0   20.10        390.11     18.07            
492 -> 20.10           0.11132         0.00              27.740           0            0.6090       5.9830           83.50         2.1099             4               711.0   20.10        396.90     13.35            
493 -> 21.80           0.17331         0.00              9.690            0            0.5850       5.7070           54.00         2.3817             6               391.0   19.20        396.90     12.01            
494 -> 24.50           0.27957         0.00              9.690            0            0.5850       5.9260           42.60         2.3817             6               391.0   19.20        396.90     13.59            
495 -> 23.10           0.17899         0.00              9.690            0            0.5850       5.6700           28.80         2.7986             6               391.0   19.20        393.29     17.60            
496 -> 19.70           0.28960         0.00              9.690            0            0.5850       5.3900           72.90         2.7986             6               391.0   19.20        396.90     21.14            
497 -> 18.30           0.26838         0.00              9.690            0            0.5850       5.7940           70.60         2.8927             6               391.0   19.20        396.90     14.10            
498 -> 21.20           0.23912         0.00              9.690            0            0.5850       6.0190           65.30         2.4091             6               391.0   19.20        396.90     12.92            
499 -> 17.50           0.17783         0.00              9.690            0            0.5850       5.5690           73.50         2.3999             6               391.0   19.20        395.77     15.10            
500 -> 16.80           0.22438         0.00              9.690            0            0.5850       6.0270           79.70         2.4982             6               391.0   19.20        396.90     14.33            
501 -> 22.40           0.06263         0.00              11.930           0            0.5730       6.5930           69.10         2.4786             1               273.0   21.00        391.99     9.67             
502 -> 20.60           0.04527         0.00              11.930           0            0.5730       6.1200           76.70         2.2875             1               273.0   21.00        396.90     9.08             
503 -> 23.90           0.06076         0.00              11.930           0            0.5730       6.9760           91.00         2.1675             1               273.0   21.00        396.90     5.64             
504 -> 22.00           0.10959         0.00              11.930           0            0.5730       6.7940           89.30         2.3889             1               273.0   21.00        393.45     6.48             
505 -> 11.90           0.04741         0.00              11.930           0            0.5730       6.0300           80.80         2.5050             1               273.0   21.00        396.90     7.88

Data crunching

The data set of choice is the boston housing data set. As you can see from analyzing the printed output, it consists of 506 rows. Each row represents a house in the boston city area and each column encodes a feature/variable, such as the number of rooms per dwelling (RoomsPerDwelling), Median value of owner-occupied homes in $1000's (MedianHomeValue) and even variables indicating if the house is bordering river charles (CharlesRiver, value = 1) or not (CharlesRiver, value = 0).

Lets say in our analysis we are only interested in the variables just described, furthermore we only want to keep rows where the value of the indicator variable is 0. We can use Deedle to easily create a new frame that fullfills our criteria. In this example we also cast the value of the column "CharlesRiver" to be of type bool, this illustrates how data frame programming can become typesafe using deedle.

let housesNotAtRiver = 
    df
    |> Frame.sliceCols ["RoomsPerDwelling";"MedianHomeValue";"CharlesRiver"]
    |> Frame.filterRowValues (fun s -> s.GetAs<bool>("CharlesRiver") |> not ) 

//sprintf "The new frame does now contain: %i rows and %i columns" housesNotAtRiver.RowCount housesNotAtRiver.ColumnCount

housesNotAtRiver.Print()
RoomsPerDwelling MedianHomeValue CharlesRiver 
0   -> 6.5750           24.00           0            
1   -> 6.4210           21.60           0            
2   -> 7.1850           34.70           0            
3   -> 6.9980           33.40           0            
4   -> 7.1470           36.20           0            
5   -> 6.4300           28.70           0            
6   -> 6.0120           22.90           0            
7   -> 6.1720           27.10           0            
8   -> 5.6310           16.50           0            
9   -> 6.0040           18.90           0            
10  -> 6.3770           15.00           0            
11  -> 6.0090           18.90           0            
12  -> 5.8890           21.70           0            
13  -> 5.9490           20.40           0            
14  -> 6.0960           18.20           0            
:      ...              ...             ...          
491 -> 5.9830           13.60           0            
492 -> 5.9830           20.10           0            
493 -> 5.7070           21.80           0            
494 -> 5.9260           24.50           0            
495 -> 5.6700           23.10           0            
496 -> 5.3900           19.70           0            
497 -> 5.7940           18.30           0            
498 -> 6.0190           21.20           0            
499 -> 5.5690           17.50           0            
500 -> 6.0270           16.80           0            
501 -> 6.5930           22.40           0            
502 -> 6.1200           20.60           0            
503 -> 6.9760           23.90           0            
504 -> 6.7940           22.00           0            
505 -> 6.0300           11.90           0

Data exploration

Exploratory data analysis is an approach favored by many - to meet this demand we strongly advertise the use of Plotly.Net. The following snippet illustrates how we can access a column of a data frame and create an interactive chart in no time. Since we might want an idea of the distribution of the house prices a histogram can come in handy:

open Plotly.NET

// Note that we explicitly specify that we want to work with the values as floats. 
// Since the row identity is not needed anymore when plotting the distribution we can
// directly convert the collection to a FSharp Sequence. 
let pricesNotAtRiver : seq<float> = 
    housesNotAtRiver
    |> Frame.getCol "MedianHomeValue"
    |> Series.values
    
let h1 = 
    Chart.Histogram(pricesNotAtRiver)
    |> Chart.withXAxisStyle("median value of owner occupied homes in 1000s")
    |> Chart.withXAxisStyle("price distribution")

Since plotly charts are interactive they invite us to combine mutliple charts. Let repeat the filter step and see if houses that are located at the river show a similar distribution:

let housesAtRiver = 
    df
    |> Frame.sliceCols ["RoomsPerDwelling";"MedianHomeValue";"CharlesRiver"]
    |> Frame.filterRowValues (fun s -> s.GetAs<bool>("CharlesRiver"))

let pricesAtRiver : seq<float> = 
    housesAtRiver
    |> Frame.getCol "MedianHomeValue"
    |> Series.values

let h2 =     
    [
    Chart.Histogram(pricesNotAtRiver)
    |> Chart.withTraceName "not at river"
    Chart.Histogram(pricesAtRiver)
    |> Chart.withTraceName "at river"
    ]
    |> Chart.combine
    |> Chart.withXAxisStyle("median value of owner occupied homes in 1000s")
    |> Chart.withXAxisStyle("Comparison of price distributions")

The interactive chart allows us to compare the distributions directly. We can now reconstruct our own idea of the city of boston, the sampled area, just by looking at the data e.g.:

Assuming that the sampling process was homogenous while observing that there are much more houses sampled that are not located on the riverside could indicate that a spot on the river is a scarce commodity. This could also be backed by analyzing the tails of the distribution: it seems that houses located at the river are given a head-start in their assigned value - the distribution of the riverside houses is truncated on the left.

Suppose we would have a customer that wants two models, one to predict the prices of a house at the riverside and one that predicts the prices if this is not the case, then we can meet this demand by using FSharp.Stats in combination with Deedle. Of course we need a variable that is indicative of the house price, in this we will check if the number of rooms per dwelling correlates with the house value:

let pricesAll :Series<int,float> = 
    df
    |> Frame.getCol "MedianHomeValue"

let roomsPerDwellingAll :Series<int,float> = 
    df
    |> Frame.getCol "RoomsPerDwelling"   

let correlation = 
    let tmpPrices,tmpRooms = 
        Series.zipInner pricesAll roomsPerDwellingAll    
        |> Series.values 
        |> Seq.unzip
    Correlation.Seq.pearson tmpPrices tmpRooms
                                              
0.6953599471

So indeed, the number of rooms per dwelling shows a positiv correlation with the house prices. With a pearson correlation of ~0.7 it does not explain the house prices completely - but this is nothing that really surprises us, as one of our hypothesis is that the location (e.g. riverside) does also have influence on the price - however, it should be sufficient to create a linear model.

So now we will use FSharp.Stats to build the two linear models ordered by the hypothetical customer. We start by defining a function that performs the fitting and plots the result:

open Fitting.LinearRegression.OrdinaryLeastSquares

let predictPricesByRooms description data = 
    let pricesAll :Series<_,float> = 
        data
        |> Frame.getCol "MedianHomeValue"

    let roomsPerDwellingAll :Series<_,float> = 
        data
        |> Frame.getCol "RoomsPerDwelling"   

    let fit = 
        let tmpRooms, tmpPrices = 
            Series.zipInner roomsPerDwellingAll pricesAll    
            |> Series.sortBy fst
            |> Series.values 
            |> Seq.unzip
        let coeffs = Linear.Univariable.coefficient (vector tmpRooms) (vector tmpPrices)
        let model  = Linear.Univariable.fit coeffs 
        let predictedPrices = tmpRooms |> Seq.map model
        [
        Chart.Point(tmpRooms,tmpPrices)
        |> Chart.withTraceName (sprintf "%s: data" description )
        Chart.Line(tmpRooms,predictedPrices)
        |> Chart.withTraceName (sprintf "%s: coefficients: intercept:%f, slope:%f" description coeffs.[0] coeffs.[1])
        ]                                  
        |> Chart.combine
        |> Chart.withXAxisStyle("rooms per dwelling")
        |> Chart.withYAxisStyle("median value")
    fit   

Afterwards, we can apply the function on our prepared datasets and have a look at the model and especially the model coefficients.

let modelVis = 
    [
    predictPricesByRooms "not at river" housesNotAtRiver
    predictPricesByRooms "at river" housesAtRiver
    ]
    |> Chart.combine
    |> Chart.withSize(1200.,700.)

Both models approximate the data in a reasonable way. When we inspect the coefficients, we see that the models only differ slightly in slope, but have an absolute offset of ~7.5. This observation complements the insights gained by the explorative data analysis approach using the histogram!

Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Stats
val factorialOf3 : float
namespace FSharp.Stats.SpecialFunctions
module Factorial from FSharp.Stats.SpecialFunctions
<summary> Special mathematical functions </summary>
val factorial : x:int -> float
<summary> The factorial functions takes an int x and computes x!. This function will not overflow the floating point format as long as x is at most 170. </summary>
Multiple items
namespace FSharp.Data

--------------------
namespace Microsoft.FSharp.Data
namespace Deedle
val rawData : string
type Http = private new : unit -> Http static member private AppendQueryToUrl : url:string * query:(string * string) list -> string static member AsyncRequest : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> Async<HttpResponse> static member AsyncRequestStream : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> Async<HttpResponseWithStream> static member AsyncRequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> Async<string> static member private EncodeFormData : query:string -> string static member private InnerRequest : url:string * toHttpResponse:(string -> int -> string -> string -> 'a0 option -> Map<string,string> -> Map<string,string> -> Stream -> Async<'a1>) * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:'a0 * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> Async<'a1> static member Request : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> HttpResponse static member RequestStream : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> HttpResponseWithStream static member RequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) * ?timeout:int -> string
<summary> Utilities for working with network via HTTP. Includes methods for downloading resources with specified headers, query parameters and HTTP body </summary>
Multiple items
static member Http.RequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:System.Net.CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(System.Net.HttpWebRequest -> System.Net.HttpWebRequest) * ?timeout:int -> string

--------------------
static member Http.RequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:System.Net.CookieContainer * ?silentHttpErrors:bool * ?silentCookieErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(System.Net.HttpWebRequest -> System.Net.HttpWebRequest) * ?timeout:int -> string
val df : Frame<int,string>
Multiple items
module Frame from Deedle

--------------------
type Frame = static member ReadCsv : location:string * hasHeaders:Nullable<bool> * inferTypes:Nullable<bool> * inferRows:Nullable<int> * schema:string * separators:string * culture:string * maxRows:Nullable<int> * missingValues:string [] * preferOptions:bool -> Frame<int,string> + 1 overload static member ReadReader : reader:IDataReader -> Frame<int,string> static member CustomExpanders : Dictionary<Type,Func<obj,seq<string * Type * obj>>> static member NonExpandableInterfaces : ResizeArray<Type> static member NonExpandableTypes : HashSet<Type>

--------------------
type Frame<'TRowKey,'TColumnKey (requires equality and equality)> = interface IDynamicMetaObjectProvider interface INotifyCollectionChanged interface IFsiFormattable interface IFrame new : rowIndex:IIndex<'TRowKey> * columnIndex:IIndex<'TColumnKey> * data:IVector<IVector> * indexBuilder:IIndexBuilder * vectorBuilder:IVectorBuilder -> Frame<'TRowKey,'TColumnKey> + 1 overload member AddColumn : column:'TColumnKey * series:seq<'V> -> unit + 3 overloads member AggregateRowsBy : groupBy:seq<'TColumnKey> * aggBy:seq<'TColumnKey> * aggFunc:Func<Series<'TRowKey,'a>,'b> -> Frame<int,'TColumnKey> member Clone : unit -> Frame<'TRowKey,'TColumnKey> member ColumnApply : f:Func<Series<'TRowKey,'T>,ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey> + 1 overload member DropColumn : column:'TColumnKey -> unit ...

--------------------
new : names:seq<'TColumnKey> * columns:seq<ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey>
new : rowIndex:Indices.IIndex<'TRowKey> * columnIndex:Indices.IIndex<'TColumnKey> * data:IVector<IVector> * indexBuilder:Indices.IIndexBuilder * vectorBuilder:Vectors.IVectorBuilder -> Frame<'TRowKey,'TColumnKey>
static member Frame.ReadCsvString : csvString:string * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int * ?missingValues:string [] * ?preferOptions:bool -> Frame<int,string>
static member FrameExtensions.Print : frame:Frame<'K,'V> -> unit (requires equality and equality)
static member FrameExtensions.Print : frame:Frame<'K,'V> * printTypes:bool -> unit (requires equality and equality)
val housesNotAtRiver : Frame<int,string>
val sliceCols : columns:seq<'C> -> frame:Frame<'R,'C> -> Frame<'R,'C> (requires equality and equality)
val filterRowValues : f:(ObjectSeries<'C> -> bool) -> frame:Frame<'R,'C> -> Frame<'R,'C> (requires equality and equality)
val s : ObjectSeries<string>
member ObjectSeries.GetAs : column:'K -> 'R
member ObjectSeries.GetAs : column:'K * fallback:'R -> 'R
[<Struct>] type bool = System.Boolean
<summary>An abbreviation for the CLI type <see cref="T:System.Boolean" />.</summary>
<category>Basic Types</category>
val not : value:bool -> bool
<summary>Negate a logical value. Not True equals False and not False equals True</summary>
<param name="value">The value to negate.</param>
<returns>The result of the negation.</returns>
namespace Plotly
namespace Plotly.NET
val pricesNotAtRiver : seq<float>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
<summary>Builds a sequence using sequence expression syntax</summary>
<param name="sequence">The input sequence.</param>
<returns>The result sequence.</returns>


--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
<summary>An abbreviation for the CLI type <see cref="T:System.Collections.Generic.IEnumerable`1" /></summary>
<remarks> See the <see cref="T:Microsoft.FSharp.Collections.SeqModule" /> module for further operations related to sequences. See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/sequences">F# Language Guide - Sequences</a>. </remarks>
Multiple items
val float : value:'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>


--------------------
[<Struct>] type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>


--------------------
type float<'Measure> = float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
Multiple items
module Frame from Deedle

--------------------
type Frame = inherit DynamicObj new : unit -> Frame

--------------------
type Frame<'TRowKey,'TColumnKey (requires equality and equality)> = interface IDynamicMetaObjectProvider interface INotifyCollectionChanged interface IFsiFormattable interface IFrame new : rowIndex:IIndex<'TRowKey> * columnIndex:IIndex<'TColumnKey> * data:IVector<IVector> * indexBuilder:IIndexBuilder * vectorBuilder:IVectorBuilder -> Frame<'TRowKey,'TColumnKey> + 1 overload member AddColumn : column:'TColumnKey * series:seq<'V> -> unit + 3 overloads member AggregateRowsBy : groupBy:seq<'TColumnKey> * aggBy:seq<'TColumnKey> * aggFunc:Func<Series<'TRowKey,'a>,'b> -> Frame<int,'TColumnKey> member Clone : unit -> Frame<'TRowKey,'TColumnKey> member ColumnApply : f:Func<Series<'TRowKey,'T>,ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey> + 1 overload member DropColumn : column:'TColumnKey -> unit ...

--------------------
new : unit -> Frame

--------------------
new : names:seq<'TColumnKey> * columns:seq<ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey>
new : rowIndex:Indices.IIndex<'TRowKey> * columnIndex:Indices.IIndex<'TColumnKey> * data:IVector<IVector> * indexBuilder:Indices.IIndexBuilder * vectorBuilder:Vectors.IVectorBuilder -> Frame<'TRowKey,'TColumnKey>
val getCol : column:'C -> frame:Frame<'R,'C> -> Series<'R,'V> (requires equality and equality)
Multiple items
module Series from Deedle

--------------------
type Series = static member ofNullables : values:seq<Nullable<'a0>> -> Series<int,'a0> (requires default constructor and value type and 'a0 :> ValueType) static member ofObservations : observations:seq<'c * 'd> -> Series<'c,'d> (requires equality) static member ofOptionalObservations : observations:seq<'K * 'a1 option> -> Series<'K,'a1> (requires equality) static member ofValues : values:seq<'a> -> Series<int,'a>

--------------------
type Series<'K,'V (requires equality)> = interface IFsiFormattable interface ISeries<'K> new : index:IIndex<'K> * vector:IVector<'V> * vectorBuilder:IVectorBuilder * indexBuilder:IIndexBuilder -> Series<'K,'V> + 3 overloads member After : lowerExclusive:'K -> Series<'K,'V> member Aggregate : aggregation:Aggregation<'K> * keySelector:Func<DataSegment<Series<'K,'V>>,'TNewKey> * valueSelector:Func<DataSegment<Series<'K,'V>>,OptionalValue<'R>> -> Series<'TNewKey,'R> (requires equality) + 1 overload member AsyncMaterialize : unit -> Async<Series<'K,'V>> member Before : upperExclusive:'K -> Series<'K,'V> member Between : lowerInclusive:'K * upperInclusive:'K -> Series<'K,'V> member Compare : another:Series<'K,'V> -> Series<'K,Diff<'V>> member Convert : forward:Func<'V,'R> * backward:Func<'R,'V> -> Series<'K,'R> ...

--------------------
new : pairs:seq<System.Collections.Generic.KeyValuePair<'K,'V>> -> Series<'K,'V>
new : keys:seq<'K> * values:seq<'V> -> Series<'K,'V>
new : keys:'K [] * values:'V [] -> Series<'K,'V>
new : index:Indices.IIndex<'K> * vector:IVector<'V> * vectorBuilder:Vectors.IVectorBuilder * indexBuilder:Indices.IIndexBuilder -> Series<'K,'V>
val values : series:Series<'K,'T> -> seq<'T> (requires equality)
val h1 : GenericChart.GenericChart
type Chart = static member Area : x:seq<#IConvertible> * y:seq<#IConvertible> * ?Name:string * ?ShowMarkers:bool * ?ShowLegend:bool * ?MarkerSymbol:MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?Dash:DrawingStyle * ?Width:float -> GenericChart + 1 overload static member Bar : values:seq<#IConvertible> * ?Keys:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Color:Color * ?PatternShape:PatternShape * ?MultiPatternShape:seq<PatternShape> * ?Pattern:Pattern * ?Base:#IConvertible * ?Width:'a3 * ?MultiWidth:seq<'a3> * ?Opacity:float * ?MultiOpacity:seq<float> * ?Text:'a4 * ?MultiText:seq<'a4> * ?TextPosition:TextPosition * ?MultiTextPosition:seq<TextPosition> * ?TextFont:Font * ?Marker:Marker -> GenericChart (requires 'a3 :> IConvertible and 'a4 :> IConvertible) + 1 overload static member BoxPlot : ?x:seq<#IConvertible> * ?y:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Text:'a2 * ?MultiText:seq<'a2> * ?Fillcolor:Color * ?MarkerColor:Color * ?OutlierColor:Color * ?OutlierWidth:int * ?Opacity:float * ?WhiskerWidth:float * ?BoxPoints:BoxPoints * ?BoxMean:BoxMean * ?Jitter:float * ?PointPos:float * ?Orientation:Orientation * ?Marker:Marker * ?Line:Line * ?AlignmentGroup:string * ?Offsetgroup:string * ?Notched:bool * ?NotchWidth:float * ?QuartileMethod:QuartileMethod -> GenericChart (requires 'a2 :> IConvertible) + 1 overload static member Bubble : x:seq<#IConvertible> * y:seq<#IConvertible> * sizes:seq<int> * ?Name:string * ?ShowLegend:bool * ?MarkerSymbol:MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?StackGroup:string * ?Orientation:Orientation * ?GroupNorm:GroupNorm * ?UseWebGL:bool -> GenericChart + 1 overload static member Candlestick : open:seq<#IConvertible> * high:seq<#IConvertible> * low:seq<#IConvertible> * close:seq<#IConvertible> * x:seq<#IConvertible> * ?Increasing:Line * ?Decreasing:Line * ?WhiskerWidth:float * ?Line:Line * ?XCalendar:Calendar -> GenericChart + 1 overload static member Column : values:seq<#IConvertible> * ?Keys:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Color:Color * ?Pattern:Pattern * ?PatternShape:PatternShape * ?MultiPatternShape:seq<PatternShape> * ?Base:#IConvertible * ?Width:'a3 * ?MultiWidth:seq<'a3> * ?Opacity:float * ?MultiOpacity:seq<float> * ?Text:'a4 * ?MultiText:seq<'a4> * ?TextPosition:TextPosition * ?MultiTextPosition:seq<TextPosition> * ?TextFont:Font * ?Marker:Marker -> GenericChart (requires 'a3 :> IConvertible and 'a4 :> IConvertible) + 1 overload static member Contour : data:seq<#seq<'a1>> * ?X:seq<#IConvertible> * ?Y:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Colorscale:Colorscale * ?Showscale:'a4 * ?zSmooth:SmoothAlg * ?ColorBar:'a5 -> GenericChart (requires 'a1 :> IConvertible) static member Funnel : x:seq<#IConvertible> * y:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?Color:Color * ?Line:Line * ?x0:'a3 * ?dX:float * ?y0:'a4 * ?dY:float * ?Width:float * ?Offset:float * ?Orientation:Orientation * ?Alignmentgroup:string * ?Offsetgroup:string * ?Cliponaxis:bool * ?Connector:FunnelConnector * ?Insidetextfont:Font * ?Outsidetextfont:Font -> GenericChart static member Heatmap : data:seq<#seq<'a1>> * ?ColNames:seq<#IConvertible> * ?RowNames:seq<#IConvertible> * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Colorscale:Colorscale * ?Showscale:'a4 * ?Xgap:'a5 * ?Ygap:'a6 * ?zSmooth:SmoothAlg * ?ColorBar:'a7 * ?UseWebGL:bool -> GenericChart (requires 'a1 :> IConvertible) static member Histogram : ?X:seq<#IConvertible> * ?Y:seq<#IConvertible> * ?Orientation:Orientation * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Text:'c * ?MultiText:seq<'c> * ?HistFunc:HistFunc * ?HistNorm:HistNorm * ?AlignmentGroup:string * ?OffsetGroup:string * ?NBinsX:int * ?NBinsY:int * ?BinGroup:string * ?XBins:Bins * ?YBins:Bins * ?MarkerColor:Color * ?Marker:Marker * ?Line:Line * ?ErrorX:Error * ?ErrorY:Error * ?Cumulative:Cumulative * ?HoverLabel:Hoverlabel -> GenericChart (requires 'c :> IConvertible) + 1 overload ...
static member Chart.Histogram : data:seq<#System.IConvertible> * orientation:StyleParam.Orientation * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Text:'a1 * ?MultiText:seq<'a1> * ?HistFunc:StyleParam.HistFunc * ?HistNorm:StyleParam.HistNorm * ?AlignmentGroup:string * ?OffsetGroup:string * ?NBinsX:int * ?NBinsY:int * ?BinGroup:string * ?XBins:TraceObjects.Bins * ?YBins:TraceObjects.Bins * ?MarkerColor:Color * ?Marker:TraceObjects.Marker * ?Line:Line * ?ErrorX:TraceObjects.Error * ?ErrorY:TraceObjects.Error * ?Cumulative:TraceObjects.Cumulative * ?HoverLabel:LayoutObjects.Hoverlabel -> GenericChart.GenericChart (requires 'a1 :> System.IConvertible)
static member Chart.Histogram : ?X:seq<#System.IConvertible> * ?Y:seq<#System.IConvertible> * ?Orientation:StyleParam.Orientation * ?Name:string * ?ShowLegend:bool * ?Opacity:float * ?Text:'c * ?MultiText:seq<'c> * ?HistFunc:StyleParam.HistFunc * ?HistNorm:StyleParam.HistNorm * ?AlignmentGroup:string * ?OffsetGroup:string * ?NBinsX:int * ?NBinsY:int * ?BinGroup:string * ?XBins:TraceObjects.Bins * ?YBins:TraceObjects.Bins * ?MarkerColor:Color * ?Marker:TraceObjects.Marker * ?Line:Line * ?ErrorX:TraceObjects.Error * ?ErrorY:TraceObjects.Error * ?Cumulative:TraceObjects.Cumulative * ?HoverLabel:LayoutObjects.Hoverlabel -> GenericChart.GenericChart (requires 'c :> System.IConvertible)
static member Chart.withXAxisStyle : title:string * ?TitleFont:Font * ?MinMax:(float * float) * ?ShowGrid:bool * ?ShowLine:bool * ?Side:StyleParam.Side * ?Overlaying:StyleParam.LinearAxisId * ?Id:StyleParam.SubPlotId * ?Domain:(float * float) * ?Position:float * ?Zeroline:bool * ?Anchor:StyleParam.LinearAxisId -> (GenericChart.GenericChart -> GenericChart.GenericChart)
module GenericChart from Plotly.NET
<summary> Module to represent a GenericChart </summary>
val toChartHTML : gChart:GenericChart.GenericChart -> string
<summary> Converts a GenericChart to it HTML representation. The div layer has a default size of 600 if not specified otherwise. </summary>
val housesAtRiver : Frame<int,string>
val pricesAtRiver : seq<float>
val h2 : GenericChart.GenericChart
static member Chart.withTraceName : ?Name:string * ?ShowLegend:bool * ?LegendGroup:string * ?Visible:StyleParam.Visible -> (GenericChart.GenericChart -> GenericChart.GenericChart)
static member Chart.combine : gCharts:seq<GenericChart.GenericChart> -> GenericChart.GenericChart
val pricesAll : Series<int,float>
Multiple items
val int : value:'T -> int (requires member op_Explicit)
<summary>Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Int32.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted int</returns>


--------------------
[<Struct>] type int = int32
<summary>An abbreviation for the CLI type <see cref="T:System.Int32" />.</summary>
<category>Basic Types</category>


--------------------
type int<'Measure> = int
<summary>The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Int32" />.</summary>
<category>Basic Types with Units of Measure</category>
val roomsPerDwellingAll : Series<int,float>
val correlation : float
val tmpPrices : seq<float>
val tmpRooms : seq<float>
val zipInner : series1:Series<'K,'V1> -> series2:Series<'K,'V2> -> Series<'K,('V1 * 'V2)> (requires equality)
Multiple items
module Seq from Plotly.NET

--------------------
module Seq from FSharp.Stats
<summary> Module to compute common statistical measure </summary>

--------------------
module Seq from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.seq`1" />.</summary>
val unzip : input:seq<'a * 'b> -> seq<'a> * seq<'b>
<summary> Splits a sequence of pairs into two sequences </summary>
module Correlation from FSharp.Stats
<summary> Contains correlation functions for different data types </summary>
module Seq from FSharp.Stats.Correlation
<summary> Contains correlation functions optimized for sequences </summary>
val pearson : seq1:seq<'T> -> seq2:seq<'T> -> float (requires member op_Explicit and member get_Zero and member get_One)
<summary> Calculates the pearson correlation of two samples. Homoscedasticity must be assumed. </summary>
namespace FSharp.Stats.Fitting
module LinearRegression from FSharp.Stats.Fitting
module OrdinaryLeastSquares from FSharp.Stats.Fitting.LinearRegression
val predictPricesByRooms : description:string -> data:Frame<'a,string> -> GenericChart.GenericChart (requires equality)
val description : string
val data : Frame<'a,string> (requires equality)
val pricesAll : Series<'a,float> (requires equality)
val roomsPerDwellingAll : Series<'a,float> (requires equality)
val fit : GenericChart.GenericChart
val sortBy : proj:('T -> 'V) -> series:Series<'K,'T> -> Series<'K,'T> (requires comparison and equality)
val fst : tuple:('T1 * 'T2) -> 'T1
<summary>Return the first element of a tuple, <c>fst (a,b) = a</c>.</summary>
<param name="tuple">The input tuple.</param>
<returns>The first value.</returns>
val coeffs : Vector<float>
module Linear from FSharp.Stats.Fitting.LinearRegression.OrdinaryLeastSquares
<summary> Simple linear regression y : x -&gt; a + bx </summary>
module Univariable from FSharp.Stats.Fitting.LinearRegression.OrdinaryLeastSquares.Linear
val coefficient : xData:Vector<float> -> yData:Vector<float> -> Vector<float>
<summary> Calculates the coefficients for linear regression in the form of [|intercept; slope;|] </summary>
Multiple items
val vector : l:seq<float> -> Vector<float>

--------------------
type vector = Vector<float>
val model : (float -> float)
val fit : coef:Vector<float> -> x:float -> float
<summary> Fit to x </summary>
val predictedPrices : seq<float>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
<summary>Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection. The given function will be applied as elements are demanded using the <c>MoveNext</c> method on enumerators retrieved from the object.</summary>
<remarks>The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently.</remarks>
<param name="mapping">A function to transform items from the input sequence.</param>
<param name="source">The input sequence.</param>
<returns>The result sequence.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
static member Chart.Point : xy:seq<#System.IConvertible * #System.IConvertible> * ?Name:string * ?ShowLegend:bool * ?MarkerSymbol:StyleParam.MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#System.IConvertible> * ?TextPosition:StyleParam.TextPosition * ?TextFont:Font * ?StackGroup:string * ?Orientation:StyleParam.Orientation * ?GroupNorm:StyleParam.GroupNorm * ?UseWebGL:bool -> GenericChart.GenericChart
static member Chart.Point : x:seq<#System.IConvertible> * y:seq<#System.IConvertible> * ?Name:string * ?ShowLegend:bool * ?MarkerSymbol:StyleParam.MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#System.IConvertible> * ?TextPosition:StyleParam.TextPosition * ?TextFont:Font * ?StackGroup:string * ?Orientation:StyleParam.Orientation * ?GroupNorm:StyleParam.GroupNorm * ?UseWebGL:bool -> GenericChart.GenericChart
val sprintf : format:Printf.StringFormat<'T> -> 'T
<summary>Print to a string using the given format.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
static member Chart.Line : xy:seq<#System.IConvertible * #System.IConvertible> * ?Name:string * ?ShowMarkers:bool * ?ShowLegend:bool * ?MarkerSymbol:StyleParam.MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#System.IConvertible> * ?TextPosition:StyleParam.TextPosition * ?TextFont:Font * ?Dash:StyleParam.DrawingStyle * ?Width:float * ?StackGroup:string * ?Orientation:StyleParam.Orientation * ?GroupNorm:StyleParam.GroupNorm * ?UseWebGL:bool -> GenericChart.GenericChart
static member Chart.Line : x:seq<#System.IConvertible> * y:seq<#System.IConvertible> * ?Name:string * ?ShowMarkers:bool * ?ShowLegend:bool * ?MarkerSymbol:StyleParam.MarkerSymbol * ?Color:Color * ?Opacity:float * ?Labels:seq<#System.IConvertible> * ?TextPosition:StyleParam.TextPosition * ?TextFont:Font * ?Dash:StyleParam.DrawingStyle * ?Width:float * ?StackGroup:string * ?Orientation:StyleParam.Orientation * ?GroupNorm:StyleParam.GroupNorm * ?UseWebGL:bool -> GenericChart.GenericChart
static member Chart.withYAxisStyle : title:string * ?TitleFont:Font * ?MinMax:(float * float) * ?ShowGrid:bool * ?ShowLine:bool * ?Side:StyleParam.Side * ?Overlaying:StyleParam.LinearAxisId * ?Id:StyleParam.SubPlotId * ?Domain:(float * float) * ?Position:float * ?ZeroLine:bool * ?Anchor:StyleParam.LinearAxisId -> (GenericChart.GenericChart -> GenericChart.GenericChart)
val modelVis : GenericChart.GenericChart
static member Chart.withSize : width:float * height:float -> (GenericChart.GenericChart -> GenericChart.GenericChart)
static member Chart.withSize : ?Width:int * ?Height:int -> (GenericChart.GenericChart -> GenericChart.GenericChart)