Dealing with VarVector<Single> Feature column in ML.NET - c#

I have a tricky model I'm trying to normalize for binary classification. Here's an example of the model structure. I renamed a few things just to simplify.
public class Review
{
public bool Label { get; set; }
public ReviewItem ReviewItem { get; set; }
public List<OtherItem> OtherItems { get; set; }
}
public class ReviewItem
{
public string SomeText { get; set; }
public float SomeNumber { get; set; }
public bool SomeBool { get; set; }
}
public class OtherItem
{
public string SomeDifferentText { get; set; }
public float SomeDifferentNumber { get; set; }
public bool SomeDifferentBool { get; set; }
}
There can be any number of OtherItem in the List. This is what I tried to flatten the model a bit.
public class ReviewMlModel
{
public bool Label { get; set; }
public string ReviewItem_SomeText { get; set; }
public float ReviewItem_SomeNumber { get; set; }
public bool ReviewItem_SomeBool { get; set; }
public string[] OtherItem_SomeDifferentText { get; set; }
public float[] OtherItem_SomeDifferentNumber { get; set; }
public bool[] OtherItem_SomeDifferentBool { get; set; }
}
From there I tried this to normalize it:
var data = mlContext.Data.LoadFromEnumerable(allReviews);
var dataPrepEstimator = mlContext.Transforms.Text.FeaturizeText("ReviewItem_SomeText")
.Append(mlContext.Transforms.Text.FeaturizeText("OtherItem_SomeDifferentText"))
.Append(mlContext.Transforms.Conversion.ConvertType("ReviewItem_SomeBool"))
.Append(mlContext.Transforms.Conversion.ConvertType("OtherItem_SomeDifferentBool"))
.Append(mlContext.Transforms.Concatenate("Features",
"ReviewItem_SomeText", "OtherItem_SomeDifferentText", "ReviewItem_SomeBool",
"OtherItem_SomeDifferentBool", "ReviewItem_SomeNumber", "OtherItem_SomeDifferentNumber"));
var transformedData = dataPrepEstimator.Fit(data).Transform(data);
var model = mlContext.BinaryClassification.Trainers.AveragedPerceptron()
.Fit(transformedData);
This gives me the exception on the line where I try to create the model:
Schema mismatch for feature column 'Features': expected Vector<Single>, got VarVector<Single> (Parameter 'inputSchema')
I'm guessing this is due to the fact these arrays all have variable lengths, but I don't see a way to transform the VarVector. Do I need to go make the original allReviews enumerable have the same length array for every array? Or am I way off track with how I flattened the original model?

Looks like it was a combination of changing the arrays to all have the same size, as well as adding [VectorType(size)] attribute to all the array properties.

Related

Automapper executes without error, but no data being copied from source to destination

I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));

merging two multi level class objects with element update c#

I have two objects (A,B) of same class type (PPLWebOperatorGridList). I need update the A.OldValue with B.Value.
I have tried by adding the guid property and update it in the constructor as shown below. But these object list may repeat same value:
public PPLWebOperatorGridList()
{
this.guid = this.FieldName+this.TagName+
this.Length+this.Encoder+this.Value;
}
public string guid { get; set; }
I have tried as below. I know there are bugs in it but consider the idea in it.
private List<PPLWebOperatorGridList> UpddateOldValues(List<PPLWebOperatorGridList> customeTlvList, List<PPLWebOperatorGridList> customeTlvList2)
{
foreach (var list in customeTlvList)
{
foreach (var list1 in customeTlvList2)
{
if (list.guid == list1.guid)
{
list.OldValue = list1.Value;
if (list.children.Count > 0)
UpddateOldValues(list.children.ToList(), list1.children.ToList());
}
}
}
return customeTlvList;
}
The guid property may be same for some in the list.
class PPLWebOperatorGridList
{
public bool expanded { get; set; }
public string FieldName { get; set; }
public string TagName { get; set; }
public string Length { get; set; }
public string Encoder { get; set; }
public string Value { get; set; }
public List<PPLWebOperatorGridList> children { get; set; }
public string OldValue { get; set; }
}
I need to loop through based on index and update the A.OldValue with B.Value. I am not very familiar with linq, so please suggest a solution.

How to sum result in each Table and Round from RoundResult in HomePayerResult

