c# - 如何使用 Deedle 进行基于行的处理(帧输入和帧输出)

标签 c# f# functional-programming deedle

我正在尝试使用 Deedle 在 DataFrame 上执行基于行的处理。但我就是无法让自己的思想适应迪德尔的方式。

对于像这样的框架来说

    Indicator1 Indicator2
1   100        200
2   300        500
3   -200       1000

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

  1. 如果指标值小于 500 且大于 0,则乘以 1.1
  2. 如果指标值小于0,则设为NaN

我一直在尝试使用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# 二维数组执行此操作的命令式(而且非常简单)方法是

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

例如 如果 Indicator1 小于 300,则新 Indicator2 值为 Indicator2 + 5% * Indicator1

我需要使用

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

上面的伪代码听起来很简单,但我只是可以弄清楚如何重现正确的 objectSeries 来重新创建框架。

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

更新

自从最初的问题发布以来,我就在 C# 中使用了 Deedle。令我惊讶的是,在 C# 中基于行的计算非常简单,并且 C# Frame.rows 函数处理缺失值的方式与 F# mapRows 函数非常不同。以下是我用来尝试并验证逻辑的一个非常基本的示例。它可能对任何正在搜索类似应用程序的人有用:

需要注意的是: 1. rows 函数没有删除行,而两列的值都缺失 2. Mean 函数足够智能,可以根据可用数据点计算平均值。

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();
        }
    }
}

最佳答案

您可以使用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 

关于c# - 如何使用 Deedle 进行基于行的处理(帧输入和帧输出),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26012029/

相关文章:

c# - 使用 C# 在 Selenium 中使用 SwitchTo() 框架

f# - 在F#中实现约束数字类型的习语/实践?

f# - F# 命名约定是否禁止在不同光盘中使用相同的名称。工会类型?

f# - PostAndReply 在已处理的 MailboxProcessor 上

scala - 双冒号(或冒号-冒号)::在 Scala 中是什么意思?

c# - 异步函数阻止我的 wpf 应用程序

c# - CrossMediaManager.Current.Play 不在 iOS xamarin.forms 上播放本地音频文件

C#/.NET : Creating Dynamic Visuals in C#

java - 在 MongoDB 中对文档使用 forEach

r - 创建、命名、存储和汇总模型的编程方式