Time Series Forecasting ML .Net - asp.net

After 3/4 year into asp net, i'm trying since few weeks to learn ML.net but i'm having some trouble with forecasting time series.
Here is my main questions :
I would like to predict price over the 7 next days but my data is not evenly distributed, how can i force the horizon to predict over the 7 next day and not just 7 occurrences ?
Can i predict all 3 values ( unit price , price pack 10, price pack 100) in the same engine ?
Each items getting their own "life"( the price of one item may go down while the other goes up) do i need to create a model for each item ?
Even if my dataset is not big enough for now how can i get a beter prediction from these data ( result of the prediction at the end of post) ?
My final goal is to send to my ML core an item name with his current price ( unit, pack 10 ,pack 100) then the core predict an optimal sell price and date. Then with simple math i can choose to buy or not.
Here is all my process to build the model for times series prediction.
First, loading data.
string queryThisWeek = "SELECT * from Ressource where ressource ='" + ressourceToHandle.Ressource + "' and Date >= '" + startCurrentWeek + "' order by Date desc";
string queryBeforeThisWeek = "SELECT * from Ressource where ressource ='" + ressourceToHandle.Ressource + "' and Date < '" + startCurrentWeek + "' order by Date desc";
var connection = new SqliteConnection(ConnectionString);
var factory = DbProviderFactories.GetFactory(connection);
DatabaseSource dbSourceThisWeek = new DatabaseSource(factory, ConnectionString, queryThisWeek);
DatabaseSource dbSourceBeforeThisWeek = new DatabaseSource(factory, ConnectionString, queryBeforeThisWeek);
IDataView dataViewThisWeek = loader.Load(dbSourceThisWeek);
IDataView dataViewBeforeThisWeek = loader.Load(dbSourceBeforeThisWeek);
Maybe i should select more data from the past ?
Yes my database is not big enough yet ( maybe 40-65 records per item from past 4 days) but each day i'm getting more data
Then i create 3 pipelines ( one for each type of Price ( Price of a unit , price of pack X10, price pack X100 )) :
forecastPipeline = mlContext.Forecasting.ForecastBySsa(
outputColumnName: "PriceForecasted",
inputColumnName: "Prix1",
windowSize: 7,
seriesLength: 30,
trainSize: 365,
horizon: 7,
confidenceLevel: 0.95f,
confidenceLowerBoundColumn: "LowerBoundPrice",
confidenceUpperBoundColumn: "UpperBoundPrice");
Is my setting correct here for my needs ?
Evaluate my 3 prediction for each prices:
actual = mlContext.Data.CreateEnumerable<Ressources>(testData, true)
.Select(observed => observed.Prix1);
forecast = mlContext.Data.CreateEnumerable<RessourceLot1Prediction>(predictions, true)
.Select(prediction => prediction.PriceForecasted[0]);
// Calculate error (actual - forecast)
var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);
// Get metric averages
var MAE = metrics.Average(error => Math.Abs(error)); // Mean Absolute Error
var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2))); // Root Mean Squared Error
Creating my 3 engines for each prices i want to predict :
var forecastEngineLot1 = forecaster.CreateTimeSeriesEngine<Ressources, RessourceLot1Prediction>(core.mlContext);
forecastEngineLot1.CheckPoint(core.mlContext, modelPath);
Finally i predict my 3 prices :
IEnumerable<string> forecastOutput =
mlContext.Data.CreateEnumerable<Ressources>(testData, reuseRowObject: false)
.Take(horizon)
.Select((Ressources ress, int index) =>
{
string Date = ress.Date.ToString("dd-MM-yyyy hh:mm");
float actualPrice = ress.Prix1;
float lowerEstimate = Math.Max(0, forecast.LowerBoundPrice[index]);
float estimate = forecast.PriceForecasted[index];
float upperEstimate = forecast.UpperBoundPrice[index];
return $"Date: {Date}\n" +
$"Actual price: {actualPrice}\n" +
$"Lower Estimate: {lowerEstimate}\n" +
$"Forecast: {estimate}\n" +
$"Upper Estimate: {upperEstimate}\n";
});
I have these data:
Item Name
Unit Price
Price of pack X10
Price of pack X100
Average Price
Datetime when price captured
Here is my result and my dataset :
Class used :
public class Ressources
{
[LoadColumn(0)]
public string Ressource { get; set; }
[LoadColumn(1)]
public float Price1 { get; set; }
[LoadColumn(2)]
public float Price10 { get; set; }
[LoadColumn(3)]
public float Price100 { get; set; }
[LoadColumn(4)]
public float PriceAverage { get; set; }
[LoadColumn(5)]
public DateTime Date { get; set; }
}
public class RessourceLot1Prediction
{
public float[] PriceForecasted { get; set; }
public float[] LowerBoundPrice { get; set; }
public float[] UpperBoundPrice { get; set; }
}
public class RessourceLot10Prediction
{
public float[] PriceForecasted { get; set; }
public float[] LowerBoundPrice { get; set; }
public float[] UpperBoundPrice { get; set; }
}
public class RessourceLot100Prediction
{
public float[] PriceForecasted { get; set; }
public float[] LowerBoundPrice { get; set; }
public float[] UpperBoundPrice { get; set; }
}

