59 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/app/house-price/house-price.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { HousePriceComponent } from './house-price.component';
4 |
5 | describe('HousePriceComponent', () => {
6 | let component: HousePriceComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ HousePriceComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(HousePriceComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/app/house-price/house-price.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { HouseFeatures } from '../houseFeatures';
3 | import { AREAS } from '../mock-areas';
4 | import { HousePriceCalcService } from '../house-price-calc.service';
5 | import { Observable } from 'rxjs';
6 |
7 | @Component({
8 | selector: 'app-house-price',
9 | templateUrl: './house-price.component.html',
10 | styleUrls: ['./house-price.component.css']
11 | })
12 | export class HousePriceComponent implements OnInit {
13 | houseFeature: HouseFeatures = {
14 | area: '76',
15 | houseType: 'condo',
16 | rooms: 7,
17 | bedRooms: 3,
18 | bedRoomsBsmt: 0,
19 | fullBath: 2,
20 | halfBath: 0,
21 | approxSquFeet: 1200,
22 | garageType: 'attached',
23 | garageSpaces: 2,
24 | parkingSpaces: 0
25 | };
26 |
27 | availableAreas: string[];
28 | selectedArea: string;
29 | housePrice: Observable;
30 |
31 | constructor(private priceCalcService: HousePriceCalcService) { }
32 |
33 | ngOnInit() {
34 | this.availableAreas = this.priceCalcService.getAreas();
35 | }
36 |
37 | getPredictedPrice(): void {
38 | this.housePrice = this.priceCalcService.getPrice(this.houseFeature);
39 | }
40 |
41 | onSelectArea(a: string): void {
42 | this.selectedArea = a;
43 | this.houseFeature.area = a;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/app/houseFeatures.ts:
--------------------------------------------------------------------------------
1 | export class HouseFeatures {
2 | area: string;
3 | houseType: string;
4 | rooms: number;
5 | bedRooms: number;
6 | bedRoomsBsmt: number;
7 | fullBath: number;
8 | halfBath: number;
9 | approxSquFeet: number;
10 | garageType: string;
11 | garageSpaces: number;
12 | parkingSpaces: number;
13 | }
14 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/app/mock-areas.ts:
--------------------------------------------------------------------------------
1 | export const AREAS: string[] = [
2 | '76','11'
3 | ];
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/HousePricePredictorWeb/src/assets/.gitkeep
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/browserslist:
--------------------------------------------------------------------------------
1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 | #
5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
6 |
7 | > 0.5%
8 | last 2 versions
9 | Firefox ESR
10 | not dead
11 | not IE 9-11
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/HousePricePredictorWeb/src/favicon.ico
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Housepricepredictor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../coverage/housepricepredictor'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.error(err));
13 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "types": []
6 | },
7 | "exclude": [
8 | "test.ts",
9 | "**/*.spec.ts"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "test.ts",
12 | "polyfills.ts"
13 | ],
14 | "include": [
15 | "**/*.spec.ts",
16 | "**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/src/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tslint.json",
3 | "rules": {
4 | "directive-selector": [
5 | true,
6 | "attribute",
7 | "app",
8 | "camelCase"
9 | ],
10 | "component-selector": [
11 | true,
12 | "element",
13 | "app",
14 | "kebab-case"
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "module": "es2015",
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "importHelpers": true,
13 | "target": "es5",
14 | "typeRoots": [
15 | "node_modules/@types"
16 | ],
17 | "lib": [
18 | "es2018",
19 | "dom"
20 | ]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/HousePricePredictorWeb/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rulesDirectory": [
4 | "codelyzer"
5 | ],
6 | "rules": {
7 | "array-type": false,
8 | "arrow-parens": false,
9 | "deprecation": {
10 | "severity": "warn"
11 | },
12 | "import-blacklist": [
13 | true,
14 | "rxjs/Rx"
15 | ],
16 | "interface-name": false,
17 | "max-classes-per-file": false,
18 | "max-line-length": [
19 | true,
20 | 140
21 | ],
22 | "member-access": false,
23 | "member-ordering": [
24 | true,
25 | {
26 | "order": [
27 | "static-field",
28 | "instance-field",
29 | "static-method",
30 | "instance-method"
31 | ]
32 | }
33 | ],
34 | "no-consecutive-blank-lines": false,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-empty": false,
44 | "no-inferrable-types": [
45 | true,
46 | "ignore-params"
47 | ],
48 | "no-non-null-assertion": true,
49 | "no-redundant-jsdoc": true,
50 | "no-switch-case-fall-through": true,
51 | "no-use-before-declare": true,
52 | "no-var-requires": false,
53 | "object-literal-key-quotes": [
54 | true,
55 | "as-needed"
56 | ],
57 | "object-literal-sort-keys": false,
58 | "ordered-imports": false,
59 | "quotemark": [
60 | true,
61 | "single"
62 | ],
63 | "trailing-comma": false,
64 | "no-output-on-prefix": true,
65 | "use-input-property-decorator": true,
66 | "use-output-property-decorator": true,
67 | "use-host-property-decorator": true,
68 | "no-input-rename": true,
69 | "no-output-rename": true,
70 | "use-life-cycle-interface": true,
71 | "use-pipe-transform-interface": true,
72 | "component-class-suffix": true,
73 | "directive-class-suffix": true
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/HousePriceService/Controllers/HousePriceController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using System.Collections.Generic;
3 |
4 | namespace HousePriceService.Controllers
5 | {
6 | [Route("api/[controller]")]
7 | [ApiController]
8 | public class HousePriceController : ControllerBase
9 | {
10 | // For testing point to the place where the trainer had out put the models
11 | private string _modelPath = @"C:\Users\junwi\source\repos\MLNetRegression\HousePriceTraining\bin\Debug\netcoreapp2.2\housePriceModel.zip";
12 | private string _dataTransformModelPath = @"C:\Users\junwi\source\repos\MLNetRegression\HousePriceTraining\bin\Debug\netcoreapp2.2\housePriceDataTransformer.zip";
13 |
14 | // GET api/HousePrice
15 | [HttpGet]
16 | public ActionResult> Get()
17 | {
18 | var housePriceSample1 = new HouseData() { Area = "76", BedRooms = 3, BedRoomsBsmt = 0, FullBath = 2, HalfBath = 0, Rooms = 7, ApproxSquFeet = 1300, GarageType = "Attached", GarageSpaces = 2 };
19 | HouseData[] hd = new HouseData[] { housePriceSample1 };
20 |
21 | var results = HousePricePrediction.PredictSinglePriceSet(hd, _dataTransformModelPath, _modelPath);
22 |
23 | return new string[] { results[0].ToString() };
24 | }
25 |
26 | // GET api/HousePrice/price
27 | // GET api/HousePrice/price?area=76&sqft=1300&rooms=7&bedrooms=3&fullbath=2&halfbath=0&garageType=Attached&garageSpaces=2
28 | //area=76&houseType=condo&rooms=7&bedRooms=3&bedRoomsBsmt=0&fullBath=2&halfBath=0&approxSquFeet=1200&garageType=attached&garageSpaces=2&parkingSpaces=0
29 | [HttpGet("{price}")]
30 | public ActionResult> Get([FromQuery] string area, [FromQuery] float approxSquFeet, [FromQuery] float rooms, [FromQuery] float bedrooms, [FromQuery] float fullbath,
31 | [FromQuery] float halfbath, [FromQuery] string garageType, [FromQuery] float garageSpaces)
32 | {
33 | var requestHousePriceFeatures = new HouseData() { Area = area, BedRooms = bedrooms, BedRoomsBsmt = 0, FullBath = fullbath, HalfBath = halfbath, Rooms = rooms, ApproxSquFeet = approxSquFeet, GarageType = garageType, GarageSpaces = garageSpaces };
34 | HouseData[] hd = new HouseData[] { requestHousePriceFeatures };
35 |
36 | var results = HousePricePrediction.PredictSinglePriceSet(hd, _dataTransformModelPath, _modelPath);
37 |
38 | return new string[] { results[0].ToString() };
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/HousePriceService/Dockerfile:
--------------------------------------------------------------------------------
1 | #Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
2 | #For more information, please see https://aka.ms/containercompat
3 |
4 | FROM microsoft/dotnet:2.2-aspnetcore-runtime-nanoserver-1803 AS base
5 | WORKDIR /app
6 | EXPOSE 80
7 | EXPOSE 443
8 |
9 | FROM microsoft/dotnet:2.2-sdk-nanoserver-1803 AS build
10 | WORKDIR /src
11 | COPY ["HousePriceService/HousePriceService.csproj", "HousePriceService/"]
12 | RUN dotnet restore "HousePriceService/HousePriceService.csproj"
13 | COPY . .
14 | WORKDIR "/src/HousePriceService"
15 | RUN dotnet build "HousePriceService.csproj" -c Release -o /app
16 |
17 | FROM build AS publish
18 | RUN dotnet publish "HousePriceService.csproj" -c Release -o /app
19 |
20 | FROM base AS final
21 | WORKDIR /app
22 | COPY --from=publish /app .
23 | ENTRYPOINT ["dotnet", "HousePriceService.dll"]
--------------------------------------------------------------------------------
/HousePriceService/HouseData.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML.Data;
2 |
3 | //MLS # Stat Closed Date Sold Pr Type Yr Blt Street # Str Name Area Zip ASF # Rms # Full Baths # Half Baths Bsmt Bth Beds Bsmt. Beds Garage Type # Garage Spaces # Parking Spaces
4 |
5 | namespace HousePriceService
6 | {
7 | public class HouseData
8 | {
9 | [LoadColumn(8)]
10 | public string Area;
11 |
12 | [LoadColumn(4)]
13 | public string HouseType;
14 |
15 | [LoadColumn(11)]
16 | public float Rooms;
17 |
18 | [LoadColumn(15)]
19 | public float BedRooms;
20 |
21 | [LoadColumn(16)]
22 | public float BedRoomsBsmt;
23 |
24 | [LoadColumn(12)]
25 | public float FullBath;
26 |
27 | [LoadColumn(13)]
28 | public float HalfBath;
29 |
30 | [LoadColumn(3)]
31 | public float Label;
32 |
33 | [LoadColumn(10)]
34 | public float ApproxSquFeet;
35 |
36 | [LoadColumn(17)]
37 | public string GarageType;
38 |
39 | [LoadColumn(18)]
40 | public float GarageSpaces;
41 |
42 | [LoadColumn(19)]
43 | public float ParkingSpaces;
44 | }
45 |
46 | // The output datat
47 | public class HousePrediction
48 | {
49 | [ColumnName("Score")]
50 | public float SoldPrice;
51 | }
52 | }
--------------------------------------------------------------------------------
/HousePriceService/HousePricePrediction.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML;
2 | using Microsoft.ML.Data;
3 | using System;
4 |
5 | namespace HousePriceService
6 | {
7 | public class HousePricePrediction
8 | {
9 | ///
10 | /// This takes a set of features and predicts a set of prices. It assumes taht a separate pipeline was used for
11 | /// data preparation and another for traing the model - for example using cross validation
12 | ///
13 | ///
14 | ///
15 | ///
16 | ///
17 | ///
18 | public static float[] PredictSinglePriceSet(HouseData[] houseData, string dataTransformModelPath, string outputModelPath)
19 | {
20 | float[] results = new float[houseData.Length];
21 | // create a new context
22 | MLContext mlContext = new MLContext();
23 |
24 | // Create a data view from the house data objects
25 | IDataView data = mlContext.Data.LoadFromEnumerable(houseData);
26 |
27 | // Define data preparation and trained model schemas
28 | DataViewSchema dataPrepPipelineSchema, modelSchema;
29 |
30 | // Load data preparation pipeline and trained model
31 | ITransformer dataPrepPipeline = mlContext.Model.Load(dataTransformModelPath, out dataPrepPipelineSchema);
32 | ITransformer trainedModel = mlContext.Model.Load(outputModelPath, out modelSchema);
33 |
34 | // Transform inbound data
35 | var transformedData = dataPrepPipeline.Transform(data);
36 |
37 | // Use transform to produce an set of predictions
38 | var predictedPrices = trainedModel.Transform(transformedData);
39 |
40 | // Print out the prediced prices
41 | var scoreColumn = predictedPrices.GetColumn("Score");
42 | int i = 0;
43 | foreach (var r in scoreColumn)
44 | {
45 | Console.WriteLine(r);
46 | results[i++] = r;
47 | }
48 |
49 | return results;
50 | }
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/HousePriceService/HousePriceService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 | InProcess
6 | Windows
7 | cd0c51b3-b72d-42d9-9b5f-ddd3c2e4e619
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Always
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/HousePriceService/MLNETModels/housePriceModel.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/HousePriceService/MLNETModels/housePriceModel.zip
--------------------------------------------------------------------------------
/HousePriceService/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace HousePriceService
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/HousePriceService/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:64918",
7 | "sslPort": 44327
8 | }
9 | },
10 | "$schema": "http://json.schemastore.org/launchsettings.json",
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "api/HousePrice",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "HousePriceService": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "api/values",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | },
27 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
28 | },
29 | "Docker": {
30 | "commandName": "Docker",
31 | "launchBrowser": true,
32 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/api/values"
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/HousePriceService/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 |
7 | namespace HousePriceService
8 | {
9 | public class Startup
10 | {
11 | public Startup(IConfiguration configuration)
12 | {
13 | Configuration = configuration;
14 | }
15 |
16 | public IConfiguration Configuration { get; }
17 |
18 | // This method gets called by the runtime. Use this method to add services to the container.
19 | public void ConfigureServices(IServiceCollection services)
20 | {
21 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
22 | }
23 |
24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
26 | {
27 | if (env.IsDevelopment())
28 | {
29 | app.UseDeveloperExceptionPage();
30 | }
31 | else
32 | {
33 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
34 | app.UseHsts();
35 | }
36 |
37 | app.UseHttpsRedirection();
38 | app.UseCors(builder => builder
39 | .AllowAnyOrigin()
40 | .AllowAnyMethod()
41 | .AllowAnyHeader()
42 | .AllowCredentials());
43 | app.UseMvc();
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/HousePriceService/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/HousePriceService/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/HousePriceTraining/.gitignore:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio.
3 | ################################################################################
4 |
5 | /.vs/myApp
6 | /bin/Debug/netcoreapp2.2
7 | /obj
8 | /.vs
9 |
--------------------------------------------------------------------------------
/HousePriceTraining/About.md:
--------------------------------------------------------------------------------
1 |
2 | # Applying ML.NET to a regression problem
3 |
4 | ML.NET is an opensource cross-platform machine learning framework intended for .NET developers. It provides a great set of tools to let you implement machine learning applications using .NET – you can find out more about ML.NET [here](https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet)
5 |
6 | To understand how the functionality fits into the typical workflow of accessing data, selecting features, normalisation, training the model and evaluating the fit using test data sets. I took a look at implementing a simple regression application to predict the sale price of a house given a simple set of features over about 800 home sales.
7 |
8 | The focus was on getting a small sample up and running, that can then be used to experiment with the choice of feature and training algorithms. You can find the code for this article on GitHub [here](https://github.com/junwin/MLNetRegression)
9 |
10 |
11 |
12 | ML.NET provides a developer friendly API for machine learning, in terms of:
13 | • Transforms(Feature selection, Text, Schema, Categorical, data normalization, handling missing data)
14 | • Learners(Linear, Boosted trees, SVM, K-Means)
15 | • Tools(Data framework, Evaluators, calibrators, Data Loaders)
16 |
17 | Put together these support the typical ML workflow:
18 | • Data preparation(loading and feature extraction)
19 | • Training (Training and evaluating models)
20 | • Running( using the trained model)
21 |
22 | A big advantage of using the ML.Net framework is that it allows the user to easily experiment with different learning algorithms, changing the set of features, sizes of training and test datasets to get the best results for their problem. This avoids a common issue where teams spend a lot of time collecting unnecessary data and produce models that do not perform well.
23 |
24 |
25 | Key Concept
26 |
27 | When discussing ML.Net it is important to recognize to use of:
28 | • Transformers - these convert and manipulate data and produce data as an output.
29 | • Estimators - these take data and produce a transformer or a model, e.g. when training
30 | • Prediction - this takes a single row of features and predicts a single row of results.
31 |
32 | We will see how these come into play in the simple regression sample.
33 |
34 | ML.NET lets you develop a range of ML systems
35 | • Forecasting/Regression
36 | • Issue Classification
37 | • Predictive maintenance
38 | • Image classification
39 | • Sentiment Analysis
40 | • Recommender Systems
41 | • Clustering systems
42 |
43 | In the sample we are going to take a look a supervised learning problem of
44 | Multivariate linear regression. In this case we want use one or more features to predict the sale price of a house.
45 |
46 | We will train the model using a set of sales data to predict the sale price of a house given a set of features over about 800 home sales.
47 |
48 | While the sample data has a wide range of features, a key aspect of developing a useful system would be to understand the choice of features used affects the model.
49 |
50 | 1) Training and Saving the model
51 |
52 | Our first job is to define a simple data class that we can use when loading our .csv file of house data.
53 | The important part to note is the [LoadColumn()] attributes, these allow us to associate the fields to different columns in the input.
54 | It gives us a simple way to adapt to changes in the data sets we can process.
55 | The class is also used when we want to predict the price of some house.
56 | We do not need to use all the fields in the class when training the model.
57 |
58 | ```c#
59 | public class HouseData
60 | {
61 | [LoadColumn(3)]
62 | public float Area;
63 |
64 | [LoadColumn(4)]
65 | public float Rooms;
66 |
67 | [LoadColumn(13)]
68 | public float BedRooms;
69 |
70 | [LoadColumn(12)]
71 | public float BedRoomsBsmt;
72 |
73 | [LoadColumn(5)]
74 | public float FullBath;
75 |
76 | [LoadColumn(6)]
77 | public float HalfBath;
78 |
79 | [LoadColumn(7)]
80 | public float Floors;
81 |
82 | [LoadColumn(9)]
83 | public float SoldPrice;
84 |
85 | [LoadColumn(22)]
86 | public float LotSize;
87 |
88 | [LoadColumn(16)]
89 | public string GarageType;
90 | }
91 | ```
92 |
93 | Given we have our data class, we can now read the date from the file.
94 |
95 | ```c#
96 | Console.WriteLine("Training product forecasting");
97 |
98 | // Read the sample data into a view that we can use for training
99 | var trainingDataView = mlContext.Data.ReadFromTextFile(dataPath, hasHeader: true, separatorChar: ',');
100 |
101 | // create the trainer we will use - ML.NET supports different training methods
102 | var trainer = mlContext.Regression.Trainers.FastTree(labelColumn: DefaultColumnNames.Label, featureColumn: DefaultColumnNames.Features);
103 |
104 | // Create the training pipeline, this determines how the input data will be transformed
105 | // We can also select the features we want to use here, the names used correspond to the porperty names in
106 | // HouseData
107 | string[] numericFeatureNames = { "Area","Rooms", "BedRooms", "BedRoomsBsmt", "FullBath", "HalfBath", "Floors","LotSize"};
108 |
109 | // We distinguish between features that are strings e.g. {"attached","detached","none") garage types and
110 | // Numeric faeature, since learning systems only work with numeric values we need to convert the strings.
111 | // You can see that in the training pipeline we have applied OneHotEncoding to do this.
112 | string[] categoryFeatureNames = { "GarageType" };
113 |
114 | var trainingPipeline = mlContext.Transforms.Concatenate(NumFeatures, numericFeatureNames)
115 | .Append(mlContext.Transforms.Categorical.OneHotEncoding(CatFeatures, inputColumnName: categoryFeatureNames[0]))
116 | .Append(mlContext.Transforms.Concatenate(DefaultColumnNames.Features, NumFeatures, CatFeatures))
117 | .Append(mlContext.Transforms.CopyColumns(DefaultColumnNames.Label, inputColumnName: nameof(HouseData.SoldPrice)))
118 | .Append(trainer);
119 |
120 | // Split the data 90:10 into train and test sets, train and evaluate.
121 | var (trainData, testData) = mlContext.Regression.TrainTestSplit(trainingDataView, testFraction: 0.2);
122 |
123 | ```
124 |
125 | Evaluation
126 |
--------------------------------------------------------------------------------
/HousePriceTraining/Helpers.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML;
2 | using Microsoft.ML.Data;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace myApp
7 | {
8 | internal class Helpers
9 | {
10 | public static void PrintRegressionMetrics(string algorithmName, RegressionMetrics metrics)
11 | {
12 | Console.WriteLine($"*************************************************************************************************************");
13 | Console.WriteLine($"* Metrics for {algorithmName} Regression model ");
14 | Console.WriteLine($"*------------------------------------------------------------------------------------------------------------");
15 | Console.WriteLine($"* L1 Loss: {metrics.MeanAbsoluteError:0.###} ");
16 | Console.WriteLine($"* L2 Loss: {metrics.MeanSquaredError:0.###} ");
17 | Console.WriteLine($"* RMS: {metrics.RootMeanSquaredError:0.###} ");
18 | Console.WriteLine($"* Loss Function: {metrics.LossFunction:0.###} ");
19 | Console.WriteLine($"* R-squared: {metrics.RSquared:0.###} ");
20 | Console.WriteLine($"*************************************************************************************************************");
21 | }
22 |
23 | /*
24 | * ML NET V11 needs a different signature
25 | public static void PrintRegressionFoldsAverageMetrics(string algorithmName, TrainCatalogBase.CrossValidationResult[] crossValidationResults)
26 | */
27 |
28 | /*
29 | public static void PrintRegressionFoldsAverageMetrics(string algorithmName,
30 | (RegressionMetrics metrics,
31 | ITransformer model,
32 | IDataView scoredTestData)[] crossValidationResults
33 | )
34 | */
35 |
36 | public static void PrintRegressionFoldsAverageMetrics(string algorithmName, IReadOnlyList> crossValidationResults)
37 | {
38 | Console.WriteLine($"**********************************************");
39 | Console.WriteLine($"* Metrics for {algorithmName} Regression ");
40 | Console.WriteLine($"*---------------------------------------------");
41 |
42 | foreach (var result in crossValidationResults)
43 | {
44 | Console.WriteLine($"* R-squared: {result.Metrics.RSquared:0.###} ");
45 | }
46 |
47 | Console.WriteLine($"**********************************************");
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/HousePriceTraining/HouseData.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML.Data;
2 |
3 | //MLS # Stat Closed Date Sold Pr Type Yr Blt Street # Str Name Area Zip ASF # Rms # Full Baths # Half Baths Bsmt Bth Beds Bsmt. Beds Garage Type # Garage Spaces # Parking Spaces
4 |
5 | namespace myApp
6 | {
7 | public class HouseData
8 | {
9 | [LoadColumn(8)]
10 | public string Area;
11 |
12 | [LoadColumn(4)]
13 | public string HouseType;
14 |
15 | [LoadColumn(11)]
16 | public float Rooms;
17 |
18 | [LoadColumn(15)]
19 | public float BedRooms;
20 |
21 | [LoadColumn(16)]
22 | public float BedRoomsBsmt;
23 |
24 | [LoadColumn(12)]
25 | public float FullBath;
26 |
27 | [LoadColumn(13)]
28 | public float HalfBath;
29 |
30 | [LoadColumn(3)]
31 | public float Label;
32 |
33 | [LoadColumn(10)]
34 | public float ApproxSquFeet;
35 |
36 | [LoadColumn(17)]
37 | public string GarageType;
38 |
39 | [LoadColumn(18)]
40 | public float GarageSpaces;
41 |
42 | [LoadColumn(19)]
43 | public float ParkingSpaces;
44 | }
45 |
46 | // The output datat
47 | public class HousePrediction
48 | {
49 | [ColumnName("Score")]
50 | public float SoldPrice;
51 | }
52 | }
--------------------------------------------------------------------------------
/HousePriceTraining/HousePriceModel.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML;
2 | using Microsoft.ML.Trainers.FastTree;
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | namespace myApp
8 | {
9 | public class HousePriceModel
10 | {
11 | private static string NumFeatures = nameof(NumFeatures);
12 |
13 | private static string CatFeatures = nameof(CatFeatures);
14 |
15 |
16 | ///
17 | /// Build and train the model used to predict house prices
18 | ///
19 | ///
20 | ///
21 | ///
22 | public static void CreateHousePriceModelUsingPipeline(MLContext mlContext, string dataPath, string outputModelPath)
23 | {
24 | Console.WriteLine("Training house sell price model");
25 |
26 |
27 |
28 | // Load sample data into a view that we can use for training - ML.NET provides support for
29 | // many different data types.
30 | var trainingDataView = mlContext.Data.LoadFromTextFile(dataPath, hasHeader: true, separatorChar: ',');
31 |
32 | // create the trainer we will use - ML.NET supports different training methods
33 | // some trainers support automatic feature normalization and setting regularization
34 | // ML.NET lets you choose a number of different training alogorithms
35 | var trainer = mlContext.Regression.Trainers.FastTree(labelColumnName: "Label", featureColumnName: "Features");
36 |
37 | // Feature Selection - We can also select the features we want to use here, the names used
38 | // correspond to the porperty names in HouseData
39 | string[] numericFeatureNames = { "Rooms", "BedRooms", "BedRoomsBsmt", "FullBath", "HalfBath", "ApproxSquFeet", "GarageSpaces", "ParkingSpaces" };
40 |
41 | // We distinguish between features that are strings e.g. {"attached","detached","none") garage types and
42 | // Numeric faeature, since learning systems only work with numeric values we need to convert the strings.
43 | // You can see that in the training pipeline we have applied OneHotEncoding to do this.
44 | // We have added area, since although in the data set its a number, it could be some other code.
45 | string[] categoryFeatureNames = { "GarageType", "Area" };
46 |
47 | // ML.NET combines transforms for data preparation and model training into a single pipeline, these are then applied
48 | // to training data and the input data used to make predictions in your model.
49 | /*
50 | var trainingPipeline = mlContext.Transforms.Concatenate(NumFeatures, numericFeatureNames)
51 | .Append(mlContext.Transforms.Categorical.OneHotEncoding("CatGarageType", inputColumnName: categoryFeatureNames[0]))
52 | .Append(mlContext.Transforms.Categorical.OneHotEncoding("CatArea", inputColumnName: categoryFeatureNames[1]))
53 | .Append(mlContext.Transforms.Concatenate("Features", NumFeatures, "CatGarageType", "CatArea"))
54 | .Append(mlContext.Transforms.CopyColumns("Label", inputColumnName: nameof(HouseData.SoldPrice)))
55 | //.Append(mlContext.Transforms.NormalizeMinMax("Features"));
56 | .Append(trainer);
57 | */
58 |
59 | var trainingPipeline = mlContext.Transforms.Categorical.OneHotEncoding("CatGarageType", inputColumnName: categoryFeatureNames[0])
60 | .Append(mlContext.Transforms.Categorical.OneHotEncoding("CatArea", inputColumnName: categoryFeatureNames[1]))
61 | .Append(mlContext.Transforms.Concatenate("Features", "Rooms", "BedRooms", "BedRoomsBsmt", "FullBath", "HalfBath", "ApproxSquFeet", "GarageSpaces", "ParkingSpaces", "CatGarageType", "CatArea"))
62 | .Append(trainer);
63 |
64 | // Train the model
65 | var model = trainingPipeline.Fit(trainingDataView);
66 |
67 | // Save the model for later comsumption from end-user apps
68 | using (var file = File.OpenWrite(outputModelPath))
69 | mlContext.Model.Save(model, trainingDataView.Schema, file);
70 | }
71 |
72 | public static void CreateHousePriceModelUsingCrossValidationPipeline(MLContext mlContext, string dataPath, string dataTransformModelPath, string outputModelPath)
73 | {
74 | Console.WriteLine("Training house sell price model");
75 |
76 | // Load sample data into a view that we can use for training - ML.NET provides support for
77 | // many different data types.
78 | var trainingDataView = mlContext.Data.LoadFromTextFile(dataPath, hasHeader: true, separatorChar: ',');
79 |
80 | // create the trainer we will use - ML.NET supports different training methods
81 | // some trainers support automatic feature normalization and setting regularization
82 | // ML.NET lets you choose a number of different training alogorithm
83 |
84 | var trainer = mlContext.Regression.Trainers.Sdca();
85 |
86 | // Feature Selection - We can also select the features we want to use here, the names used
87 | // correspond to the porperty names in HouseData
88 | // We distinguish between features that are strings e.g. {"attached","detached","none")
89 | // and normal numeric features, since learning systems we use here only work
90 | // with numeric values we need to convert the strings when setting up the pipeline
91 | // You can see that in the training pipeline we have applied OneHotEncoding to do this.
92 | // We have added area, since although in the data set its a number, it could be some other code
93 | // The pipeline below works with transforms the data to the for we can use in a
94 | // separate pipline for cross validation - often you can combine these into a single pipeline see above
95 | var dataTransformPipeline = mlContext.Transforms.Categorical.OneHotEncoding("CatGarageType", inputColumnName: "GarageType")
96 | .Append(mlContext.Transforms.Categorical.OneHotEncoding("CatArea", inputColumnName: "Area"))
97 | .Append(mlContext.Transforms.Concatenate("Features", "Rooms", "BedRooms", "BedRoomsBsmt", "FullBath", "HalfBath"
98 | , "ApproxSquFeet", "GarageSpaces", "ParkingSpaces", "CatGarageType", "CatArea"));
99 |
100 | // We use cross-valdiation to estimate the variance of the model quality from one run to another,
101 | // it and also eliminates the need to extract a separate test set for evaluation.
102 | // We display the quality metrics in order to evaluate and get the model's accuracy metrics
103 | Console.WriteLine("=============== Cross-validating to get model's accuracy metrics ===============");
104 |
105 | // data transform pipeline to convert he HouseData taining feature set
106 | var transformer = dataTransformPipeline.Fit(trainingDataView);
107 | var transformedData = transformer.Transform(trainingDataView);
108 |
109 | // train and corss validate - this returns a model and training meteric for each
110 | // fold, in this case I have chosen 3 folds
111 | var cvResults = mlContext.Regression.CrossValidate(transformedData, trainer, numberOfFolds: 3);
112 |
113 | // We will use th RSqured metric to judge the how well we have fitted
114 | // the data - the closer to 1, the better the fit.
115 | // Select all models and use the one with the best RSquared result
116 | ITransformer[] models =
117 | cvResults
118 | .OrderByDescending(fold => fold.Metrics.RSquared)
119 | .Select(fold => fold.Model)
120 | .ToArray();
121 |
122 | // Model with best fit
123 | ITransformer topModel = models[0];
124 |
125 | // print the stats
126 | Helpers.PrintRegressionFoldsAverageMetrics(trainer.ToString(), cvResults);
127 |
128 | // Save the model for later comsumption from end-user apps
129 | // since we have 2 pipelines we need to save both
130 | if (File.Exists(outputModelPath))
131 | {
132 | File.Delete(outputModelPath);
133 | }
134 |
135 | if (File.Exists(dataTransformModelPath))
136 | {
137 | File.Delete(dataTransformModelPath);
138 | }
139 |
140 | // save the pipeline used to tranform the data and the pipeline used in training
141 | using (var file = File.OpenWrite(dataTransformModelPath))
142 | mlContext.Model.Save(transformer, trainingDataView.Schema, file);
143 |
144 | using (var file = File.OpenWrite(outputModelPath))
145 | mlContext.Model.Save(topModel, transformedData.Schema, file);
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/HousePriceTraining/HousePricePrediction.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML;
2 | using Microsoft.ML.Data;
3 | using System;
4 | using System.IO;
5 |
6 | namespace myApp
7 | {
8 | public class HousePricePrediction
9 | {
10 | ///
11 | /// Use a trained model to predict a house sale price - this works when a single pipeline
12 | /// has been used when creating the model
13 | ///
14 | ///
15 | ///
16 | ///
17 | ///
18 | public static void PredictSinglePrice(HouseData houseData, MLContext mlContext, string outputModelPath = "housePriceModel.zip")
19 | {
20 | // Load the prediction model we saved earlier
21 | ITransformer loadedModel;
22 | DataViewSchema dataViewSchema;
23 | using (var stream = new FileStream(outputModelPath, FileMode.Open, FileAccess.Read, FileShare.Read))
24 | {
25 | loadedModel = mlContext.Model.Load(stream, out dataViewSchema);
26 | }
27 |
28 | // Create a handy function based on our HouseData class and a class to contain the result
29 | //var predictionFunction = loadedModel.
30 | var predictionFunction = mlContext.Model.CreatePredictionEngine(loadedModel, dataViewSchema);
31 |
32 | // Predict the Sale price - TA DA
33 | var prediction = predictionFunction.Predict(houseData);
34 |
35 | var pv = prediction.SoldPrice;
36 |
37 | Console.WriteLine($"**********************************************************************");
38 | Console.WriteLine($"Predicted SellPrice: {pv:0.####}");
39 | Console.WriteLine($"**********************************************************************");
40 | }
41 |
42 | ///
43 | /// This takes a set of features and predicts a set of prices. It assumes taht a separate pipeline was used for
44 | /// data preparation and another for traing the model - for example using cross validation
45 | ///
46 | ///
47 | ///
48 | ///
49 | ///
50 | ///
51 | public static float[] PredictSinglePriceSet(HouseData[] houseData, string dataTransformModelPath, string outputModelPath)
52 | {
53 |
54 | // create a new context
55 | MLContext mlContext = new MLContext();
56 |
57 | // Create a data view from the house data objects
58 | IDataView data = mlContext.Data.LoadFromEnumerable(houseData);
59 |
60 | // Define data preparation and trained model schemas
61 | DataViewSchema dataPrepPipelineSchema, modelSchema;
62 |
63 | // Load data preparation pipeline and trained model
64 | ITransformer dataPrepPipeline = mlContext.Model.Load(dataTransformModelPath, out dataPrepPipelineSchema);
65 | ITransformer trainedModel = mlContext.Model.Load(outputModelPath, out modelSchema);
66 |
67 | // Transform inbound data
68 | var transformedData = dataPrepPipeline.Transform(data);
69 |
70 | // Use transform to produce an set of predictions
71 | var predictedPrices = trainedModel.Transform(transformedData);
72 |
73 | // get the result set and print out the values
74 | float[] results = new float[houseData.Length];
75 | var scoreColumn = predictedPrices.GetColumn("Score");
76 |
77 | int i = 0;
78 | foreach (var r in scoreColumn)
79 | {
80 | Console.WriteLine(r);
81 | results[i++] = r;
82 | }
83 |
84 | return results;
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/HousePriceTraining/HousePriceTraining.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Always
16 |
17 |
18 | Always
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/HousePriceTraining/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ML;
2 | using System;
3 | using System.IO;
4 |
5 | namespace myApp
6 | {
7 | internal class Program
8 | {
9 | // Define input files and where the trained model will be stored
10 | private static readonly string _trainDataPath = Path.Combine(Environment.CurrentDirectory, "HouseData.csv");
11 |
12 | private static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "housePriceModel.zip");
13 | private static readonly string _dataTransformModelPath = Path.Combine(Environment.CurrentDirectory, "housePriceDataTransformer.zip");
14 |
15 | private static void Main(string[] args)
16 | {
17 | // STEP 2: Create a ML.NET environment
18 | MLContext mlContext = new MLContext(seed: 0);
19 |
20 | // set up some test data
21 | var housePriceSample1 = new HouseData() { Area = "76", BedRooms = 3, BedRoomsBsmt = 0, FullBath = 2, HalfBath = 0, Rooms = 7, ApproxSquFeet = 1300, GarageType = "Attached", GarageSpaces = 2 };
22 | var housePriceSample2 = new HouseData() { Area = "62", BedRooms = 5, BedRoomsBsmt = 1, FullBath = 6, HalfBath = 1, Rooms = 16, ApproxSquFeet = 8410, GarageType = "Attached", GarageSpaces = 4 };
23 |
24 | // Train and Save the model
25 | // HousePriceModel.TrainAndSaveModel(mlContext, _trainDataPath, _modelPath);
26 | /*
27 | // Run a few test examples
28 |
29 | HousePricePrediction.PredictSinglePrice(housePriceSample1, mlContext, _modelPath);
30 | HousePricePrediction.PredictSinglePrice(housePriceSample2, mlContext, _modelPath);
31 | */
32 |
33 | // Train and Save the model using crossvalidation
34 | HousePriceModel.CreateHousePriceModelUsingCrossValidationPipeline(mlContext, _trainDataPath, _dataTransformModelPath, _modelPath);
35 |
36 | // Run a few test examples
37 | HouseData[] hd = new HouseData[] { housePriceSample1, housePriceSample2 };
38 |
39 | var results = HousePricePrediction.PredictSinglePriceSet(hd, _dataTransformModelPath, _modelPath);
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/HousePriceTraining/README.md:
--------------------------------------------------------------------------------
1 | # Predicting a house price using ML .NET
2 |
3 | # House price sample
4 | To understand how the functionality fits into the typical workflow of data preparation, training the model and evaluating the fit using test data sets and using the model. I took a look at implementing a simple regression application to predict the sale price of a house given a simple set of features over about 800 home sales. In the sample, we are going to take a look at a supervised learning problem of Multivariate linear regression. A supervised learning task is used to predice the value of a label from a set of features. In this case, we want to use one or more features to predict the sale price(the label) of a house.
5 |
6 | The focus was on getting a small sample up and running, that can then be used to experiment with the choice of feature and training algorithms. You can find the code for this article on [GitHub here](https://github.com/junwin/MLNetRegression)
7 |
8 | We will train the model using a set of sales data to predict the sale price of a house given a set of features over about 800 home sales. While the sample data has a wide range of features, a key aspect of developing a useful system would be to understand the choice of features used affects the model.
9 |
10 | # Before you start
11 |
12 | You can find a [10 minute tutorial](https://dotnet.microsoft.com/learn/machinelearning-ai/ml-dotnet-get-started-tutorial/intro) that will take you through installing and pre requisits - or just use the following steps.
13 |
14 | You will need to have Visual Studio 16.6 or later with the .NET Core installed you can get there [here](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=docs.microsoft.com&utm_campaign=button+cta&utm_content=download+vs2017)
15 |
16 | To start building .NET apps you just need to download and install the [.NET SDK](https://download.visualstudio.microsoft.com/download/pr/48d03227-4429-4daa-ab6a-78840bc61ea5/b815b04bd689bf15a9d95668624a77fb/dotnet-sdk-2.2.104-win-gs-x64.exe).
17 |
18 | Install the ML.Net Package by running the following in a command prompt
19 | ```
20 | dotnet add package Microsoft.ML --version 0.10.0
21 | ```
22 |
--------------------------------------------------------------------------------
/myApp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.271
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HousePriceService", "HousePriceService\HousePriceService.csproj", "{B945B2ED-1C47-45A9-96D8-3615C1A70261}"
7 | EndProject
8 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "HousePricePredictorWeb", "HousePricePredictorWeb\", "{1A549FA3-EED6-40AD-9684-9E9C901C31A6}"
9 | ProjectSection(WebsiteProperties) = preProject
10 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.0"
11 | Debug.AspNetCompiler.VirtualPath = "/localhost_52274"
12 | Debug.AspNetCompiler.PhysicalPath = "HousePricePredictorWeb\"
13 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_52274\"
14 | Debug.AspNetCompiler.Updateable = "true"
15 | Debug.AspNetCompiler.ForceOverwrite = "true"
16 | Debug.AspNetCompiler.FixedNames = "false"
17 | Debug.AspNetCompiler.Debug = "True"
18 | Release.AspNetCompiler.VirtualPath = "/localhost_52274"
19 | Release.AspNetCompiler.PhysicalPath = "HousePricePredictorWeb\"
20 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_52274\"
21 | Release.AspNetCompiler.Updateable = "true"
22 | Release.AspNetCompiler.ForceOverwrite = "true"
23 | Release.AspNetCompiler.FixedNames = "false"
24 | Release.AspNetCompiler.Debug = "False"
25 | VWDPort = "52274"
26 | SlnRelativePath = "HousePricePredictorWeb\"
27 | EndProjectSection
28 | EndProject
29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HousePriceTraining", "HousePriceTraining\HousePriceTraining.csproj", "{069960BF-DAF1-4D18-AB49-BD35CA7280AC}"
30 | EndProject
31 | Global
32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
33 | Debug|Any CPU = Debug|Any CPU
34 | Release|Any CPU = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
37 | {B945B2ED-1C47-45A9-96D8-3615C1A70261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {B945B2ED-1C47-45A9-96D8-3615C1A70261}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {B945B2ED-1C47-45A9-96D8-3615C1A70261}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {B945B2ED-1C47-45A9-96D8-3615C1A70261}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {1A549FA3-EED6-40AD-9684-9E9C901C31A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {1A549FA3-EED6-40AD-9684-9E9C901C31A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {1A549FA3-EED6-40AD-9684-9E9C901C31A6}.Release|Any CPU.ActiveCfg = Debug|Any CPU
44 | {1A549FA3-EED6-40AD-9684-9E9C901C31A6}.Release|Any CPU.Build.0 = Debug|Any CPU
45 | {069960BF-DAF1-4D18-AB49-BD35CA7280AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {069960BF-DAF1-4D18-AB49-BD35CA7280AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {069960BF-DAF1-4D18-AB49-BD35CA7280AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {069960BF-DAF1-4D18-AB49-BD35CA7280AC}.Release|Any CPU.Build.0 = Release|Any CPU
49 | EndGlobalSection
50 | GlobalSection(SolutionProperties) = preSolution
51 | HideSolutionNode = FALSE
52 | EndGlobalSection
53 | GlobalSection(ExtensibilityGlobals) = postSolution
54 | SolutionGuid = {FCF113C5-48A8-4D69-BD75-280FE9E56F5C}
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/obj/Debug/netcoreapp2.2/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | using System;
12 | using System.Reflection;
13 |
14 | [assembly: System.Reflection.AssemblyCompanyAttribute("myApp")]
15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
18 | [assembly: System.Reflection.AssemblyProductAttribute("myApp")]
19 | [assembly: System.Reflection.AssemblyTitleAttribute("myApp")]
20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
21 |
22 | // Generated by the MSBuild WriteCodeFragment class.
23 |
24 |
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.AssemblyInfoInputs.cache:
--------------------------------------------------------------------------------
1 | 02f7e09988378261a23dbd17e07d74cd978e6222
2 |
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.assets.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/obj/Debug/netcoreapp2.2/myApp.assets.cache
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.csproj.CoreCompileInputs.cache:
--------------------------------------------------------------------------------
1 | f2ccc039a15fe1b383fefa8189a71c16210b7f7c
2 |
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | C:\Users\junwi\source\repos\MLNetRegression\obj\Debug\netcoreapp2.2\myApp.csprojAssemblyReference.cache
2 | C:\Users\junwi\source\repos\MLNetRegression\obj\Debug\netcoreapp2.2\myApp.csproj.CoreCompileInputs.cache
3 | C:\Users\junwi\source\repos\MLNetRegression\obj\Debug\netcoreapp2.2\myApp.AssemblyInfoInputs.cache
4 | C:\Users\junwi\source\repos\MLNetRegression\obj\Debug\netcoreapp2.2\myApp.AssemblyInfo.cs
5 |
--------------------------------------------------------------------------------
/obj/Debug/netcoreapp2.2/myApp.csprojAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/junwin/MLNetRegression/f79c2c0db739530c6af0ef4675dda7d2644b7f0f/obj/Debug/netcoreapp2.2/myApp.csprojAssemblyReference.cache
--------------------------------------------------------------------------------
/obj/myApp.csproj.nuget.cache:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "dgSpecHash": "fzaE/ib8fArw04Ohrg2f5I48mzJWlNJURarNztN37ibVogs3eU0O+ZMRzUGFy81gCI6gsK0n0FhwMX62f/cShQ==",
4 | "success": true
5 | }
--------------------------------------------------------------------------------
/obj/myApp.csproj.nuget.g.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | NuGet
6 | C:\Users\junwi\source\repos\MLNetRegression\obj\project.assets.json
7 | $(UserProfile)\.nuget\packages\
8 | C:\Users\junwi\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder
9 | PackageReference
10 | 4.9.3
11 |
12 |
13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
14 |
15 |
16 |
17 |
18 |
19 |
20 | C:\Users\junwi\.nuget\packages\newtonsoft.json\10.0.3
21 |
22 |
--------------------------------------------------------------------------------
/obj/myApp.csproj.nuget.g.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------