如何访问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;}; ...]
对计算来说没那么有用......
答案 0 :(得分:6)
我所做的是创建一个记录类型,以便稍后可以使用强类型操作,然后像下面的代码一样快速地将文本文件读入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
答案 1 :(得分:6)
值得补充的是,使用F#3.0类型的提供程序,访问CSV文件变得更加简单。类型提供程序可以在编译期间静态查看CSV数据,并生成表示列的类型(如BookWindow
),然后它会推断各列的数据类型。
例如,请查看new version of Try F# web site上“财务建模”下的“使用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 Sample Pack。我有一个可能更好的版本,它也处理my GitHub repo上的类型推断。
在内存中存储数据后,您可以使用标准F#函数进行计算。例如,要计算平均收盘价格(您可以尝试尝试F#),您可以写:
Seq.average [ for row in msft.Data -> row.Close ]
这会生成一个只有收盘价的清单,然后在数字上调用标准平均函数。
答案 2 :(得分:2)
你可能过于复杂了,这不是最干净的解决方案,但你仍然可以使用你拥有的东西。将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