Replicate quality control

Back to the index

BinderScriptNotebook

Replicate quality control

Summary: This tutorial demonstrates an example workflow using different FsLab libraries. The aim is to check the quality of replicate measurements by clustering the samples.

Introduction

In biology and other sciences, experimental procedures are often repeated several times in the same conditions. These resulting samples are called replicates. Replicates are especially useful to check for the reproducibility of the results and to boost their trustability.

One metric for the quality of the measurements is rather easy in principle. Samples received from a similar procedure should also result in similar measurements. Therefore just checking if replicates are more similar than other samples can already hand to the experimenter some implications about the quality of his samples. This is especially useful when considering that usually - as the ground truth is unknown - this trustability is difficult to measure.

In this tutorial, a simple workflow will be presented for how to visualize the clustering of replicates in an experiment. For this, 3 FsLab libraries will be used:

  1. FSharp.Data for retreiving the data file
  2. Deedle for reading a frame containing the data
  3. & 3. FSharp.Stats to impute missing values and cluster the samples
  4. CyJS.NET to visualize the results

Referencing packages

#r "nuget: FSharp.Data"
#r "nuget: Deedle"
#r "nuget: FSharp.Stats"
#r "nuget: Cyjs.NET"

do fsi.AddPrinter(fun (printer:Deedle.Internal.IFsiFormattable) -> "\n" + (printer.Format()))

Loading Data

In this tutorial, an in silico generated dataset is used.

FSharp.Data and Deedle are used to load the data into the fsi.

open FSharp.Data
open Deedle

// Load the data 
let rawData = Http.RequestString @"https://raw.githubusercontent.com/fslaborg/datasets/main/data/InSilicoGeneExpression.csv"

// Create a deedle frame and index the rows with the values of the "Key" column.
let rawFrame : Frame<string,string> = 
    Frame.ReadCsvString(rawData)
    |> Frame.indexRows "Key"
