ML.NET LoadFromEnumerable抛出ArgumentOutOfRangeException问题咨询
异常信息
System.ArgumentOutOfRangeException: Could not determine an IDataView type and registered custom types for member ValueType (Parameter 'rawType')
问题原因
不管场景1还是场景2,触发异常的核心逻辑一致:ML.NET的LoadFromEnumerable方法会自动扫描实体类的所有公共属性,尝试将其映射为IDataView的列。你的DateTimeValue类中包含ValueType属性,其类型是自定义枚举ValueTypeEnum,而ML.NET默认不支持直接将自定义枚举映射为IDataView类型,因此抛出该异常。
场景2中手动构建Schema的代码未生效,因为你是先调用LoadFromEnumerable再创建Schema,两者没有关联——LoadFromEnumerable不会使用后续创建的Schema,而是自动从实体类推断列结构。
解决方案
方案1:用[IgnoreColumn]标记无需映射的属性
直接在ValueType属性上添加ML.NET的[IgnoreColumn]特性,让LoadFromEnumerable跳过该属性的映射:
using Microsoft.ML.Data; // ... [Browsable(false)] [IgnoreColumn] // 添加此特性忽略该列 public ValueTypeEnum ValueType { get => _valueType; set => SetProperty(ref _valueType, value); }
修改后,调用LoadFromEnumerable时会自动跳过ValueType属性,不会触发类型识别异常。
方案2:注册自定义枚举类型
如果需要保留ValueType属性作为IDataView的列,可提前向MLContext注册枚举类型,将其映射为整数类型:
MLContext mlContext = new MLContext(); // 注册自定义枚举,映射为Int32类型 mlContext.Model.RegisterEnumType<ValueTypeEnum>(); // 后续正常调用LoadFromEnumerable var dataViewDateTimeValues = mlContext.Data.LoadFromEnumerable(dateTimeValues.Data.Values);
注册后,ML.NET会将ValueTypeEnum的枚举值转换为对应的整数(如Raw=0、Interpolated=1),作为IDataView的列数据。
方案3:投影为仅含所需属性的对象
在传入LoadFromEnumerable前,将数据投影为只包含DateTimeOffset和Value的匿名类型或DTO,避免扫描到不需要的属性:
MLContext mlContext = new MLContext(); // 投影数据,仅保留需要的属性 var projectedData = dateTimeValues.Data.Values.Select(item => new { item.DateTimeOffset, item.Value }); var dataViewDateTimeValues = mlContext.Data.LoadFromEnumerable(projectedData);
该方式无需修改原实体类,适合临时数据处理场景。
内容的提问来源于stack exchange,提问作者Eric Ouellet

