anchor.diff:  open Accord.Statistics.Models.Regression.Linear
   open Iveonik.Stemmers
   open FSharp.Collections.ParallelSeq
  +open System.Collections.Concurrent
   
   type Train = CsvProvider<"../data/train.csv">
   let train = Train.GetSample()
  
positive.code: //0.50783 - kaggle reported from stemmed
  //0.5063 - string contains
  
  let testInput = 
      test.Rows 
      |> Seq.map (fun w ->
          stemmedWordMatch
            w.Search_term
            w.Product_title
            (productDescription w.Product_uid)
            (attribs w.Product_uid)
            (brandName w.Product_uid))
      |> Seq.toArray
  
  let testOutput = target.Compute(testInput)
  let inline bracket n = Math.Max(1., Math.Min(3., n))
  let testOutput' = testOutput |> Seq.map bracket
  
  let submission = 
      Seq.zip test.Rows testOutput'
      |> Seq.map (fun (r,o) -> sprintf "%A,%A" r.Id o)
      |> Seq.toList
  let outputPath = __SOURCE_DIRECTORY__ + @"../../data/benchmark_submission_FSharp.csv"
  File.WriteAllLines(outputPath, "id,relevance" :: submission)
  
negative.code: 
  let isStemmedMatch input word =
      let word' = stem word |> Regex.Escape // TODO strip punctuation?
      Regex.IsMatch(stemWords input, sprintf @"\b%s" word', RegexOptions.IgnoreCase)
  let stemmedWordMatch = features isStemmedMatch
  
  let stringContainsMatch = features containedIn
  
  printfn "Extracting training features..."
  let trainInput = 
      train.Rows
      |> PSeq.ordered
      |> PSeq.map (fun w ->
          stemmedWordMatch
            w.Search_term
            w.Product_title
            (productDescription w.Product_uid)
            (attribs w.Product_uid)
            (brandName w.Product_uid))
      |> PSeq.toArray
  
  let trainOutput = 
      train.Rows
      |> Seq.map (fun t -> float t.Relevance)
      |> Seq.toArray
  
  printfn "Regressing..."
  let target = MultipleLinearRegression(11, true)
  let sumOfSquaredErrors = target.Regress(trainInput, trainOutput)
  let observationCount = trainInput |> Seq.length |> float
  let sme = sumOfSquaredErrors / observationCount
  let rsme = sqrt(sme)
  //0.48917 - stem all words for comparison
  //0.48940 - added title & desc length feature
  //0.49059 - added desc word match ratio
  //0.49080 - added title word match ratio
  