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.6"
#r "nuget: Plotly.NET.Interactive, 2.0.0-preview.6"
#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"

// Use .net Core functions to convert the retrieved string to a stream
let dataAsStream = new System.IO.MemoryStream(rawData |> System.Text.Encoding.UTF8.GetBytes) 

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

// Using the Print() method, we can use the Deedle pretty printer to have a look at the data set.
dataAsFrame.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 = 
    dataAsFrame
    |> 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.withX_AxisStyle("median value of owner occupied homes in 1000s")
    |> Chart.withX_AxisStyle("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 = 
    dataAsFrame
    |> 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.withX_AxisStyle("median value of owner occupied homes in 1000s")
    |> Chart.withX_AxisStyle("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> = 
    dataAsFrame
    |> Frame.getCol "MedianHomeValue"

let roomsPerDwellingAll :Series<int,float> = 
    dataAsFrame
    |> 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.withX_AxisStyle("rooms per dwelling")
        |> Chart.withY_AxisStyle("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
val factorial : x:int -> float
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
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 dataAsStream : System.IO.MemoryStream
namespace System
namespace System.IO
Multiple items
type MemoryStream =
  inherit Stream
  new : unit -> unit + 6 overloads
  member BeginRead : buffer: byte [] * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult
  member BeginWrite : buffer: byte [] * offset: int * count: int * callback: AsyncCallback * state: obj -> IAsyncResult
  member CopyTo : destination: Stream * bufferSize: int -> unit
  member CopyToAsync : destination: Stream * bufferSize: int * cancellationToken: CancellationToken -> Task
  member Dispose : disposing: bool -> unit
  member EndRead : asyncResult: IAsyncResult -> int
  member EndWrite : asyncResult: IAsyncResult -> unit
  member Flush : unit -> unit
  ...

--------------------
System.IO.MemoryStream() : System.IO.MemoryStream
System.IO.MemoryStream(buffer: byte []) : System.IO.MemoryStream
System.IO.MemoryStream(capacity: int) : System.IO.MemoryStream
System.IO.MemoryStream(buffer: byte [], writable: bool) : System.IO.MemoryStream
System.IO.MemoryStream(buffer: byte [], index: int, count: int) : System.IO.MemoryStream
System.IO.MemoryStream(buffer: byte [], index: int, count: int, writable: bool) : System.IO.MemoryStream
System.IO.MemoryStream(buffer: byte [], index: int, count: int, writable: bool, publiclyVisible: bool) : System.IO.MemoryStream
namespace System.Text
type Encoding =
  interface ICloneable
  new : unit -> unit + 2 overloads
  member Clone : unit -> obj
  member Equals : value: obj -> bool
  member GetByteCount : chars: nativeptr<char> * count: int -> int + 5 overloads
  member GetBytes : chars: nativeptr<char> * charCount: int * bytes: nativeptr<byte> * byteCount: int -> int + 7 overloads
  member GetCharCount : bytes: nativeptr<byte> * count: int -> int + 3 overloads
  member GetChars : bytes: nativeptr<byte> * byteCount: int * chars: nativeptr<char> * charCount: int -> int + 4 overloads
  member GetDecoder : unit -> Decoder
  member GetEncoder : unit -> Encoder
  ...
property System.Text.Encoding.UTF8: System.Text.Encoding with get
System.Text.Encoding.GetBytes(s: string) : byte []
System.Text.Encoding.GetBytes(chars: char []) : byte []
System.Text.Encoding.GetBytes(chars: System.ReadOnlySpan<char>, bytes: System.Span<byte>) : int
System.Text.Encoding.GetBytes(s: string, index: int, count: int) : byte []
System.Text.Encoding.GetBytes(chars: char [], index: int, count: int) : byte []
System.Text.Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
System.Text.Encoding.GetBytes(s: string, charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
System.Text.Encoding.GetBytes(chars: char [], charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
val dataAsFrame : 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.ReadCsv : path:string * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int * ?missingValues:string [] * ?preferOptions:bool -> Frame<int,string>
static member Frame.ReadCsv : stream:System.IO.Stream * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int * ?missingValues:string [] * ?preferOptions:bool -> Frame<int,string>
static member Frame.ReadCsv : reader:System.IO.TextReader * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int * ?missingValues:string [] * ?preferOptions:bool -> Frame<int,string>
static member Frame.ReadCsv : stream:System.IO.Stream * hasHeaders:System.Nullable<bool> * inferTypes:System.Nullable<bool> * inferRows:System.Nullable<int> * schema:string * separators:string * culture:string * maxRows:System.Nullable<int> * missingValues:string [] * preferOptions:System.Nullable<bool> -> Frame<int,string>
static member Frame.ReadCsv : location:string * hasHeaders:System.Nullable<bool> * inferTypes:System.Nullable<bool> * inferRows:System.Nullable<int> * schema:string * separators:string * culture:string * maxRows:System.Nullable<int> * missingValues:string [] * preferOptions:bool -> Frame<int,string>
static member Frame.ReadCsv : path:string * indexCol:string * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int * ?missingValues:string [] * ?preferOptions:bool -> Frame<'R,string> (requires equality)
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
val not : value:bool -> bool
namespace Plotly
namespace Plotly.NET
val pricesNotAtRiver : seq<float>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

--------------------
[<Struct>]
type float = System.Double

--------------------
type float<'Measure> =
  float
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:Symbol * ?Color:string * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?Dash:DrawingStyle * ?Width:float -> GenericChart + 1 overload
  static member Bar : keys:seq<#IConvertible> * values:seq<#IConvertible> * ?Name:string * ?Showlegend:bool * ?Color:string * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?Marker:Marker -> GenericChart + 1 overload
  static member BoxPlot : ?x:'a0 * ?y:'a1 * ?Name:string * ?Showlegend:bool * ?Color:string * ?Fillcolor:'a2 * ?Opacity:float * ?Whiskerwidth:'a3 * ?Boxpoints:Boxpoints * ?Boxmean:BoxMean * ?Jitter:'a4 * ?Pointpos:'a5 * ?Orientation:Orientation * ?Marker:Marker * ?Line:Line * ?Alignmentgroup:'a6 * ?Offsetgroup:'a7 * ?Notched:bool * ?NotchWidth:float * ?QuartileMethod:QuartileMethod -> GenericChart + 1 overload
  static member Bubble : x:seq<#IConvertible> * y:seq<#IConvertible> * sizes:seq<#IConvertible> * ?Name:string * ?Showlegend:bool * ?MarkerSymbol:Symbol * ?Color:string * ?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 ChoroplethMap : locations:seq<string> * z:seq<#IConvertible> * ?Text:seq<#IConvertible> * ?Locationmode:LocationFormat * ?Autocolorscale:bool * ?Colorscale:Colorscale * ?Colorbar:Colorbar * ?Marker:Marker * ?GeoJson:'a2 * ?FeatureIdKey:string * ?Zmin:float * ?Zmax:float -> GenericChart
  static member ChoroplethMapbox : locations:seq<#IConvertible> * z:seq<#IConvertible> * geoJson:'a2 * ?FeatureIdKey:string * ?Text:seq<#IConvertible> * ?Below:string * ?Colorscale:Colorscale * ?Colorbar:Colorbar * ?ZAuto:bool * ?ZMin:float * ?ZMid:float * ?ZMax:float -> GenericChart
  static member Column : keys:seq<#IConvertible> * values:seq<#IConvertible> * ?Name:string * ?Showlegend:bool * ?Color:string * ?Opacity:float * ?Labels:seq<#IConvertible> * ?TextPosition:TextPosition * ?TextFont:Font * ?Marker:Marker -> GenericChart + 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 DensityMapbox : lon:seq<#IConvertible> * lat:seq<#IConvertible> * ?Z:seq<#IConvertible> * ?Radius:float * ?Opacity:float * ?Text:seq<#IConvertible> * ?Below:string * ?Colorscale:Colorscale * ?Colorbar:Colorbar * ?Showscale:bool * ?ZAuto:bool * ?ZMin:float * ?ZMid:float * ?ZMax:float -> GenericChart + 1 overload
  ...
static member Chart.Histogram : data:seq<#System.IConvertible> * ?Orientation:StyleParam.Orientation * ?Name:string * ?Showlegend:bool * ?Opacity:float * ?Color:string * ?HistNorm:StyleParam.HistNorm * ?HistFunc:StyleParam.HistNorm * ?nBinsx:int * ?nBinsy:int * ?Xbins:Bins * ?Ybins:Bins * ?xError:'b * ?yError:'c -> GenericChart.GenericChart
static member Chart.withX_AxisStyle : title:string * ?MinMax:(float * float) * ?Showgrid:bool * ?Showline:bool * ?Side:StyleParam.Side * ?Overlaying:StyleParam.AxisAnchorId * ?Id:int * ?Domain:(float * float) * ?Position:float * ?Zeroline:bool * ?Anchor:StyleParam.AxisAnchorId -> (GenericChart.GenericChart -> GenericChart.GenericChart)
module GenericChart

from Plotly.NET
val toChartHTML : gChart:GenericChart.GenericChart -> string
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)

--------------------
[<Struct>]
type int = int32

--------------------
type int<'Measure> =
  int
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

--------------------
module Seq

from Microsoft.FSharp.Collections
val unzip : input:seq<'a * 'b> -> seq<'a> * seq<'b>
module Correlation

from FSharp.Stats
module Seq

from FSharp.Stats.Correlation
val pearson : seq1:seq<'T> -> seq2:seq<'T> -> float (requires member op_Explicit and member get_Zero and member get_One)
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
val coeffs : Vector<float>
module Linear

from FSharp.Stats.Fitting.LinearRegression.OrdinaryLeastSquares
module Univariable

from FSharp.Stats.Fitting.LinearRegression.OrdinaryLeastSquares.Linear
val coefficient : xData:Vector<float> -> yData:Vector<float> -> Vector<float>
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
val predictedPrices : seq<float>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
static member Chart.Point : xy:seq<#System.IConvertible * #System.IConvertible> * ?Name:string * ?Showlegend:bool * ?MarkerSymbol:StyleParam.Symbol * ?Color:string * ?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.Symbol * ?Color:string * ?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
static member Chart.Line : xy:seq<#System.IConvertible * #System.IConvertible> * ?Name:string * ?ShowMarkers:bool * ?Showlegend:bool * ?MarkerSymbol:StyleParam.Symbol * ?Color:string * ?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.Symbol * ?Color:string * ?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.withY_AxisStyle : title:string * ?MinMax:(float * float) * ?Showgrid:bool * ?Showline:bool * ?Side:StyleParam.Side * ?Overlaying:StyleParam.AxisAnchorId * ?Id:int * ?Domain:(float * float) * ?Position:float * ?Zeroline:bool * ?Anchor:StyleParam.AxisAnchorId -> (GenericChart.GenericChart -> GenericChart.GenericChart)
val modelVis : GenericChart.GenericChart
static member Chart.withSize : width:float * height:float -> (GenericChart.GenericChart -> GenericChart.GenericChart)