Condition0_1     Condition0_2     Condition0_3     Condition1_1     Condition1_2     Condition1_3     Condition2_1     Condition2_2     Condition2_3     
Gene0  -> <missing>        <missing>        859.507048737706 892.488061131967 1018.39682842723 <missing>        1103.47465251202 1157.72940330711 1065.74060396554 
Gene1  -> 874.831680800388 750.248739657293 885.186911420285 928.994516057073 853.081858812674 793.574297701139 1065.97949919587 1131.14376992316 <missing>        
Gene2  -> 838.556912459832 852.727407339623 899.295260312015 860.880771705626 932.199854945633 976.124808642915 1207.93463145272 <missing>        1277.61049813247 
Gene3  -> 578.81785907921  678.347549342628 602.246497320338 <missing>        643.093516693419 <missing>        <missing>        873.194740469258 849.451122811244 
Gene4  -> 842.094396445274 965.835426665507 867.369051645365 928.252271146921 881.501122913359 <missing>        1054.1287942036  1171.60939846118 1038.00577431047 
Gene5  -> 1020.09691148753 1074.40387941314 1007.97548739644 1016.85273907176 1137.89035971088 1053.22697953361 1375.66060145121 1231.83519162636 <missing>        
Gene6  -> 1101.31859349101 1035.34541804719 1073.81849597601 1173.85556819786 1135.11445658909 1135.37014907268 1312.46683931566 <missing>        1446.11026206729 
Gene7  -> 1293.5505187121  1279.24240353059 1210.69733913481 1418.83379683658 1315.66861035805 1340.02039414327 1547.14933515457 1542.7958833035  1506.05595369617 
Gene8  -> 932.451969005451 943.887579432217 1064.35286448003 993.708988922016 1020.75857130752 1141.8439164254  1302.84589494999 <missing>        1255.55859138653 
Gene9  -> <missing>        676.324726723238 627.516574042796 <missing>        761.340619105394 629.926834913104 913.833973465211 <missing>        935.953193020724 
Gene10 -> <missing>        631.593373387394 <missing>        760.573132248994 667.777800663737 708.579020598344 897.652044466068 951.352427593893 913.498402976585 
Gene11 -> 925.558844182864 921.275745566886 962.402042467281 919.912081924523 915.817349871239 <missing>        1133.39251694594 1215.95999339307 1256.12477917909 
Gene12 -> 877.088860898347 910.78457773273  977.60432138044  906.470100177092 895.635227528066 974.138600172186 1268.46086169626 1130.47280685606 1209.22769248572 
Gene13 -> 961.944859271178 938.498328719872 913.620698710984 866.402054828119 906.174954450491 985.197102336624 1124.13083729644 1212.131809912   1159.25077296929 
Gene14 -> 992.748362800567 1000.19176657168 983.841273992796 1102.47481181182 1189.49999801473 1098.43197409232 1287.05128248142 1193.33301922455 <missing>        
:         ...              ...              ...              ...              ...              ...              ...              ...              ...              
Gene85 -> 1141.84782692372 966.934334466062 960.874704416693 1083.08973656227 1034.99233568037 1165.59614687963 1296.69301350431 1265.91311513118 <missing>        
Gene86 -> 709.392263094341 599.356231019707 627.809442533116 656.618659654456 693.650796020343 659.473041695018 852.316184386208 824.655405167439 925.919147678158 
Gene87 -> 899.380276781729 884.17260562817  948.935506964083 1089.52324524629 1029.65752699391 1003.33640042116 1298.44005521355 1280.59977722652 1241.62816145067 
Gene88 -> 1144.81738980837 1063.96798295389 1035.41837813454 1089.09832802759 <missing>        1201.22372291913 1403.27831423481 1289.29148231194 1310.98966263453 
Gene89 -> <missing>        1412.27615611229 1213.87168101546 1464.29266169994 1410.28662129759 1460.0814182168  1633.25421505257 1622.26533282371 1614.55971113835 
Gene90 -> 1380.11337491127 1298.94445749242 1388.80183781222 1380.04885949936 1464.39067804687 <missing>        1602.07971635588 1572.12371268329 1588.54863749936 
Gene91 -> 1104.4688200858  1044.62985634541 1038.52005763965 1118.68807975572 1079.12934076147 1110.47798847764 1357.74586648515 1341.72499952814 <missing>        
Gene92 -> 643.08246230498  713.608735692286 664.349154855986 804.005009357483 735.028682825565 715.584678733244 988.804126972969 <missing>        935.68406770922  
Gene93 -> 1066.41860092441 <missing>        1100.26729085649 1129.70531336959 1190.5905781972  1160.86694672781 1370.99671365522 1326.95197016386 1386.621278477   
Gene94 -> 842.568958216624 920.226880055378 824.776105482268 1000.45119277737 999.622914936843 926.209950863813 1179.08167586582 1186.13260877293 1151.99017404333 
Gene95 -> <missing>        776.852408021102 809.406302005126 866.770357211847 777.940357407953 868.312695316338 1039.8775076931  1072.75143664128 1095.87599329151 
Gene96 -> 736.95604192717  831.823622542142 790.627443848724 887.289779057259 781.461038651523 867.660284443528 932.981758186553 1042.45392008744 1149.56046307528 
Gene97 -> 979.147873857094 1033.86834107186 1010.60740727841 974.152107390665 1141.69306792765 1093.41903358936 1185.3882808851  1198.15294047248 1389.92530724036 
Gene98 -> 759.570384027805 661.370466127403 647.949680836865 831.520407212324 787.268819663521 855.916145637134 1018.7813832175  959.437629515552 1013.48894708169 
Gene99 -> <missing>        1170.12951077744 1103.50236480969 1212.87417318883 1219.28343069146 1184.0055742792  1340.62297540036 <missing>        1405.19376312643

Data imputation

