2013-10-07 55 views
1

我有以下数据:组,和与加权平均F#

let data = [(41609.00 , 10000., 3.822); (41609.00, 60000., 3.857); (41974.00 , 20000., 4.723); (41974.00, 30000., 3.22); (41974.00 , 4000., 4.655); (42339.00, 7000., 4.22); (42339.00 , 5000., 3.33)] 

拳头柱= OADate,第二=体积,第三=价格。

我现在想按日期分组,计算总量并计算加权平均价格。这是我到目前为止:

let aggr data = 
    data 
    //Multiply second and third column element by element 
    |> Seq.map (fun (a, b, c) -> (a, b, b * c)) 
    //Group by first column 
    |> Seq.groupBy fst 
    //Sum column 2 & 3 based on group of column 1 
    |> Seq.map (fun (d, e, f) -> (d, e |> Seq.sum, f |> Seq.sum)) 
    //take the sum and grouped column 1 & 2 and compute weighted average of the third 
    |> Seq.map (fun (g, h, i) -> (g, h, i/h)) 

我得到一个类型不匹配的元组有不同的长度。我以前使用类似的语法没有问题。 任何人都可以请我指出正确的方向?

UPDATE:

如果有人有兴趣的解决方案是:多亏了托马斯和叶

let aggr data = 
data 
|> Seq.map (fun (a, b, c) -> (a, b, b * c)) 
|> Seq.groupBy (fun (a, b, c) -> a) 
|> Seq.map (fun (key, group) -> group |> Seq.reduce (fun (a, b, c) (x, y, z) -> a, b+y , c+z)) 
|> Seq.map (fun (g, h, i) -> (g, h, i/h)) 
+0

可能会对此感兴趣的相关问题:http://stackoverflow.com/q/2328697/11410 – Benjol

回答

3

在代码中的第一个问题是,你正在呼吁Seq.groupByfst作为参数。这不起作用,因为fst是返回两元素元组的第一个元素的函数,但是您的输入是三元元组。遗憾的是,该功能对任何元组都不起作用。您需要编写一个选择三个中第一个值的lambda:

(...) 
|> Seq.groupBy (fun (a, b, c) -> a) 

接下来的问题是下一步的映射。分组产生一个元组列表,其中包含作为第一个元素的键(time)和包含原始输入序列中元素列表的组(在你的情况下是三元元组)。要与组中的所有第二组分的总和一起返回键,你可以写:

(...) 
|> Seq.map (fun (key, group) -> key, group |> Seq.sumBy (fun (_, v, _) -> v)) 

我不能完全确定要与第二和第三列做什么,但是这应该给你知道如何继续。

+0

另外,我一直在研究时间序列和数据框操作的库,这可能会使这更容易。如果您有兴趣,请查看https://github.com/BlueMountainCapital/FSharp.DataFrame和http://bluemountaincapital.github.io/FSharp.DataFrame/。 –

+0

感谢Tomas。这是否意味着如果我想通过hte键来求和snd和trd列,我需要在两行中做到这一点?此外,最后一个Seq.map也存在问题。任何想法? – nik

+0

你总是可以用多个键返回一个元组 - 在第二个片段中,我刚刚返回了组的键和值,但是你可以扩展它并返回其他东西(第三列的总和?)我认为它应该工作一次你做吧。 –