This is a follow up from the question here Dynamic classes/objects ML.net's PredictionMoadel<TInput, TOutput> Train()
My system cannot use a predefined class at compile time, therefore I tried to feed a dynamic class into ML.NET like below
// field data type
public class Field
{
public string FieldName { get; set; }
public Type FieldType { get; set; }
}
// dynamic class helper
public class DynamicClass : DynamicObject
{
private readonly Dictionary<string, KeyValuePair<Type, object>> _fields;
public DynamicClass(List<Field> fields)
{
_fields = new Dictionary<string, KeyValuePair<Type, object>>();
fields.ForEach(x => _fields.Add(x.FieldName,
new KeyValuePair<Type, object>(x.FieldType, null)));
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_fields.ContainsKey(binder.Name))
{
var type = _fields[binder.Name].Key;
if (value.GetType() == type)
{
_fields[binder.Name] = new KeyValuePair<Type, object>(type, value);
return true;
}
else throw new Exception("Value " + value + " is not of type " + type.Name);
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _fields[binder.Name].Value;
return true;
}
}
private static void Main(string[] args)
{
var fields = new List<Field>
{
new Field {FieldName = "Name", FieldType = typeof(string)},
new Field {FieldName = "Income", FieldType = typeof(float)}
};
dynamic obj1 = new DynamicClass(fields);
obj1.Name = "John";
obj1.Income = 100f;
dynamic obj2 = new DynamicClass(fields);
obj2.Name = "Alice";
obj2.Income = 200f;
var trainingData = new List<dynamic> {obj1, obj2};
var env = new LocalEnvironment();
var schemaDef = SchemaDefinition.Create(typeof(DynamicClass));
schemaDef.Add(new SchemaDefinition.Column(null, "Name", TextType.Instance));
schemaDef.Add(new SchemaDefinition.Column(null, "Income", NumberType.R4));
var trainDataView = env.CreateStreamingDataView(trainingData, schemaDef);
var pipeline = new CategoricalEstimator(env, "Name")
.Append(new ConcatEstimator(env, "Features", "Name"))
.Append(new FastTreeRegressionTrainer(env, "Income", "Features"));
var model = pipeline.Fit(trainDataView);
}
and got the error: "'No field or property with name 'Name' found in type 'System.Object'". I tried generating the class using Reflection only to run into the same problem.
Is there a workaround? Thanks