ML.NET 以通用方式合并 IDataView
ML.NET Merge IDataViews in a genric way
我正在为 ML.NET 创建一个 CLI 工具,我需要创建一个合并函数,以合并两个相同类型的数据集。但它需要尽可能通用,因为该工具包含不同的数据集类型。
我设法创建了一个方法,将 IDataview 转换为具有给定数据集类型的通用 IEnumerable:
private IEnumerable<object> GetDataEnumerable(MLContext mlContext, IDataView dataView, Type dataViewType) {
var createEnumerableMethod = typeof(DataOperationsCatalog).GetMethod(nameof(MLContext.Data.CreateEnumerable));
var generic = createEnumerableMethod.MakeGenericMethod(dataViewType);
return (IEnumerable<object>)generic.Invoke(mlContext.Data, new object[] { dataView, false, null, null });
}
几天后我想通了。首先,我将 2 个 IDataviews 转换为在运行时获取类型的 IEnumerable。之后,我将它们合并在一起,将它们转换为列表,并使用反射将它们转换为正确的类型。最后,我再次使用反射将最终可枚举加载回 IDataview。
var oldDataEnumerable = GetDataEnumerable(mlContext, oldDataView, dataViewType).ToList();
var newDataEnumerable = GetDataEnumerable(mlContext, newDataView, dataViewType).ToList();
var mergedEnumerable = MergeDataEnumerables(oldDataEnumerable, newDataEnumerable, dataViewType);
return LoadEnumerableFromObject(mlContext, mergedEnumerable, dataViewType);
private IEnumerable<object> GetDataEnumerable(MLContext mlContext, IDataView dataView, Type dataViewType) {
var createEnumerableMethod = typeof(DataOperationsCatalog).GetMethod(nameof(MLContext.Data.CreateEnumerable));
var generic = createEnumerableMethod.MakeGenericMethod(dataViewType);
return (IEnumerable<object>)generic.Invoke(mlContext.Data, new object[] { dataView, false, null, null });
}
private object MergeDataEnumerables(List<object> firstDataEnumerable, List<object> secondDataEnumerable, Type dataViewType) {
firstDataEnumerable.AddRange(secondDataEnumerable);
var castMethod = typeof(Enumerable).GetMethod("Cast");
var genericCast = castMethod.MakeGenericMethod(dataViewType);
var toListMethod = typeof(Enumerable).GetMethod("ToList");
var genericToList = toListMethod.MakeGenericMethod(dataViewType);
var castedEnumerable = genericCast.Invoke(null, new[] { firstDataEnumerable });
return genericToList.Invoke(null, new[] { castedEnumerable });
}
private IDataView LoadEnumerableFromObject(MLContext mlContext, object dataEnumerable, Type dataViewType) {
var dataType = mlContext.Data.GetType();
var loadFromEnumerableMethod = dataType.GetMethods().First(m => m.Name == "LoadFromEnumerable" && m.IsGenericMethod);
var generic = loadFromEnumerableMethod.MakeGenericMethod(dataViewType);
var schema = SchemaDefinition.Create(dataViewType);
return (IDataView)generic.Invoke(mlContext.Data, new object[] { dataEnumerable, schema });
}
我正在为 ML.NET 创建一个 CLI 工具,我需要创建一个合并函数,以合并两个相同类型的数据集。但它需要尽可能通用,因为该工具包含不同的数据集类型。
我设法创建了一个方法,将 IDataview 转换为具有给定数据集类型的通用 IEnumerable:
private IEnumerable<object> GetDataEnumerable(MLContext mlContext, IDataView dataView, Type dataViewType) {
var createEnumerableMethod = typeof(DataOperationsCatalog).GetMethod(nameof(MLContext.Data.CreateEnumerable));
var generic = createEnumerableMethod.MakeGenericMethod(dataViewType);
return (IEnumerable<object>)generic.Invoke(mlContext.Data, new object[] { dataView, false, null, null });
}
几天后我想通了。首先,我将 2 个 IDataviews 转换为在运行时获取类型的 IEnumerable。之后,我将它们合并在一起,将它们转换为列表,并使用反射将它们转换为正确的类型。最后,我再次使用反射将最终可枚举加载回 IDataview。
var oldDataEnumerable = GetDataEnumerable(mlContext, oldDataView, dataViewType).ToList();
var newDataEnumerable = GetDataEnumerable(mlContext, newDataView, dataViewType).ToList();
var mergedEnumerable = MergeDataEnumerables(oldDataEnumerable, newDataEnumerable, dataViewType);
return LoadEnumerableFromObject(mlContext, mergedEnumerable, dataViewType);
private IEnumerable<object> GetDataEnumerable(MLContext mlContext, IDataView dataView, Type dataViewType) {
var createEnumerableMethod = typeof(DataOperationsCatalog).GetMethod(nameof(MLContext.Data.CreateEnumerable));
var generic = createEnumerableMethod.MakeGenericMethod(dataViewType);
return (IEnumerable<object>)generic.Invoke(mlContext.Data, new object[] { dataView, false, null, null });
}
private object MergeDataEnumerables(List<object> firstDataEnumerable, List<object> secondDataEnumerable, Type dataViewType) {
firstDataEnumerable.AddRange(secondDataEnumerable);
var castMethod = typeof(Enumerable).GetMethod("Cast");
var genericCast = castMethod.MakeGenericMethod(dataViewType);
var toListMethod = typeof(Enumerable).GetMethod("ToList");
var genericToList = toListMethod.MakeGenericMethod(dataViewType);
var castedEnumerable = genericCast.Invoke(null, new[] { firstDataEnumerable });
return genericToList.Invoke(null, new[] { castedEnumerable });
}
private IDataView LoadEnumerableFromObject(MLContext mlContext, object dataEnumerable, Type dataViewType) {
var dataType = mlContext.Data.GetType();
var loadFromEnumerableMethod = dataType.GetMethods().First(m => m.Name == "LoadFromEnumerable" && m.IsGenericMethod);
var generic = loadFromEnumerableMethod.MakeGenericMethod(dataViewType);
var schema = SchemaDefinition.Create(dataViewType);
return (IDataView)generic.Invoke(mlContext.Data, new object[] { dataEnumerable, schema });
}