Missing data is a constant companion of many data scientists. And it's not the best company, as missing values can introduce a substantial amount of bias, make the handling and analysis of the data more arduous, and create reductions in efficiency.

To tackle this, missing values can be substituted in a step called imputation. Different approaches for this exist. Here a k-nearest neighbour imputation is shown, which works as follows: For each observation with missing values, the k most similar other observations are chosen. Then the missing value of this observation is substituted by the mean of these values in the neighbouring observations.

open FSharp.Stats
open FSharp.Stats.ML

// Select the imputation method: kNearestImpute where the 2 nearest observations are considered
let kn : Impute.MatrixBaseImputation<float[],float> = Impute.kNearestImpute 2

// Impute the missing values using the "imputeBy" function. The values of the deedle frame are first transformed into the input type of this function.
let imputedData = 
    rawFrame 
    |> Frame.toJaggedArray 
    |> Impute.imputeBy kn Ops.isNan

// Creating a new frame from the old keys and the new imputed data
let imputedFrame = 
    Frame.ofJaggedArray imputedData
    |> Frame.indexRowsWith rawFrame.RowKeys
    |> Frame.indexColsWith rawFrame.ColumnKeys
Condition0_1      Condition0_2     Condition0_3      Condition1_1     Condition1_2       Condition1_3       Condition2_1     Condition2_2       Condition2_3      
Gene0  -> 815.0863716692485 834.177804837712 859.507048737706  892.488061131967 1018.39682842723   993.467661383195   1103.47465251202 1157.72940330711   1065.74060396554  
Gene1  -> 874.831680800388  750.248739657293 885.186911420285  928.994516057073 853.081858812674   793.574297701139   1065.97949919587 1131.14376992316   1097.76308399039  
Gene2  -> 838.556912459832  852.727407339623 899.295260312015  860.880771705626 932.199854945633   976.124808642915   1207.93463145272 1106.54977345808   1277.61049813247  
Gene3  -> 578.81785907921   678.347549342628 602.246497320338  650.900998152141 643.093516693419   662.8620463286804  871.917379913417 873.194740469258   849.451122811244  
Gene4  -> 842.094396445274  965.835426665507 867.369051645365  928.252271146921 881.501122913359   1009.0399679729114 1054.1287942036  1171.60939846118   1038.00577431047  
Gene5  -> 1020.09691148753  1074.40387941314 1007.97548739644  1016.85273907176 1137.89035971088   1053.22697953361   1375.66060145121 1231.83519162636   1258.40412114039  
Gene6  -> 1101.31859349101  1035.34541804719 1073.81849597601  1173.85556819786 1135.11445658909   1135.37014907268   1312.46683931566 1315.53219258206   1446.11026206729  
Gene7  -> 1293.5505187121   1279.24240353059 1210.69733913481  1418.83379683658 1315.66861035805   1340.02039414327   1547.14933515457 1542.7958833035    1506.05595369617  
Gene8  -> 932.451969005451  943.887579432217 1064.35286448003  993.708988922016 1020.75857130752   1141.8439164254    1302.84589494999 1219.183035179655  1255.55859138653  
Gene9  -> 735.2133784999505 676.324726723238 627.516574042796  650.900998152141 761.340619105394   629.926834913104   913.833973465211 845.062060254252   935.953193020724  
Gene10 -> 748.63186994741   631.593373387394 683.5207771870655 760.573132248994 667.777800663737   708.579020598344   897.652044466068 951.352427593893   913.498402976585  
Gene11 -> 925.558844182864  921.275745566886 962.402042467281  919.912081924523 915.817349871239   979.6678512544049  1133.39251694594 1215.95999339307   1256.12477917909  
Gene12 -> 877.088860898347  910.78457773273  977.60432138044   906.470100177092 895.635227528066   974.138600172186   1268.46086169626 1130.47280685606   1209.22769248572  
Gene13 -> 961.944859271178  938.498328719872 913.620698710984  866.402054828119 906.174954450491   985.197102336624   1124.13083729644 1212.131809912     1159.25077296929  
Gene14 -> 992.748362800567  1000.19176657168 983.841273992796  1102.47481181182 1189.49999801473   1098.43197409232   1287.05128248142 1193.33301922455   1353.28807884254  
:         ...               ...              ...               ...              ...                ...                ...              ...                ...               
Gene85 -> 1141.84782692372  966.934334466062 960.874704416693  1083.08973656227 1034.99233568037   1165.59614687963   1296.69301350431 1265.91311513118   1269.106757436075 
Gene86 -> 709.392263094341  599.356231019707 627.809442533116  656.618659654456 693.650796020343   659.473041695018   852.316184386208 824.655405167439   925.919147678158  
Gene87 -> 899.380276781729  884.17260562817  948.935506964083  1089.52324524629 1029.65752699391   1003.33640042116   1298.44005521355 1280.59977722652   1241.62816145067  
Gene88 -> 1144.81738980837  1063.96798295389 1035.41837813454  1089.09832802759 1095.4373870826148 1201.22372291913   1403.27831423481 1289.29148231194   1310.98966263453  
Gene89 -> 1336.03815552525  1412.27615611229 1213.87168101546  1464.29266169994 1410.28662129759   1460.0814182168    1633.25421505257 1622.26533282371   1614.55971113835  
Gene90 -> 1380.11337491127  1298.94445749242 1388.80183781222  1380.04885949936 1464.39067804687   1407.121461949345  1602.07971635588 1572.12371268329   1588.54863749936  
Gene91 -> 1104.4688200858   1044.62985634541 1038.52005763965  1118.68807975572 1079.12934076147   1110.47798847764   1357.74586648515 1341.72499952814   1258.40412114039  
Gene92 -> 643.08246230498   713.608735692286 664.349154855986  804.005009357483 735.028682825565   715.584678733244   988.804126972969 994.4828305630385  935.68406770922   
Gene93 -> 1066.41860092441  1131.85550949513 1100.26729085649  1129.70531336959 1190.5905781972    1160.86694672781   1370.99671365522 1326.95197016386   1386.621278477    
Gene94 -> 842.568958216624  920.226880055378 824.776105482268  1000.45119277737 999.622914936843   926.209950863813   1179.08167586582 1186.13260877293   1151.99017404333  
Gene95 -> 808.7914067089065 776.852408021102 809.406302005126  866.770357211847 777.940357407953   868.312695316338   1039.8775076931  1072.75143664128   1095.87599329151  
Gene96 -> 736.95604192717   831.823622542142 790.627443848724  887.289779057259 781.461038651523   867.660284443528   932.981758186553 1042.45392008744   1149.56046307528  
Gene97 -> 979.147873857094  1033.86834107186 1010.60740727841  974.152107390665 1141.69306792765   1093.41903358936   1185.3882808851  1198.15294047248   1389.92530724036  
Gene98 -> 759.570384027805  661.370466127403 647.949680836865  831.520407212324 787.268819663521   855.916145637134   1018.7813832175  959.437629515552   1013.48894708169  
Gene99 -> 1162.515191125715 1170.12951077744 1103.50236480969  1212.87417318883 1219.28343069146   1184.0055742792    1340.62297540036 1368.7660061523002 1405.19376312643