Related

Joining two a ViewModel

This is the model:
public class ProCar
{
public string ProductName { get; set; }
public int ProductYear { get; set; }
public string CarBrand { get; set; }
public int CarEngine { get; set; }
}
I'm using this LINQ. How to save to a List of ProCar.
List<Product> p1 = db.Products.ToList();
List<Car> c1 = db.Cars.ToList();
List<ProCar> query = from pList in p1
join cList in c1 on pList equals cList.ProductId
select new { ProductName = pList.ProductName, ProductYear = pList.ProductYear, CarBrand = cList.CarBrand, CarEngine = cList.CarEngine };
return View();
Cannot find the issue.
Assuming you have relation between Product and Car :
var query = from product in db.Products
join car in db.Cars on product.Id equals car.ProductId//The relation between car and product
select new ProCar
{
ProductName = product.ProductName,
ProductYear = product.ProductYear,
CarBrand = car.CarBrand,
CarEngine = car.CarEngine
};
List<ProCar> proCarList = query.ToList();
See Join Clause
You are creating an anonymous list type that is unable to find/cast List type of ProCar. So you need to specify for tightly couply model binding as below
List<ProCar> query = ( from pList in p1
join cList in c1 on pList equals cList.ProductId
select new ProCar
{
ProductName = product.ProductName,
ProductYear = product.ProductYear,
CarBrand = car.CarBrand,
CarEngine = car.CarEngine
}).ToList();

How to create datime chart