I have a list of players each player have Array of player result.
I try to sum all result for a specific round and table.
HomePlayerResults.RoundResult.Select(x => x.Table == 1 && x.Round == 1).Result;
tryed:
var H1 = matchResult.HomePlayerResults.SelectMany(x => x.RoundResults.GroupBy(res => res.Table)).ToList();
But then i´ll sum res.Result for each round
Without more details this is a very hard question to answer and you really need to provide much more context for the issue at hand, but I'll answer it based upon what was provided.
What you actually asked:
For this statement: I have a list of players each player have Array of player result. I try to sum all result for a specific round and table
Okay, given these classes:
public class Result
{
public int Val { get; set; }
}
public class Player
{
public IEnumerable<Result> Results { get; set; }
}
You'd do this to sum all the results of all the players:
var players = new List<Player>();
var results = players.Sum(x => x.Sum(y => y.Val));
What it looks like your intentions are from your provided code
If I'm understanding your wording right it sounds like you are trying to sum the results from a specific 'round', after which you then show this:
HomePlayerResults.RoundResult.Select(x => x.Table == 1 && x.Round == 1).Result;
This looks like you are trying to use Select as a Where clause, which is incorrect. The above will return a collection of 'true' or 'false' booleans and then compile time fail because Result does not exist on a boolean. I think THIS is what you are trying to do:
HomePlayerResults.RoundResult.Where(x => x.Table == 1 && x.Round == 1).Sum(x => x.Result);
I could be way off base, but without clarifying your question better or adding more details this is about as much as we can do to help.
Ok Sorry i copy the Class MatchResult: Then i explain what result i want futher down.
public class MatchResults
{
public string MatchAdmin { get; set; }
public string Error { get; set; }
public int allotHome { get; set; }
public int allotAway { get; set; }
public bool StrikeOut { get; set; }
public int StrikeOutNbrOfRounds { get; set; }
public int homeTeamId { get; set; }
public int awayTeamId { get; set; }
public int MatchId { get; set; }
public bool Hcp { get; set; }
public bool HcpBrutto { get; set; }
public bool Allot { get; set; }
public bool Finished { get; set; }
public int Lanes { get; set; }
public string SchemeId { get; set; }
public List<PlayerResult> HomePlayerResults { get; set; }
public List<PlayerResult> AwayPlayerResults { get; set; }
public List<SquadResult> HomeSquadResults { get; set; }
public List<SquadResult> AwaySquadResults { get; set; }
}
public class PlayerResult
{
public string LicNbr { get; set; }
public string FirstName { get; set; }
public string SurName { get; set; }
public string PlayerShortName { get; set; }
public string NameAndLicNbr { get; set; }
public int ShirtNo { get; set; }
public int Hcp { get; set; }
public List<RoundResult> RoundResults { get; set; }
}
public class RoundResult
{
public int Round { get; set; }
public int Result { get; set; }
public int Table { get; set; }
public int Squad { get; set; }
public int RoundNbr { get; set; }
}
So when this MatchResult Class from ServiceReference, i got one MatchResult and in this i have results from HomeTeam and AwayTeam. EatchTeam has PlayerResult witch is 8 players and one substitute So the list is 0 - 8.
Each PlayerResult has RoundResult[ 0 - 4] In there ic want to list for Each Round Each Table the pair of Players Result and Calc agains AwayTeam Pair Of player at same Table same Round who wins the minimatch.
From that i need to show the Winner Point.
There is an issue. From Round[1] There can be an player [0-7] with no result, si the substitute and that player shall swap placee. For example player [3] round 2 dont play that round, so substitute get [3] and player[3] get player[8] position in List of HomPlayerResult.
Hope you understand..
Best Regards
Gert

How to change a Android (JsonProperty["value"]) value in C#? [duplicate]