Hierarchical clustering

To sort the level of closeness between samples, we perform a hierarchical clustering. Details about this can be found here and here.

open FSharp.Stats.ML.Unsupervised

// Retreive the sample columns from the frame
let samples = 
    imputedFrame
    |> Frame.getNumericCols
    |> Series.observations
    |> Seq.map (fun (k,vs) -> 
        k,
        vs
        |> Series.values
    )

// Run the hierarchical clustering on the samples
// The clustering is performed on labeled samples (name,values) so that these labels later appear in the cluster tree
let clustering = 
    HierarchicalClustering.generate 
        (fun (name1,values1) (name2,values2) -> DistanceMetrics.euclidean values1 values2) // perform the distance calculation only on the values, not the labels
        HierarchicalClustering.Linker.wardLwLinker
        samples
    |> HierarchicalClustering.mapClusterLeaftags fst // only keep the labels in the cluster tree
Node
  (16, 7262.367644, 9,
   Node
     (15, 1317.505683, 6,
      Node
        (14, 765.0062545, 3,
         Node
           (13, 750.1592066, 2, Leaf (3, 1, "Condition1_1"),
            Leaf (5, 1, "Condition1_3")), Leaf (4, 1, "Condition1_2")),
      Node
        (11, 744.3808016, 3,
         Node
           (9, 684.1625739, 2, Leaf (0, 1, "Condition0_1"),
            Leaf (1, 1, "Condition0_2")), Leaf (2, 1, "Condition0_3"))),
   Node
     (12, 745.2649938, 3,
      Node
        (10, 701.3010992, 2, Leaf (6, 1, "Condition2_1"),
         Leaf (7, 1, "Condition2_2")), Leaf (8, 1, "Condition2_3")))

