如何使用Deedle(Frame in和Frame out)执行基于行的进程

时间:2014-09-24 08:23:24

标签: c# f# functional-programming deedle

我正在尝试使用Deedle在DataFrame上执行基于行的处理。但是我无法将我的思维调到Deedle的方式。

说像

这样的框架
    Indicator1 Indicator2
1   100        200
2   300        500
3   -200       1000

假设需要对每个指标应用一些规则:

  1. 如果指标值小于500且大于0,则乘以1.1
  2. 如果指标值小于0,则将其设为NaN
  3. 我一直在尝试使用Frame.mapRow ....函数。

    我知道我可以使用

    fun v -> let indVal = v.GetAs<Int>("Indicator1");
             let newIndVal = match indVal with 
                             |...... logic  
                             |...... some other logic
             let indVal2 = v.GetAs<Int>("Indicator2");
             let newIndVal2 = match indVal2 with 
                             |...... logic  
                             |...... some other logic  
    

    使用Frame.mapRow ....

    但我仍然坚持如何让newIndValnewIndVal2重新进入一行并最终回到新的数据框。

    我想要实现的是框架和框架输出。此外,我只知道逐个处理列(在通过索引或名称检索它们之后)。如果要应用的逻辑是通用的,有没有办法不将一列逻辑应用于一列?

    使用C或C#2d数组执行此操作的必要(并且非常简单)是

    loop through the row dimension
        loop through the column dimension
             apply the rule as the side effect to the array[row,col]
    

    如何在Deedle实现这一目标?

    更新

    如果计算不需要引用同一行中的其他列,那么Leaf Garland的建议很有用。对于我的情况,我需要逐行查看数据,因此我想使用Frame.mapRows。我应该清楚简化要求:

    说像

    这样的框架
        Indicator1 Indicator2
    1   100        200
    2   <Missing>  500
    3   -200       1000
    4   100        <Missing>
    5   <Missing>  500
    6   -200       100
    

    例如 如果指标1小于300,则新指标2值为指标2 + 5%*指标1

    我需要使用

    mapRows fun k v -> let var1 = v.get("Indicator1")
                       let var2 = v.get("Indicator2")
                       run through the conditions and produce new var1 and var2
                       produce a objectSeries
    |> Frame.ofRows
    

    上面的pesudo代码听起来很简单,但我可以弄清楚如何重现一个合适的objectSeries来重新创建Frame。

    我也注意到了我无法用mapRows函数解释的东西[问题]:Deedle Frame.mapRows how to properly use it and how to construct objectseries properly

    更新

    自从发布原始问题以来,我已经在C#中使用了Deedle。令我惊讶的是,基于行的计算在C#中非常容易,并且C#Frame.rows函数处理缺失值的方式与F#mapRows函数非常不同。以下是我用来尝试和实现逻辑的一个非常基本的例子。它可能对搜索类似应用程序的人有用:

    需要注意的事项是: 1.行的功能并没有删除行,而两列都是&#39;价值缺失 2.平均函数足够智能,可根据可用数据点计算平均值。

    using System.Text;
    using System.Threading.Tasks;
    using Deedle;
    
    namespace TestDeedleRowProcessWithMissingValues
    {
        class Program
        {
            static void Main(string[] args)
            {
                var s1 = new SeriesBuilder<DateTime, double>(){
                     {DateTime.Today.Date.AddDays(-5),10.0},
                     {DateTime.Today.Date.AddDays(-4),9.0},
                     {DateTime.Today.Date.AddDays(-3),8.0},
                     {DateTime.Today.Date.AddDays(-2),double.NaN},
                     {DateTime.Today.Date.AddDays(-1),6.0},
                     {DateTime.Today.Date.AddDays(-0),5.0}
                 }.Series;
    
                var s2 = new SeriesBuilder<DateTime, double>(){
                     {DateTime.Today.Date.AddDays(-5),10.0},
                     {DateTime.Today.Date.AddDays(-4),double.NaN},
                     {DateTime.Today.Date.AddDays(-3),8.0},
                     {DateTime.Today.Date.AddDays(-2),double.NaN},
                     {DateTime.Today.Date.AddDays(-1),6.0}                 
                 }.Series;
    
                var f = Frame.FromColumns(new KeyValuePair<string, Series<DateTime, double>>[] { 
                    KeyValue.Create("s1",s1),
                    KeyValue.Create("s2",s2)
                });
    
                s1.Print();
                f.Print();
    
    
                f.Rows.Select(kvp => kvp.Value).Print();
    
    //            29/05/2015 12:00:00 AM -> series [ s1 => 10; s2 => 10]
    //            30/05/2015 12:00:00 AM -> series [ s1 => 9; s2 => <missing>]
    //            31/05/2015 12:00:00 AM -> series [ s1 => 8; s2 => 8]
    //            1/06/2015 12:00:00 AM  -> series [ s1 => <missing>; s2 => <missing>]
    //            2/06/2015 12:00:00 AM  -> series [ s1 => 6; s2 => 6]
    //            3/06/2015 12:00:00 AM  -> series [ s1 => 5; s2 => <missing>]
    
    
                f.Rows.Select(kvp => kvp.Value.As<double>().Mean()).Print();
    
    //            29/05/2015 12:00:00 AM -> 10
    //            30/05/2015 12:00:00 AM -> 9
    //            31/05/2015 12:00:00 AM -> 8
    //            1/06/2015 12:00:00 AM  -> <missing>
    //            2/06/2015 12:00:00 AM  -> 6
    //            3/06/2015 12:00:00 AM  -> 5
    
    
                //Console.ReadLine();
            }
        }
    }
    

1 个答案:

答案 0 :(得分:2)

您可以使用Frame.mapValues映射框架中的所有值。为它提供一个获取数据类型并返回更新值的函数。

let indicator1 = [100.0;300.0;-200.0] |> Series.ofValues
let indicator2 = [200.0;500.0;1000.0] |> Series.ofValues

let frame = Frame.ofColumns ["indicator1" => indicator1; "indicator2" => indicator2]
// val frame : Frame<int,string> =
// 
//     indicator1 indicator2
// 0 -> 100        200       
// 1 -> 300        500       
// 2 -> -200       1000     

let update v =
  match v with
  |v when v<500.0 && v>0.0 -> v * 1.1
  |v when v<0.0 -> nan
  |v -> v

let newFrame = frame |> Frame.mapValues update
// val newFrame : Frame<int,string> =
//  
//      indicator1 indicator2
// 0 -> 110        220       
// 1 -> 330        500       
// 2 -> <missing>  1000