I have a datatable from SQL Server with datetime field ScannedDateTime
I am trying to make a chart in VB NET with 2 line type series:
X - should be date from field ScannedDateTime
Y - should be time from fiels ScannedDateTime
I have not idea how to do it? To convert time to decimal numbers and show it as y axis or what?
I would like to keep y in time format "hh:mm" and to limit min value as work time example: from 07:00 to 15:00
Devexpress?
I tried this but why is time repeated???
Thanks for idea
It seems that you need to show the Time value from every data source record using the TimeSpan scale. While the DevExpress ChartControl does not support the TimeSpan scale type, you can use the following approach to generate the required chart layout.
First, define an extra numeric field that will be used as the ValueDataMember and contain the number of ticks corresponding to the TimeSpan value.
To show TimeSpan labels instead of numeric values, populate a collection of Custom Axis Label elements.
Finally, customize the Crosshair Cursor label text by handling the CustomDrawCrosshair event.
Please refer to the sample source code illustrating this approach:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
List<MyData> inputData = new List<MyData>();
inputData.Add(new MyData() { ID = 1, ScannedDateTime = new DateTime(2019, 4, 1, 11, 22, 33) });
inputData.Add(new MyData() { ID = 2, ScannedDateTime = new DateTime(2019, 4, 2, 15, 00, 12) });
inputData.Add(new MyData() { ID = 3, ScannedDateTime = new DateTime(2019, 4, 3, 09, 11, 03) });
Series lineSeries = new Series("Scanned Date", ViewType.Line);
lineSeries.ArgumentDataMember = "ScannedDateTime";
lineSeries.ValueScaleType = ScaleType.Numerical;
lineSeries.ValueDataMembers.AddRange(new string[] { "TimeTicks" });
lineSeries.DataSource = inputData;
chartControl1.Series.Add(lineSeries);
XYDiagram diagram = (XYDiagram)chartControl1.Diagram;
diagram.AxisX.DateTimeScaleOptions.MeasureUnit = DateTimeMeasureUnit.Day;
for (int i = 0; i < 24; i++)
{
TimeSpan ts = new TimeSpan(i, 0, 0); //display tickmarks for every hour
diagram.AxisY.CustomLabels.Add(new CustomAxisLabel() { AxisValue = ts.Ticks, Name = ts.ToString() });
}
chartControl1.CustomDrawCrosshair += ChartControl1_CustomDrawCrosshair; // optional - if you need to show TimeSpan values in the Crosshair Cursor
}
private void ChartControl1_CustomDrawCrosshair(object sender, CustomDrawCrosshairEventArgs e)
{
foreach(CrosshairElementGroup g in e.CrosshairElementGroups)
{
foreach(CrosshairElement el in g.CrosshairElements)
{
TimeSpan ts = TimeSpan.FromTicks((long)el.SeriesPoint.Values[0]);
el.LabelElement.Text = string.Format("{0} - {1}", el.SeriesPoint.Argument, ts);
}
}
}
}
public class MyData
{
public int ID { get; set; }
public DateTime ScannedDateTime { get; set; }
public double TimeTicks
{
get
{
return ScannedDateTime.TimeOfDay.Ticks;
}
}
}

linq query issues multiple tables