Data visualization

Finally, the clustering results can be visualized to check for replicate clustering. For this we use Cyjs.NET, an FsLab library which makes use of the Cytoscape.js network visualization tool.

Further information about styling the graphs can be found here.

open Cyjs.NET

// Function for flattening the cluster tree to an edgelist
let hClustToEdgeList (f : int -> 'T) (hClust : HierarchicalClustering.Cluster<'T>) =
    let rec loop (d,nodeLabel) cluster=
        match cluster with
        | HierarchicalClustering.Node (id,dist,_,c1,c2) ->
            let t = f id
            loop (dist,t) c1
            |> List.append (loop (dist,t) c2)
            |> List.append [nodeLabel,t,d] 
        | HierarchicalClustering.Leaf (_,_,label)-> [(nodeLabel,label,d)]
    loop (0., f 0) hClust

let rawEdgeList = hClustToEdgeList (string) clustering

// The styled vertices, samnples are coloured based on the condition they belong to. So replicates of one condition have the same colour
let cytoVertices = 
    rawEdgeList
    |> List.collect (fun (v1,v2,w) ->
        [v1;v2]
    )
    |> List.distinct
    |> List.map (fun v -> 
        let label,color,size = 
            match v.Split '_' with
            | [|"Condition0";_|] -> "Condition0", "#6FB1FC","40"
            | [|"Condition1";_|] -> "Condition1", "#EDA1ED","40"
            | [|"Condition2";_|] -> "Condition2", "#F5A45D","40"
            | _ -> "","#DDDDDD","10"

        let styling = [CyParam.label label; CyParam.color color; CyParam.width size]
        Elements.node (v) styling
    )

// Helper function to transform the distances between samples to weights
let distanceToWeight = 
    let max = rawEdgeList |> List.map (fun (a,b,c) -> c) |> List.max
    fun distance -> 1. - (distance / max)   


// Styled edges
let cytoEdges = 
    rawEdgeList
    |> List.mapi (fun i (v1,v2,weight) -> 
        let styling = [CyParam.weight (distanceToWeight weight)]
        Elements.edge ("e" + string i) v1 v2 styling
    )

// Resulting cytograph
let cytoGraph = 

    CyGraph.initEmpty ()
    |> CyGraph.withElements cytoVertices
    |> CyGraph.withElements cytoEdges
    |> CyGraph.withStyle "node" 
        [
            CyParam.content =. CyParam.label
            CyParam.shape =. CyParam.shape
            CyParam.color =. CyParam.color
            CyParam.width =. CyParam.width
        ]
    |> CyGraph.withLayout (Layout.initCose (id))  
