[英]What is the most idiomatic style to force a computation using Sequences in f#?
[英]Accessing entries in a csv files for computation F#
如何访问csv文件中的条目以便在F#中对它们执行计算?
我可以用通常的方式将csv文件读入内存,但是一旦我被卡住了。
理想情况下,我只需从列创建数组,然后使用array.map2执行计算。
所以我的数组1是一些网站使用指标,第2列是达到第1列中的值的用户数(比如对网站进行6次访问)我们可以通过乘以数组中的每个条目来计算平均访问次数第1列,由第2列组成的数组,除以第2列的array.sum。
我在F#片段http://fssnip.net/3T上尝试了csv to Array代码,但它为我生成了一系列字符串元组。
有谁能建议更好的方法?
编辑:一些示例输入将类似于: -
Visits Count
1 8
2 9
3 5
4 3
5 2
6 1
7 1
10 1
输出将返回数据的平均值,在这种情况下为2.87(小数点后2位)。
编辑2:从我发现的CSV到阵列代码的当前输出是这个
val it : seq<BookWindow> =
seq [{Visits = 1;
Count = 8;}; {Visits = 2;
Count = 9;}; {Visits = 3;
Count = 5;}; {Visits = 4;
Count = 3;}; ...]
这对计算没那么有用......
我所做的是创建一个记录类型,以便我可以使用强类型操作,然后像下面的代码一样快速地将文本文件读入seq<myRecord>
。 如果我打算稍后重用它,我通常会将该方法作为static member fromFile
移动到记录中。 如果你像我一样使用大型文本文件,seq非常有用,它以这种方式使用非常少的内存。
编辑这个更干净:
open System.IO
type myRecord = {
Visits: int
Count: int
} with
static member fromFile file =
file
|> File.ReadLines // expose as seq<string>
|> Seq.skip 1 // skip headers
|> Seq.map (fun s-> s.Split '\t') // split each line into array
|> Seq.map (fun a -> {Visits=int a.[0]; Count=int a.[1]}) // and create record
myRecord.fromFile @"D:\data.csv"
|> Seq.fold (fun (tv, tc) r -> (tv+r.Visits*r.Count, tc+r.Count))(0,0)
|> (fun t -> float (fst t) / float (snd t))
//val mean : float = 2.866666667
值得补充的是,使用F#3.0类型的提供程序,访问CSV文件变得更加简单。 类型提供程序可以在编译期间静态查看CSV数据,并生成表示列的类型(如BookWindow
),然后它会推断各列的数据类型。
例如,在新版本的Try F#网站上查看“财务建模”下的“使用Yahoo财务类型提供程序”一文。 你可以这样写:
#r "Samples.Csv.dll"
// Type provider that generates schema based on CSV file located online
[<Literal>]
let url = "http://ichart.finance.yahoo.com/table.csv?s=MSFT"
let msft = new Samples.FSharp.CsvProvider.MiniCsv<url>()
// The provider automatically infers the structure and we
// can access columns as properties of the 'row' object
for row in msft.Data do
printfn "%A %f" row.Date row.Close
据我所知,最新公开版本的CSV提供程序位于F#3.0示例包中 。 我有一个可能更好的版本,也可以处理我的GitHub仓库上的类型推断。
将数据存储到内存后,可以使用标准F#函数进行计算。 例如,要计算平均收盘价格(您可以尝试尝试F#),您可以写:
Seq.average [ for row in msft.Data -> row.Close ]
这会生成一个只有收盘价的清单,然后在数字上调用标准平均函数。
你可能过于复杂,这不是最干净的解决方案,但你仍然可以使用你拥有的东西。 将BookWindow类型映射到单独的数组中,如果这提供了一种很好的计算方法。
type BookWindow = { Visits: int
Count: int }
// Sample data
let list = [|{Visits = 1; Count = 8;}; {Visits = 2; Count = 9;}; {Visits = 3; Count = 5;}|]
let visitcol = list |> Array.map (fun r -> r.Visits)
let countcol = list |> Array.map (fun r -> r.Count)
Array.map2( fun v c -> v * c) visitcol countcol
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.