Here is what I have guys/girls...I have 3 tables as follows (only included important columns):
ITEMS:
ItemId Name ItemLocationId
20 Portal Orange 12
21 Portal Blue 13
ITEMLOCATIONS:
ItemLocationid ItemId CreateDate LocationIf
13 21 3/26/2017 2:19:15 AM 5
14 20 3/27/2017 6:25:45 PM 6
15 21 3/31/2017 12:17:25 AM 6
16 21 3/31/2017 12:18:42 AM 5
17 21 3/31/2017 12:20:23 AM 6
LOCATIONS
LocationId Name
5 Storage Room
6 Boss Room
My issue lies in the itemlocations table...I only need the most recent ItemLocation in the table...The others are for historical value...here is the query I am running now
Dim i = From r In mydb.Items
Join il In mydb.ItemLocations On r.ItemLocationId Equals il.ItemLocationId
Join l In mydb.Locations On il.LocationId Equals l.LocationId
Where r.CompanyId = UserPro.CompanyId
Select r.ItemId, r.Name, Location = l.Name
this is returning the first itemlocation in the table for that item...how do I get only the one with then most recent
did not have database available so sketched answer for you in LinqPad.
You need to select by date:
void Main()
{
List<Item> Items = new List<Item> { new Item { ItemID=20, ItemLocationID=12, Name="Portal Orqange"},
new Item{ ItemID=21, ItemLocationID=13, Name="Portal Blue"}};
List<ItemLocation> ItemLocations = new List<ItemLocation> {
new ItemLocation {ItemLocationID=13, ItemId=21, CreateDate=DateTime.Parse("3/26/2017 2:19:15 AM"), LocationId=5},
new ItemLocation {ItemLocationID=14, ItemId=20, CreateDate=DateTime.Parse("3/27/2017 6:25:45 PM"), LocationId=6},
new ItemLocation {ItemLocationID=15, ItemId=21, CreateDate=DateTime.Parse("3/31/2017 12:17:25 AM"), LocationId=6},
new ItemLocation {ItemLocationID=16, ItemId=21, CreateDate=DateTime.Parse("3/31/2017 12:18:42 AM"), LocationId=5},
new ItemLocation {ItemLocationID=17, ItemId=21, CreateDate=DateTime.Parse("3/31/2017 12:20:23 AM"), LocationId=6},
};
List<Location> Locations = new List<Location> { new Location { LocationID=5, Name="Storage Room"},
new Location { LocationID=6, Name="Boss Room"}
};
Items.Join(ItemLocations, i => i.ItemID, il => il.ItemId, (i, il) => new { i, il }).OrderByDescending(i =>i.il.CreateDate )
.Join(Locations, iil => iil.il.LocationId, il=>il.LocationID, (lc, c) => new {lc,c}).FirstOrDefault()
.Dump();
}
// Define other methods and classes here
public class Item
{
public int ItemID { get; set; }
public string Name { get; set; }
public int ItemLocationID { get; set;}
}
public class ItemLocation
{
public int ItemLocationID { get; set; }
public int ItemId { get; set; }
public DateTime CreateDate { get; set; }
public int LocationId { get; set;}
}
public class Location
{
public int LocationID { get; set; }
public string Name { get; set;}
}
When ready to code, just replace Dump() which is LinqPad specific to Select.
Result as follows:
What about this one
Dim groupQuery=from il mydb.ItemLocations
.group il by il.ItemId into gl
select gl.orderByDescending(g=>g.CreateDate).First();
Dim i = From r In mydb.Items
Join il In groupQuery On r.ItemLocationId Equals il.ItemLocationId
Join l In mydb.Locations On il.LocationId Equals l.LocationId
Where r.CompanyId = UserPro.CompanyId
Select r.ItemId, r.Name, Location = l.Name

Finding all the dates that lie between 2 input dates in c# with xml as data source

I am working on an application in asp.net with XML as data source where I am asking users to input 2 dates from 2 textboxes in the form "dd/MM" and not including the year. and I need to find all the details of the employee whose birthday lies in that range of date. The XML has details of all the employee and the DOB is saved in the form of "dd/MM". I tried different logics bt dint work out. so please suggest me how to tackle this problem.
thanks in advance.
A simple approach is the one I specified in the comments. Using Linq it can be used similar to the following.
namespace Test {
public class BirthdayTest
{
public HasBirthday[] birthdays = new[] {
new HasBirthday { Name = "Name1", Birthday = new DateTime(2014, 1, 1) },
new HasBirthday { Name = "Name2", Birthday = new DateTime(2014, 2, 14) }
};
public class HasBirthday {
public DateTime Birthday { get; set; }
public string Name { get; set; }
}
public IEnumerable<HasBirthday> InRange(string from, string to) {
int firstMonth = Int32.Parse(from.Substring(3));
int lastMonth = Int32.Parse(to.Substring(3));
int firstDay = Int32.Parse(from.Substring(0, 2));
int lastDay = Int32.Parse(to.Substring(0, 2));
IEnumerable<HasBirthday> inRange = birthdays
.Where(birthday =>
birthday.Birthday.Month <= lastMonth &&
birthday.Birthday.Month >= firstMonth &&
(birthday.Birthday.Month != lastMonth || birthday.Birthday.Day <= lastDay) &&
(birthday.Birthday.Month != firstMonth || birthday.Birthday.Day >= firstDay));
return inRange;
}
}
}
And then call it with your two dates in the form of "dd/MM". Notice the last "split" when breaking years.
string from = "01/01";
string to = "31/12";
Console.WriteLine("between {0} and {1}", from, to);
foreach (HasBirthday birthday in InRange(from, to)){
Console.WriteLine("{0}, {1}", birthday.Name, birthday.Birthday);
}
from = "01/02";
to = "31/12";
Console.WriteLine("between {0} and {1}", from, to);
foreach (HasBirthday birthday in InRange(from, to)){
Console.WriteLine("{0}, {1}", birthday.Name, birthday.Birthday);
}
from = "01/12";
to = "02/01";
Console.WriteLine("between {0} and {1}", from, to);
foreach (HasBirthday birthday in InRange(from, "31/12")){
Console.WriteLine("{0}, {1}", birthday.Name, birthday.Birthday);
}
foreach (HasBirthday birthday in InRange("01/01", to)){
Console.WriteLine("{0}, {1}", birthday.Name, birthday.Birthday);
}
Which outputs:
between 01/01 and 31/12
Name1, 1/1/2014 12:00:00 AM
Name2, 2/14/2014 12:00:00 AM
between 01/02 and 31/12
Name2, 2/14/2014 12:00:00 AM
between 01/12 and 02/01
Name1, 1/1/2014 12:00:00 AM