// Send the cytograph to the browser
cytoGraph
|> CyGraph.show
No value returned by any evaluator

Interpretation

As can be seen in the graph, replicates of one condition cluster together. This is a good sign for the quality of the experiment. If one replicate of a condition does not behave this way, it can be considered an outlier. If the replicates don't cluster together at all, there might be some problems with the experiment.

namespace Deedle
namespace Deedle.Internal
type IFsiFormattable = abstract member Format : unit -> string
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Data

--------------------
namespace Microsoft.FSharp.Data
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 rawFrame : Frame<string,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>
Multiple items
val string : value:'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>


--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
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>
val indexRows : column:'C -> frame:Frame<'R1,'C> -> Frame<'R2,'C> (requires equality and equality and 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)
namespace FSharp.Stats
namespace FSharp.Stats.ML
val kn : Impute.MatrixBaseImputation<float [],float>
module Impute from FSharp.Stats.ML
<summary> Module for data imputation and missing value filtering </summary>
type MatrixBaseImputation<'a,'b> = seq<'a> -> 'a -> int -> 'b
<summary> Type definintion for a vector based imputation The imputed values are based on the given whole dataset </summary>
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>
val kNearestImpute : k:int -> data:seq<float []> -> arr:float [] -> index:int -> float
<summary> Imputation by k-nearest neighbour </summary>
val imputedData : float [] []
val toJaggedArray : frame:Frame<'R,'C> -> float [] [] (requires equality and equality)
val imputeBy : impute:Impute.MatrixBaseImputation<'a [],'a> -> isMissing:('a -> bool) -> data:seq<#seq<'a>> -> 'a [] []
<summary> Imputes rows by matrix-based imputation </summary>
module Ops from FSharp.Stats
<summary> Operations module (automatically opened) </summary>
val isNan : num:'b -> bool (requires equality)
<summary> Returs true if x is nan (generics) equality </summary>
val imputedFrame : Frame<string,string>
static member Frame.ofJaggedArray : jArray:'T [] [] -> Frame<int,int>
val indexRowsWith : keys:seq<'R2> -> frame:Frame<'R1,'C> -> Frame<'R2,'C> (requires equality and equality and equality)
property Frame.RowKeys: seq<string> with get
val indexColsWith : keys:seq<'C2> -> frame:Frame<'R,'C1> -> Frame<'R,'C2> (requires equality and equality and equality)
property Frame.ColumnKeys: seq<string> with get
namespace FSharp.Stats.ML.Unsupervised
val samples : seq<string * seq<float>>
val getNumericCols : frame:Frame<'R,'C> -> Series<'C,Series<'R,float>> (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 observations : series:Series<'K,'T> -> seq<'K * 'T> (requires equality)
Multiple items
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 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>
val k : string
val vs : Series<string,float>
val values : series:Series<'K,'T> -> seq<'T> (requires equality)
val clustering : HierarchicalClustering.Cluster<string>
module HierarchicalClustering from FSharp.Stats.ML.Unsupervised
<summary> Agglomerative hierarchical clustering </summary>
val generate : distance:DistanceMetrics.Distance<'T> -> linker:HierarchicalClustering.Linker.LancWilliamsLinker -> data:seq<'T> -> HierarchicalClustering.Cluster<'T>
<summary> Builds a hierarchy of clusters of data containing cluster labels </summary>
val name1 : string
val values1 : seq<float>
val name2 : string
val values2 : seq<float>
module DistanceMetrics from FSharp.Stats.ML
<summary> Functions for computing distances of elements or sets </summary>
val euclidean : s1:seq<'a> -> s2:seq<'a> -> 'c (requires member ( - ) and member get_Zero and member ( + ) and member Sqrt and member ( * ))
<summary> Euclidean distance of two coordinate sequences </summary>
module Linker from FSharp.Stats.ML.Unsupervised.HierarchicalClustering
<summary> The linkage criterion determines the distance between sets of observations as a function of the pairwise distances between observations </summary>
val wardLwLinker : int * int * int -> dAB:float -> dAC:float -> dBC:float -> float
<summary> Ward linkage criterion (UPGMA) Calculates the d(A u B, C) </summary>
val mapClusterLeaftags : mapF:('T -> 'U) -> cluster:HierarchicalClustering.Cluster<'T> -> HierarchicalClustering.Cluster<'U>
<summary> Maps the tags of the leafs of the cluster by applying a given mapping function </summary>
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>
namespace Cyjs
namespace Cyjs.NET
val hClustToEdgeList : f:(int -> 'T) -> hClust:HierarchicalClustering.Cluster<'T> -> ('T * 'T * float) list
val f : (int -> 'T)
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 hClust : HierarchicalClustering.Cluster<'T>
type Cluster<'T> = | Node of int * float * int * Cluster<'T> * Cluster<'T> | Leaf of int * int * 'T
<summary> Binary distance tree </summary>
val loop : (float * 'T -> HierarchicalClustering.Cluster<'T> -> ('T * 'T * float) list)
val d : float
val nodeLabel : 'T
val cluster : HierarchicalClustering.Cluster<'T>
union case HierarchicalClustering.Cluster.Node: int * float * int * HierarchicalClustering.Cluster<'T> * HierarchicalClustering.Cluster<'T> -> HierarchicalClustering.Cluster<'T>
<summary> ID * distance * leafCount * cluster left * cluster right </summary>
val id : int
val dist : float
val c1 : HierarchicalClustering.Cluster<'T>
val c2 : HierarchicalClustering.Cluster<'T>
val t : 'T
Multiple items
module List from FSharp.Stats
<summary> Module to compute common statistical measure on list </summary>

--------------------
module List from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.list`1" />.</summary>
<namespacedoc><summary>Operations for collections such as lists, arrays, sets, maps and sequences. See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/fsharp-collection-types">F# Collection Types</a> in the F# Language Guide. </summary></namespacedoc>


--------------------
type List<'T> = | ( [] ) | ( :: ) of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex : rank:int * offset:int -> int member GetSlice : startIndex:int option * endIndex:int option -> 'T list static member Cons : head:'T * tail:'T list -> 'T list member Head : 'T member IsEmpty : bool member Item : index:int -> 'T with get ...
<summary>The type of immutable singly-linked lists.</summary>
<remarks>Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or the notation <c>[1;2;3]</c>. Use the values in the <c>List</c> module to manipulate values of this type, or pattern match against the values directly. </remarks>
<exclude />
val append : list1:'T list -> list2:'T list -> 'T list
<summary>Returns a new list that contains the elements of the first list followed by elements of the second.</summary>
<param name="list1">The first input list.</param>
<param name="list2">The second input list.</param>
<returns>The resulting list.</returns>
union case HierarchicalClustering.Cluster.Leaf: int * int * 'T -> HierarchicalClustering.Cluster<'T>
<summary> ID * leafCount * Tag </summary>
val label : 'T
val rawEdgeList : (string * string * float) list
val cytoVertices : Elements.Node list
val collect : mapping:('T -> 'U list) -> list:'T list -> 'U list
<summary>For each element of the list, applies the given function. Concatenates all the results and return the combined list.</summary>
<param name="mapping">The function to transform each input element into a sublist to be concatenated.</param>
<param name="list">The input list.</param>
<returns>The concatenation of the transformed sublists.</returns>
val v1 : string
val v2 : string
val w : float
val distinct : list:'T list -> 'T list (requires equality)
<summary>Returns a list that contains no duplicate entries according to generic hash and equality comparisons on the entries. If an element occurs multiple times in the list then the later occurrences are discarded.</summary>
<param name="list">The input list.</param>
<returns>The result list.</returns>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
<summary>Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection.</summary>
<param name="mapping">The function to transform elements from the input list.</param>
<param name="list">The input list.</param>
<returns>The list of transformed elements.</returns>
val v : string
val label : string
val color : string
val size : string
System.String.Split([<System.ParamArray>] separator: char []) : string []
System.String.Split(separator: string [], options: System.StringSplitOptions) : string []
System.String.Split(separator: string,?options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], count: int) : string []
System.String.Split(separator: char,?options: System.StringSplitOptions) : string []
System.String.Split(separator: string [], count: int, options: System.StringSplitOptions) : string []
System.String.Split(separator: string, count: int,?options: System.StringSplitOptions) : string []
System.String.Split(separator: char [], count: int, options: System.StringSplitOptions) : string []
System.String.Split(separator: char, count: int,?options: System.StringSplitOptions) : string []
val styling : CyParam.CyStyleParam list
module CyParam from Cyjs.NET
val label : v:'a -> CyParam.CyStyleParam
val color : v:'a -> CyParam.CyStyleParam
val width : v:'a -> CyParam.CyStyleParam
module Elements from Cyjs.NET
val node : id:string -> dataAttributes:CyParam.CyStyleParam list -> Elements.Node
val distanceToWeight : (float -> float)
val max : float
val a : string
val b : string
val c : float
val max : list:'T list -> 'T (requires comparison)
<summary>Return the greatest of all elements of the list, compared via Operators.max.</summary>
<remarks>Raises <see cref="T:System.ArgumentException" /> if <c>list</c> is empty</remarks>
<param name="list">The input list.</param>
<exception cref="T:System.ArgumentException">Thrown when the list is empty.</exception>
<returns>The maximum element.</returns>
val distance : float
val cytoEdges : Elements.Edge list
val mapi : mapping:(int -> 'T -> 'U) -> list:'T list -> 'U list
<summary>Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection. The integer index passed to the function indicates the index (from 0) of element being transformed.</summary>
<param name="mapping">The function to transform elements and their indices.</param>
<param name="list">The input list.</param>
<returns>The list of transformed elements.</returns>
val i : int
val weight : float
val weight : v:'a -> CyParam.CyStyleParam
val edge : id:string -> sourceId:string -> targetId:string -> dataAttributes:CyParam.CyStyleParam list -> Elements.Edge
val cytoGraph : CyGraph.CyGraph
module CyGraph from Cyjs.NET
val initEmpty : unit -> CytoscapeModel.Cytoscape
val withElements : elems:seq<CytoscapeModel.Element> -> cy:CyGraph.CyGraph -> CyGraph.CyGraph
val withStyle : selector:string -> cyStyles:seq<CyParam.CyStyleParam> -> cy:CyGraph.CyGraph -> CyGraph.CyGraph
val content : v:'a -> CyParam.CyStyleParam
val shape : v:'a -> CyParam.CyStyleParam
val withLayout : ly:Layout -> cy:CyGraph.CyGraph -> CyGraph.CyGraph
Multiple items
module Layout from Cyjs.NET

--------------------
type Layout = inherit DynamicObj new : name:string -> Layout member name : string
<summary> Layout type inherits from dynamic object </summary>

--------------------
new : name:string -> Layout
val initCose : applyOption:(Layout -> Layout) -> Layout
<summary> initializes a layout of type "cose" applying the givin layout option function. The cose (Compound Spring Embedder) layout uses a physics simulation to lay out graphs. </summary>
val id : x:'T -> 'T
<summary>The identity function</summary>
<param name="x">The input value.</param>
<returns>The same value.</returns>
val withSize : width:int * height:int -> cy:CyGraph.CyGraph -> CyGraph.CyGraph
module HTML from Cyjs.NET
<summary> HTML template for Cytoscape </summary>
val toEmbeddedHTML : cy:CytoscapeModel.Cytoscape -> string
<summary> Converts a CyGraph to it HTML representation and embeds it into a html page. </summary>