You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ML.NET中为IDataView添加多个自定义对数列及转换失效问题求解

问题根因

你使用了同一个CustomMappingOutput类作为两个独立自定义转换的输出类型。第二个LogThrust转换执行时,其输出对象会被初始化,CustomAction仅对LogThrust赋值,未被赋值的LogVelocity会被重置为double类型的默认值0,直接覆盖了第一步转换的计算结果。

解决方案

方案1:合并自定义映射(推荐)

将两个列的对数计算合并到同一个自定义映射中,避免多步转换的字段覆盖问题,同时减少不必要的计算开销:

using Microsoft.ML;
using Microsoft.ML.Transforms;
using System;
using System.Collections.Generic;
using System.IO;

namespace TestLog {
  public static class Program {
    private class InputData {
      public double Velocity { get; set; }
      public double Thrust { get; set; }
    }

    private class CustomMappingOutput {
      public double LogVelocity { get; set; }
      public double LogThrust { get; set; }
    }

    private class TransformedData : InputData {
      public double LogVelocity { get; set; }
      public double LogThrust { get; set; }
    }

    [CustomMappingFactoryAttribute("LogTransform")]
    private class LogCustomAction : CustomMappingFactory<InputData, CustomMappingOutput> {
      public static void CustomAction(InputData input, CustomMappingOutput output)
      {
          output.LogVelocity = Math.Log(input.Velocity);
          output.LogThrust = Math.Log(input.Thrust);
      }
      public override Action<InputData, CustomMappingOutput> GetMapping() => CustomAction;
    }

    public static void Run() {
      var mlContext = new MLContext();

      var samples = new List<InputData> {
          new InputData { Velocity= 0.006467, Thrust = 1.614237 },
          new InputData { Velocity= 0.53451,  Thrust = 1.068356 },
          new InputData { Velocity= 0.278578, Thrust = 0.216861 },
          new InputData { Velocity= 0.014179, Thrust = 0.119712 },
          new InputData { Velocity= 0.392814, Thrust = 3.915486 }
      };

      var data = mlContext.Data.LoadFromEnumerable(samples);

      var pipeline = mlContext.Transforms.CustomMapping(new LogCustomAction().GetMapping(),
                                                        contractName: "LogTransform");

      var transformer = pipeline.Fit(data);

      // 保存转换管道方便其他进程加载使用
      mlContext.Model.Save(transformer, data.Schema, "customTransform.zip");


      // 模拟其他程序加载已保存的转换模型
      var loadedTransform = mlContext.Model.Load("customTransform.zip", out _);

      // 对数据执行转换
      var transformedIDataView = loadedTransform.Transform(data);

      var newDataEnumerable = mlContext.Data.CreateEnumerable<TransformedData>(transformedIDataView,
                                                                               reuseRowObject: true);
      var newIDataView = mlContext.Data.LoadFromEnumerable(newDataEnumerable);

      // 保存转换后的IDataView为CSV文件方便校验转换结果
      var path = @"../../../transformed.csv";
      using var stream = File.Create(path);
      mlContext.Data.SaveAsText(newIDataView,
                                    stream,
                                    separatorChar: ',',
                                    headerRow: true,
                                    schema: false);
    }

    static void Main() {
      Program.Run();
      Console.WriteLine("按下回车键退出");
      Console.ReadLine();
    }
  }
}

方案2:使用ML.NET内置对数变换(最优)

你的场景完全可以用ML.NET自带的逐元素对数变换实现,无需自定义映射,性能更高、保存加载没有自定义契约的兼容问题,仅需替换管道定义部分即可:

var pipeline = mlContext.Transforms.Elementwise.Log(outputColumnName: "LogVelocity", inputColumnName: nameof(InputData.Velocity))
    .Append(mlContext.Transforms.Elementwise.Log(outputColumnName: "LogThrust", inputColumnName: nameof(InputData.Thrust)));

内容的提问来源于stack exchange,提问作者user274610

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 05:57:04