Having trouble with display colums from 4 tables MVC 3

I have a model as below and want to display items from 4 different table.
public class AuctionViewer
{
public int AuctionId { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
public DateTime startTime { get; set; }
public DateTime EndTime { get; set; }
public string Category { get; set; }
public int ExpectedHit { get; set; }
public string Status { get; set; }
}
Here is my controller code below.
public ActionResult Index()
{
MightyMouseContainer ctx = new MightyMouseContainer();
var NewList = new AuctionViewer
{
from CT in ctx.Categories
join PD in ctx.Items on CT.Category_ID equals PD.Category_ID
join AU in ctx.Auction_Schedule on PD.Item_ID equals AU.Item_ID
join ST in ctx.Status on AU.Status_ID equals ST.Status1
orderby AU.Auction_ID
select new
{
AuctionId = AU.Auction_ID,
ProductName = PD.Item_name,
Price= PD.Item_Value,
startTime = AU.Start_Time,
EndTime = AU.End_Time,
Category = CT.Category_Description,
Status = ST.Description
};
}
return View(NewList);
}
I wonder why is giving errors. please advise. I have been on this for quite a while and realized that I need some help to move on. I will appreciate prompt response in other to move forward. Thanks
Assuming your view accepts a model of IEnumerable<AuctionViewer>, you should change the select to return the strongly typed collection, e.g.:
var NewList = from CT in ctx.Categories
join PD in ctx.Items on CT.Category_ID equals PD.Category_ID
join AU in ctx.Auction_Schedule on PD.Item_ID equals AU.Item_ID
join ST in ctx.Status on AU.Status_ID equals ST.Status1
orderby AU.Auction_ID
select new AuctionViewer
{
AuctionId = AU.Auction_ID,
ProductName = PD.Item_name,
Price= PD.Item_Value,
startTime = AU.Start_Time,
EndTime = AU.End_Time,
Category = CT.Category_Description,
Status = ST.Description
};
return View(NewList);
Edit From your second error message, it seems that the view expects a List<AuctionViewer>. You can change the controller method to materialize the IQueryable as a List as follows:
var NewList = (from CT in ctx.Categories
join PD in ctx.Items on CT.Category_ID equals PD.Category_ID
join AU in ctx.Auction_Schedule on PD.Item_ID equals AU.Item_ID
join ST in ctx.Status on AU.Status_ID equals ST.Status1
orderby AU.Auction_ID
select new AuctionViewer
{
AuctionId = AU.Auction_ID,
ProductName = PD.Item_name,
Price= PD.Item_Value,
startTime = AU.Start_Time,
EndTime = AU.End_Time,
Category = CT.Category_Description,
Status = ST.Description
}).ToList();
return View(NewList);

Resources