I am trying to make use of the API for a well known online meeting provider. One of their API calls returns an object that looks like this.
{
"5234592":{
"pollsAndSurveys":{
"questionsAsked":1,
"surveyCount":0,
"percentageSurveysCompleted":0,
"percentagePollsCompleted":100,
"pollCount":2},
"attendance":{
"averageAttendanceTimeSeconds":253,
"averageInterestRating":0,
"averageAttentiveness":0,
"registrantCount":1,
"percentageAttendance":100}
},
"5235291":{
"pollsAndSurveys":{
"questionsAsked":2,
"surveyCount":0,
"percentageSurveysCompleted":0,
"percentagePollsCompleted":0,
"pollCount":0},
"attendance":{
"averageAttendanceTimeSeconds":83,
"averageInterestRating":0,
"averageAttentiveness":0,
"registrantCount":1,
"percentageAttendance":100}
}
}
I am trying to make a strongly typed object in C# so I can deal with this data. I can create objects for the pollsAndSurveys bit and the attendance bit but I don't know how to deal with the id number, in this case 5234592 & 5235291, that is the identifier for the session.
public class AttendanceStatistics
{
[JsonProperty(PropertyName = "registrantCount")]
public int RegistrantCount { get; set; }
[JsonProperty(PropertyName = "percentageAttendance")]
public float PercentageAttendance{ get; set; }
[JsonProperty(PropertyName = "averageInterestRating")]
public float AverageInterestRating { get; set; }
[JsonProperty(PropertyName = "averageAttentiveness")]
public float AverageAttentiveness { get; set; }
[JsonProperty(PropertyName = "averageAttendanceTimeSeconds")]
public float AverageAttendanceTimeSeconds { get; set; }
}
public class PollsAndSurveysStatistics
{
[JsonProperty(PropertyName = "pollCount")]
public int PollCount { get; set; }
[JsonProperty(PropertyName = "surveyCount")]
public float SurveyCount { get; set; }
[JsonProperty(PropertyName = "questionsAsked")]
public int QuestionsAsked { get; set; }
[JsonProperty(PropertyName = "percentagePollsCompleted")]
public float PercentagePollsCompleted { get; set; }
[JsonProperty(PropertyName = "percentageSurveysCompleted")]
public float PercentageSurveysCompleted { get; set; }
}
public class SessionPerformanceStats
{
[JsonProperty(PropertyName = "attendance")]
public AttendanceStatistics Attendance { get; set; }
[JsonProperty(PropertyName = "pollsAndSurveys")]
public PollsAndSurveysStatistics PollsAndSurveys { get; set; }
}
public class WebinarPerformanceStats
{
public List<SessionPerformanceStats> Stats { get; set; }
}
I am pretty sure that the WebinarPerformanceStats is the issue but I don't know where to go from here. What would I have to change to get
NewtonSoft.Json.JsonConvert.DeserializeObject<WebinarPerformanceStats>(theJsonResponse)
to work?
Make your root object be a dictionary:
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, SessionPerformanceStats>>(theJsonResponse);
Json.NET serializes a dictionary from and to a JSON object, with the keys being converted to the property names. In your case, the ID numbers will be deserialized as the dictionary keys. If you are sure they will always be numbers, you could declare them as such:
var dictionary = JsonConvert.DeserializeObject<Dictionary<long, SessionPerformanceStats>>(theJsonResponse);
See Serialize a Dictionary and Deserialize a Dictionary

Updating List<T> in DbContext

I have a Model like this
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<string> SolvedBy { get; set; }
}
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
}
and then Controller like this. But I cannot update the List "SolvedBy", the next time I step through with the debugger, the list is still empty.
[HttpPost]
public string Index(string flag = "", int id=0)
{
Challenge challenge = db.Challenges.Find(id);
if (flag == challenge.Flag)
{
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<string>();
}
chall.SolvedBy.Add(User.Identity.Name);
db.Entry(chall).State = EntityState.Modified;
db.SaveChanges();
//congrats, you solved the puzzle
return "got it";
}
else
{
return "fail";
}
}
is there any way around it to make a list of strings kept in the database?
EF don't know how to store an array in database table so it just ignore it. You can create another table/entity or use XML/JSON to store the list. You can serialize the list before saving and deserialize it after loading from database
A List<T> in a model would normally map to a second table, but in your DbContext you only have a single table. Try adding a second table.
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
public DbSet<Solution> Solutions {get; set;}
}
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<Solution> SolvedBy { get; set; }
}
public class Solution
{
public int ID { get; set; }
public string Name { get; set; }
}
Then your controller can use code along the lines of...
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<Solution>();
}
chall.SolvedBy.Add(new Solution {Name=User.Identity.Name});
None of the above has been tested and I may have made some mistakes there, but the general principle I want to illustrate is the fact that you need another table. The List<T> represents a JOIN in SQL.

Categories

Resources