I will be giving a talk titled “Introduction to Neural Networks Using C#” at the 2025 Visual Studio Live conference, March 10-14, in Las Vegas. A big part of my talk will be demonstrating a multi-class classification system. I figured I’d go over my existing implementation and clean up a few details.
I used one of my standard synthetic datasets where the goal is to predict a person’s political leaning (conservative, moderate, liberal) from sex, age, State, and income. The data looks Like:
1, 0.24, 1, 0, 0, 0.2950, 2 -1, 0.39, 0, 0, 1, 0.5120, 1 1, 0.63, 0, 1, 0, 0.7580, 0 . . .
The fields are sex (-1 = male, +1 = female), age (divided by 100), State (Michigan = 100, Nebraska = 010, Oklahoma = 001, income (divided by $100,000), political leaning (conservative = 0, moderate = 1, liberal = 2). There are 200 training items and 40 test items.
For my architecture, I used a single hidden layer (deep neural networks are possible with C#, but using PyTorch is a better option), with tanh() hidden activation, and softmax() output activation. For weight and bias initialization, I used uniform random in [-0.10, +0.10].
For training, I implemented the batch (aka mini-batch) algorithm where I accumulate the gradients in each batch and then divide by the batch size. For the loss function, I used mean cross entropy error (aka negative log likelihood) which simplifies the calculation of the gradients, compared to using mean squared error. For my demo, I used a batch size of 10 with a constant (non-adaptive) learning rate of 0.01 and max epochs = 1000.
My demo computes a simple classification accuracy. I also implemented a simple confusion matrix that shows more detailed information.
In principle, all the parts of a neural network classifier are simple, but there are many different parts to deal with. That said, neural networks from scratch are beautiful to my eye.
It’s not possible to explain the demo program in a single blog post — even a moderate explanation would take roughly 100 pages (I know because I’ve done it before). So, I’ll just say, if you came across this blog post while searching the Internet for an example of a from-scratch neural network classifier, examine the code below.

Neural networks are simultaneously complex and simple and beautiful (to me at least). Sometimes I entertain myself by starting with an image and then doing repeated image searches on the Internet for similar images, just to see how one image can morph to others due to varying levels of abstraction. Here are three attractive portraits (again, to me anyway) that range from complex to simple.
Demo program. Replace “lt”, “gt”, “lte”, “gte” with Boolean operator symbols. (My blog editor often chokes on symbols).
using System;
using System.IO;
using System.Collections.Generic;
namespace NeuralNetworkMultiClassification
{
internal class NeuralNetworkMultiClassificationProgram
{
static void Main(string[] args)
{
Console.WriteLine("\nNeural network " +
"multi-class classification C# ");
Console.WriteLine("Predict political leaning (con," +
" mod, lib) from sex, age, State, income ");
// ----------------------------------------------------
string trainFile =
"..\\..\\..\\Data\\people_train.txt";
// sex, age, State, income, politics
// 1, 0.24, 1, 0, 0, 0.29500, 2
// -1, 0.39, 0, 0, 1, 0.51200, 1
// 1, 0.63, 0, 1, 0, 0.75800, 0
double[][] trainX = Utils.MatLoad(trainFile,
new int[] { 0, 1, 2, 3, 4, 5 }, ',', "#");
double[][] trainY = Utils.MatLoad(trainFile, new int[]
{ 6 }, ',', "#");
trainY = Utils.MatToOneHot(trainY, 3);
string testFile =
"..\\..\\..\\Data\\people_test.txt";
double[][] testX = Utils.MatLoad(testFile,
new int[] { 0, 1, 2, 3, 4, 5 }, ',', "#");
double[][] testY = Utils.MatLoad(testFile, new int[]
{ 6 }, ',', "#");
testY = Utils.MatToOneHot(testY, 3);
Console.WriteLine("\nFirst three X data: ");
for (int i = 0; i "lt" 3; ++i)
Utils.VecShow(trainX[i], 5, 9, true);
Console.WriteLine("\nFirst three target Y: ");
for (int i = 0; i "lt" 3; ++i)
Utils.VecShow(trainY[i], 1, 5, true);
// ----------------------------------------------------
Console.WriteLine("\nCreating 6-100-3 tanh()" +
" softmax() neural network ");
NeuralNetwork nn =
new NeuralNetwork(6, 100, 3); // seed = 0 default
int maxEpochs = 1000;
double lrnRate = 0.01;
int batSize = 10; // train = 200 items
Console.WriteLine("\nmaxEpochs = " +
maxEpochs);
Console.WriteLine("lrnRate = " +
lrnRate.ToString("F3"));
Console.WriteLine("batSize = " + batSize);
Console.WriteLine("\nStarting (batch) training ");
nn.TrainBatch(trainX, trainY, lrnRate,
batSize, maxEpochs);
Console.WriteLine("Done ");
double trainAcc = nn.Accuracy(trainX, trainY);
Console.WriteLine("\nAccuracy on train data = " +
trainAcc.ToString("F4"));
double testAcc = nn.Accuracy(testX, testY);
Console.WriteLine("Accuracy on test data = " +
testAcc.ToString("F4"));
Console.WriteLine("\nConstructing confusion matrix ");
int[][] cm = nn.ConfusionMatrix(testX, testY);
nn.ShowConfusion(cm);
Console.WriteLine("\nPredicting politics (con," +
" mod, lib) for male 35 Michigan $49,000 ");
double[] X = new double[] { -1, 0.35, 1, 0, 0, 0.49000 };
double[] y = nn.ComputeOutput(X);
Console.WriteLine("pseudo-probs: ");
Utils.VecShow(y, 4, 9, true);
Console.WriteLine("\nSaving model wts to file ");
nn.SaveWeights("..\\..\\..\\Models\\weights.txt");
Console.WriteLine("Done ");
Console.WriteLine("\nEnd NN multi-class classification ");
Console.ReadLine();
} // Main
} // Program
// --------------------------------------------------------
public class NeuralNetwork
{
private int ni; // number input nodes
private int nh; // hidden
private int no; // output
private double[] iNodes;
private double[][] ihWeights; // input-hidden
private double[] hBiases;
private double[] hNodes;
private double[][] hoWeights; // hidden-output
private double[] oBiases;
private double[] oNodes;
// gradients
private double[][] ihGrads;
private double[] hbGrads;
private double[][] hoGrads;
private double[] obGrads;
private Random rnd; // wt init and train shuffle
// ------------------------------------------------------
public NeuralNetwork(int numIn, int numHid,
int numOut, int seed = 0)
{
this.ni = numIn; // 6 for this demo
this.nh = numHid; //
this.no = numOut; // 3
this.iNodes = new double[numIn];
this.ihWeights = Utils.MatCreate(numIn, numHid);
this.hBiases = new double[numHid];
this.hNodes = new double[numHid];
this.hoWeights = Utils.MatCreate(numHid, numOut);
this.oBiases = new double[numOut];
this.oNodes = new double[numOut];
this.ihGrads = Utils.MatCreate(numIn, numHid);
this.hbGrads = new double[numHid];
this.hoGrads = Utils.MatCreate(numHid, numOut);
this.obGrads = new double[numOut];
this.rnd = new Random(seed);
this.InitWeights(); // all weights and biases
} // ctor
// ------------------------------------------------------
private void InitWeights() // helper for ctor
{
// weights and biases to small random values
double lo = -0.10; double hi = +0.10;
int numWts = (this.ni * this.nh) +
(this.nh * this.no) + this.nh + this.no;
double[] initialWeights = new double[numWts];
for (int i = 0; i "lt" initialWeights.Length; ++i)
initialWeights[i] =
(hi - lo) * rnd.NextDouble() + lo;
this.SetWeights(initialWeights);
}
// ------------------------------------------------------
public void SetWeights(double[] wts)
{
// copy serialized weights and biases in wts[]
// to ih weights, ih biases, ho weights, ho biases
int numWts = (this.ni * this.nh) +
(this.nh * this.no) + this.nh + this.no;
if (wts.Length != numWts)
throw new Exception("Bad array in SetWeights");
int k = 0; // points into wts param
for (int i = 0; i "lt" this.ni; ++i)
for (int j = 0; j "lt" this.nh; ++j)
this.ihWeights[i][j] = wts[k++];
for (int i = 0; i "lt" this.nh; ++i)
this.hBiases[i] = wts[k++];
for (int i = 0; i "lt" this.nh; ++i)
for (int j = 0; j "lt" this.no; ++j)
this.hoWeights[i][j] = wts[k++];
for (int i = 0; i "lt" this.no; ++i)
this.oBiases[i] = wts[k++];
}
// ------------------------------------------------------
public double[] GetWeights()
{
int numWts = (this.ni * this.nh) +
(this.nh * this.no) + this.nh + this.no;
double[] result = new double[numWts];
int k = 0;
for (int i = 0; i "lt" ihWeights.Length; ++i)
for (int j = 0; j "lt" this.ihWeights[0].Length; ++j)
result[k++] = this.ihWeights[i][j];
for (int i = 0; i "lt" this.hBiases.Length; ++i)
result[k++] = this.hBiases[i];
for (int i = 0; i "lt" this.hoWeights.Length; ++i)
for (int j = 0; j "lt" this.hoWeights[0].Length; ++j)
result[k++] = this.hoWeights[i][j];
for (int i = 0; i "lt" this.oBiases.Length; ++i)
result[k++] = this.oBiases[i];
return result;
}
// ------------------------------------------------------
public double[] ComputeOutput(double[] x)
{
double[] hSums = new double[this.nh]; // scratch
double[] oSums = new double[this.no]; // out sums
for (int i = 0; i "lt" x.Length; ++i)
this.iNodes[i] = x[i];
// note: no need to copy x-values unless
// you implement a ToString.
// more efficient to simply use the x[] directly.
// 1. compute i-h sum of weights * inputs
for (int j = 0; j "lt" this.nh; ++j)
for (int i = 0; i "lt" this.ni; ++i)
hSums[j] += this.iNodes[i] *
this.ihWeights[i][j]; // note +=
// 2. add biases to hidden sums
for (int i = 0; i "lt" this.nh; ++i)
hSums[i] += this.hBiases[i];
// 3. apply hidden activation
for (int i = 0; i "lt" this.nh; ++i)
this.hNodes[i] = HyperTan(hSums[i]);
// 4. compute h-o sum of wts * hOutputs
for (int j = 0; j "lt" this.no; ++j)
for (int i = 0; i "lt" this.nh; ++i)
oSums[j] += this.hNodes[i] *
this.hoWeights[i][j]; // [1]
// 5. add biases to output sums
for (int i = 0; i "lt" this.no; ++i)
oSums[i] += this.oBiases[i];
double[] softOut = Softmax(oSums);
Array.Copy(softOut, this.oNodes, softOut.Length);
double[] retResult = new double[this.no];
Array.Copy(this.oNodes, retResult, retResult.Length);
return retResult;
}
// ------------------------------------------------------
private static double HyperTan(double x)
{
if (x "lt" -10.0) return -1.0;
else if (x "gt" 10.0) return 1.0;
else return Math.Tanh(x);
}
// ------------------------------------------------------
private static double[] Softmax(double[] logits)
{
// determine max logit
// does all output nodes at once so scale
// doesn't have to be re-computed each time
double max = logits[0];
for (int i = 0; i "lt" logits.Length; ++i)
if (logits[i] "gt" max) max = logits[i];
// scaling factor -- sum of exp(each val - max)
double scale = 0.0;
for (int i = 0; i "lt" logits.Length; ++i)
scale += Math.Exp(logits[i] - max);
double[] result = new double[logits.Length];
for (int i = 0; i "lt" logits.Length; ++i)
result[i] = Math.Exp(logits[i] - max) / scale;
return result; // now scaled so that xi sum to 1.0
}
// ------------------------------------------------------
private void ZeroOutGrads()
{
for (int i = 0; i "lt" this.ni; ++i)
for (int j = 0; j "lt" this.nh; ++j)
this.ihGrads[i][j] = 0.0;
for (int j = 0; j "lt" this.nh; ++j)
this.hbGrads[j] = 0.0;
for (int j = 0; j "lt" this.nh; ++j)
for (int k = 0; k "lt" this.no; ++k)
this.hoGrads[j][k] = 0.0;
for (int k = 0; k "lt" this.no; ++k)
this.obGrads[k] = 0.0;
} // ZeroOutGrads()
private void AccumGrads(double[] y)
{
double[] oSignals = new double[this.no];
double[] hSignals = new double[this.nh];
// 1. compute output node scratch signals
for (int k = 0; k "lt" this.no; ++k)
{
double derivative = 1.0; // CEE
//double derivative =
// this.oNodes[k] * (1 - this.oNodes[k]); // MSE
oSignals[k] = derivative *
(this.oNodes[k] - y[k]); // CEE
}
// 2. accum hidden-to-output gradients
for (int j = 0; j "lt" this.nh; ++j)
for (int k = 0; k "lt" this.no; ++k)
hoGrads[j][k] +=
oSignals[k] * this.hNodes[j];
// 3. accum output node bias gradients
for (int k = 0; k "lt" this.no; ++k)
obGrads[k] +=
oSignals[k] * 1.0; // 1.0 dummy
// 4. compute hidden node signals
for (int j = 0; j "lt" this.nh; ++j)
{
double sum = 0.0;
for (int k = 0; k "lt" this.no; ++k)
sum += oSignals[k] * this.hoWeights[j][k];
double derivative =
(1 - this.hNodes[j]) *
(1 + this.hNodes[j]); // assumes tanh
hSignals[j] = derivative * sum;
}
// 5. accum input-to-hidden gradients
for (int i = 0; i "lt" this.ni; ++i)
for (int j = 0; j "lt" this.nh; ++j)
this.ihGrads[i][j] +=
hSignals[j] * this.iNodes[i];
// 6. accum hidden node bias gradients
for (int j = 0; j "lt" this.nh; ++j)
this.hbGrads[j] +=
hSignals[j] * 1.0; // 1.0 dummy
} // AccumGrads
// ------------------------------------------------------
private void UpdateWeights(double lrnRate)
{
// assumes all gradients computed
// 1. update input-to-hidden weights
for (int i = 0; i "lt" this.ni; ++i)
{
for (int j = 0; j "lt" this.nh; ++j)
{
double delta = -1.0 * lrnRate *
this.ihGrads[i][j];
this.ihWeights[i][j] += delta;
}
}
// 2. update hidden node biases
for (int j = 0; j "lt" this.nh; ++j)
{
double delta = -1.0 * lrnRate *
this.hbGrads[j];
this.hBiases[j] += delta;
}
// 3. update hidden-to-output weights
for (int j = 0; j "lt" this.nh; ++j)
{
for (int k = 0; k "lt" this.no; ++k)
{
double delta = -1.0 * lrnRate *
this.hoGrads[j][k];
this.hoWeights[j][k] += delta;
}
}
// 4. update output node biases
for (int k = 0; k "lt" this.no; ++k)
{
double delta = -1.0 * lrnRate *
this.obGrads[k];
this.oBiases[k] += delta;
}
} // UpdateWeights()
public void TrainBatch(double[][] trainX,
double[][] trainY, double lrnRate, int batSize,
int maxEpochs)
{
int n = trainX.Length; // 200
int batchesPerEpoch = n / batSize; // 20
int freq = maxEpochs / 10; // to show progress
int[] indices = new int[n];
for (int i = 0; i "lt" n; ++i)
indices[i] = i;
// ----------------------------------------------------
//
// n = 200; bs = 10
// batches per epoch = 200 / 10 = 20
// for epoch = 0; epoch "lt" maxEpochs; ++epoch
// for batch = 0; batch "lt" bpe; ++batch
// for item = 0; item "lt" bs; ++item
// compute output
// accum grads
// end-item
// update weights
// zero-out grads
// end-batches
// shuffle indices
// end-epochs
//
// ----------------------------------------------------
for (int epoch = 0; epoch "lt" maxEpochs; ++epoch)
{
Shuffle(indices);
int ptr = 0; // points into indices
for (int batIdx = 0; batIdx "lt" batchesPerEpoch;
++batIdx) // 0, 1, . . 19
{
for (int i = 0; i "lt" batSize; ++i) // 0 . . 9
{
int ii = indices[ptr++]; // compute output
double[] x = trainX[ii];
double[] y = trainY[ii];
this.ComputeOutput(x); // into this.oNoodes
this.AccumGrads(y);
}
this.UpdateWeights(lrnRate);
this.ZeroOutGrads(); // prep for next batch
} // batches
if (epoch % freq == 0) // progress every few epochs
{
double mcee =
this.MeanCrossEntError(trainX, trainY);
double acc =
this.Accuracy(trainX, trainY);
string s1 = "epoch: " +
epoch.ToString().PadLeft(4);
string s2 = " MCEE = " +
mcee.ToString("F4");
string s3 = " acc = " +
acc.ToString("F4");
Console.WriteLine(s1 + s2 + s3);
}
} // epoch
} // TrainBatch
// ------------------------------------------------------
private void Shuffle(int[] sequence)
{
// Fisher-Yates
for (int i = 0; i "lt" sequence.Length; ++i)
{
int r = this.rnd.Next(i, sequence.Length);
int tmp = sequence[r];
sequence[r] = sequence[i];
sequence[i] = tmp;
// sequence[i] = i; // for testing
}
} // Shuffle
// ------------------------------------------------------
public double MeanSqError(double[][] trainX,
double[][] trainY)
{
// MSE - useful for progress (easier to interpret)
int n = trainX.Length;
double sumSquaredError = 0.0;
for (int i = 0; i "lt" n; ++i)
{
double[] predY = this.ComputeOutput(trainX[i]);
double[] actualY = trainY[i];
for (int j = 0; j "lt" this.no; ++j)
{
sumSquaredError += (predY[j] - actualY[j]) *
(predY[j] - actualY[j]);
}
}
return sumSquaredError / n;
} // MSE loss
// ------------------------------------------------------
public double MeanCrossEntError(double[][] trainX,
double[][] trainY)
{
int n = trainX.Length;
double sum = 0.0;
for (int i = 0; i "lt" n; ++i)
{
double[] predY = this.ComputeOutput(trainX[i]);
int idx = ArgMax(trainY[i]); // loc of 1.0 target
sum += -Math.Log(predY[idx]);
}
return sum / n;
} // MCEE loss
// ------------------------------------------------------
private static int ArgMax(double[] v)
{
// index of largest value in v[]
int result = 0;
double big = v[0];
for (int i = 0; i "lt" v.Length; ++i)
{
if (v[i] "gt" big)
{
result = i;
big = v[i];
}
}
return result;
}
// ------------------------------------------------------
public double Accuracy(double[][] dataX,
double[][] dataY)
{
int n = dataX.Length;
int nCorrect = 0; int nWrong = 0;
for (int i = 0; i "lt" n; ++i)
{
double[] predY = this.ComputeOutput(dataX[i]);
double[] actualY = dataY[i];
if (ArgMax(predY) == ArgMax(actualY))
++nCorrect;
else
++nWrong;
}
return (nCorrect * 1.0) / (nCorrect + nWrong);
}
// ------------------------------------------------------
public int[][] ConfusionMatrix(double[][] dataX,
double[][] dataY)
{
int n = this.no;
int[][] result = new int[n][]; // nxn
for (int i = 0; i "lt" n; ++i)
result[i] = new int[n];
for (int i = 0; i "lt" dataX.Length; ++i)
{
double[] x = dataX[i]; // inputs
int targetK = ArgMax(dataY[i]); // target
double[] probs = this.ComputeOutput(x); // pseudo
int predK = ArgMax(probs); // predicted 0, 1, 2
++result[targetK][predK];
}
return result;
}
public void ShowConfusion(int[][] cm)
{
int n = cm.Length;
for (int i = 0; i "lt" n; ++i)
{
Console.Write("actual " + i + ": ");
for (int j = 0; j "lt" n; ++j)
{
Console.Write(cm[i][j].ToString().
PadLeft(4) + " ");
}
Console.WriteLine("");
}
}
public void SaveWeights(string fn)
{
double[] wts = this.GetWeights(); // wts and biases
// order: ih weights, ih biases, ho weights, ho biases
// one value per line
FileStream ofs = new FileStream(fn, FileMode.Create);
StreamWriter sw = new StreamWriter(ofs);
for (int i = 0; i "lt" wts.Length; ++i)
sw.WriteLine(wts[i].ToString("F8"));
sw.Close();
ofs.Close();
}
public void LoadWeights(string fn)
{
FileStream ifs = new FileStream(fn, FileMode.Open);
StreamReader sr = new StreamReader(ifs);
List listWts = new List();
string line = ""; // one wt per line
while ((line = sr.ReadLine()) != null)
{
// if (line.StartsWith(comment) == true)
// continue;
listWts.Add(double.Parse(line));
}
sr.Close();
ifs.Close();
double[] wts = listWts.ToArray();
this.SetWeights(wts);
}
} // NeuralNetwork class
// --------------------------------------------------------
public class Utils
{
public static double[][] VecToMat(double[] vec,
int rows, int cols)
{
// vector to row vec/matrix
double[][] result = MatCreate(rows, cols);
int k = 0;
for (int i = 0; i "lt" rows; ++i)
for (int j = 0; j "lt" cols; ++j)
result[i][j] = vec[k++];
return result;
}
// ------------------------------------------------------
public static double[][] MatCreate(int rows,
int cols)
{
double[][] result = new double[rows][];
for (int i = 0; i "lt" rows; ++i)
result[i] = new double[cols];
return result;
}
// ------------------------------------------------------
public static double[][] MatLoad(string fn, int[] usecols,
char sep, string comment)
{
List"lt"double[]"gt" result = new List"lt"double[]"gt"();
string line = "";
FileStream ifs = new FileStream(fn, FileMode.Open);
StreamReader sr = new StreamReader(ifs);
while ((line = sr.ReadLine()) != null)
{
if (line.StartsWith(comment) == true)
continue;
string[] tokens = line.Split(sep);
List"lt"double"gt" lst = new List"lt"double"gt"();
for (int j = 0; j "lt" usecols.Length; ++j)
lst.Add(double.Parse(tokens[usecols[j]]));
double[] row = lst.ToArray();
result.Add(row);
}
sr.Close(); ifs.Close();
return result.ToArray();
}
// ------------------------------------------------------
//static int NumNonCommentLines(string fn,
// string comment)
//{
// int ct = 0;
// string line = "";
// FileStream ifs = new FileStream(fn,
// FileMode.Open);
// StreamReader sr = new StreamReader(ifs);
// while ((line = sr.ReadLine()) != null)
// if (line.StartsWith(comment) == false)
// ++ct;
// sr.Close(); ifs.Close();
// return ct;
//}
// ------------------------------------------------------
//public static double[][] MatLoad(string fn,
// int[] usecols, char sep, string comment)
//{
// // count number of non-comment lines
// int nRows = NumNonCommentLines(fn, comment);
// int nCols = usecols.Length;
// double[][] result = MatCreate(nRows, nCols);
// string line = "";
// string[] tokens = null;
// FileStream ifs = new FileStream(fn, FileMode.Open);
// StreamReader sr = new StreamReader(ifs);
// int i = 0;
// while ((line = sr.ReadLine()) != null)
// {
// if (line.StartsWith(comment) == true)
// continue;
// tokens = line.Split(sep);
// for (int j = 0; j "lt" nCols; ++j)
// {
// int k = usecols[j]; // into tokens
// result[i][j] = double.Parse(tokens[k]);
// }
// ++i;
// }
// sr.Close(); ifs.Close();
// return result;
//}
// ------------------------------------------------------
public static double[] MatToVec(double[][] m)
{
int rows = m.Length;
int cols = m[0].Length;
double[] result = new double[rows * cols];
int k = 0;
for (int i = 0; i "lt" rows; ++i)
for (int j = 0; j "lt" cols; ++j)
result[k++] = m[i][j];
return result;
}
// ------------------------------------------------------
public static double[][] MatToOneHot(double[][] m,
int n)
{
// convert ordinal (0,1,2 . .) to one-hot
int rows = m.Length;
int cols = m[0].Length; // assumed 1
double[][] result = MatCreate(rows, n);
for (int i = 0; i "lt" rows; ++i)
{
int k = (int)m[i][0]; // 0,1,2 . .
result[i] = new double[n]; // [0.0 0.0 0.0]
result[i][k] = 1.0; // [ 0.0 1.0 0.0]
}
return result;
}
// ------------------------------------------------------
public static void MatShow(double[][] m,
int dec, int wid)
{
for (int i = 0; i "lt" m.Length; ++i)
{
for (int j = 0; j "lt" m[0].Length; ++j)
{
double v = m[i][j];
if (Math.Abs(v) "lt" 1.0e-8) v = 0.0; // hack
Console.Write(v.ToString("F" +
dec).PadLeft(wid));
}
Console.WriteLine("");
}
}
// ------------------------------------------------------
public static void VecShow(int[] vec, int wid)
{
for (int i = 0; i "lt" vec.Length; ++i)
Console.Write(vec[i].ToString().PadLeft(wid));
Console.WriteLine("");
}
// ------------------------------------------------------
public static void VecShow(double[] vec,
int dec, int wid, bool newLine)
{
for (int i = 0; i "lt" vec.Length; ++i)
{
double x = vec[i];
if (Math.Abs(x) "lt" 1.0e-8) x = 0.0;
Console.Write(x.ToString("F" +
dec).PadLeft(wid));
}
if (newLine == true)
Console.WriteLine("");
}
} // Utils class
} // ns
Training data.
# people_train.txt # sex (M=-1, F=1) age state (michigan, # nebraska, oklahoma) income # politics (consrvative, moderate, liberal) # 1, 0.24, 1, 0, 0, 0.29500, 2 -1, 0.39, 0, 0, 1, 0.51200, 1 1, 0.63, 0, 1, 0, 0.75800, 0 -1, 0.36, 1, 0, 0, 0.44500, 1 1, 0.27, 0, 1, 0, 0.28600, 2 1, 0.50, 0, 1, 0, 0.56500, 1 1, 0.50, 0, 0, 1, 0.55000, 1 -1, 0.19, 0, 0, 1, 0.32700, 0 1, 0.22, 0, 1, 0, 0.27700, 1 -1, 0.39, 0, 0, 1, 0.47100, 2 1, 0.34, 1, 0, 0, 0.39400, 1 -1, 0.22, 1, 0, 0, 0.33500, 0 1, 0.35, 0, 0, 1, 0.35200, 2 -1, 0.33, 0, 1, 0, 0.46400, 1 1, 0.45, 0, 1, 0, 0.54100, 1 1, 0.42, 0, 1, 0, 0.50700, 1 -1, 0.33, 0, 1, 0, 0.46800, 1 1, 0.25, 0, 0, 1, 0.30000, 1 -1, 0.31, 0, 1, 0, 0.46400, 0 1, 0.27, 1, 0, 0, 0.32500, 2 1, 0.48, 1, 0, 0, 0.54000, 1 -1, 0.64, 0, 1, 0, 0.71300, 2 1, 0.61, 0, 1, 0, 0.72400, 0 1, 0.54, 0, 0, 1, 0.61000, 0 1, 0.29, 1, 0, 0, 0.36300, 0 1, 0.50, 0, 0, 1, 0.55000, 1 1, 0.55, 0, 0, 1, 0.62500, 0 1, 0.40, 1, 0, 0, 0.52400, 0 1, 0.22, 1, 0, 0, 0.23600, 2 1, 0.68, 0, 1, 0, 0.78400, 0 -1, 0.60, 1, 0, 0, 0.71700, 2 -1, 0.34, 0, 0, 1, 0.46500, 1 -1, 0.25, 0, 0, 1, 0.37100, 0 -1, 0.31, 0, 1, 0, 0.48900, 1 1, 0.43, 0, 0, 1, 0.48000, 1 1, 0.58, 0, 1, 0, 0.65400, 2 -1, 0.55, 0, 1, 0, 0.60700, 2 -1, 0.43, 0, 1, 0, 0.51100, 1 -1, 0.43, 0, 0, 1, 0.53200, 1 -1, 0.21, 1, 0, 0, 0.37200, 0 1, 0.55, 0, 0, 1, 0.64600, 0 1, 0.64, 0, 1, 0, 0.74800, 0 -1, 0.41, 1, 0, 0, 0.58800, 1 1, 0.64, 0, 0, 1, 0.72700, 0 -1, 0.56, 0, 0, 1, 0.66600, 2 1, 0.31, 0, 0, 1, 0.36000, 1 -1, 0.65, 0, 0, 1, 0.70100, 2 1, 0.55, 0, 0, 1, 0.64300, 0 -1, 0.25, 1, 0, 0, 0.40300, 0 1, 0.46, 0, 0, 1, 0.51000, 1 -1, 0.36, 1, 0, 0, 0.53500, 0 1, 0.52, 0, 1, 0, 0.58100, 1 1, 0.61, 0, 0, 1, 0.67900, 0 1, 0.57, 0, 0, 1, 0.65700, 0 -1, 0.46, 0, 1, 0, 0.52600, 1 -1, 0.62, 1, 0, 0, 0.66800, 2 1, 0.55, 0, 0, 1, 0.62700, 0 -1, 0.22, 0, 0, 1, 0.27700, 1 -1, 0.50, 1, 0, 0, 0.62900, 0 -1, 0.32, 0, 1, 0, 0.41800, 1 -1, 0.21, 0, 0, 1, 0.35600, 0 1, 0.44, 0, 1, 0, 0.52000, 1 1, 0.46, 0, 1, 0, 0.51700, 1 1, 0.62, 0, 1, 0, 0.69700, 0 1, 0.57, 0, 1, 0, 0.66400, 0 -1, 0.67, 0, 0, 1, 0.75800, 2 1, 0.29, 1, 0, 0, 0.34300, 2 1, 0.53, 1, 0, 0, 0.60100, 0 -1, 0.44, 1, 0, 0, 0.54800, 1 1, 0.46, 0, 1, 0, 0.52300, 1 -1, 0.20, 0, 1, 0, 0.30100, 1 -1, 0.38, 1, 0, 0, 0.53500, 1 1, 0.50, 0, 1, 0, 0.58600, 1 1, 0.33, 0, 1, 0, 0.42500, 1 -1, 0.33, 0, 1, 0, 0.39300, 1 1, 0.26, 0, 1, 0, 0.40400, 0 1, 0.58, 1, 0, 0, 0.70700, 0 1, 0.43, 0, 0, 1, 0.48000, 1 -1, 0.46, 1, 0, 0, 0.64400, 0 1, 0.60, 1, 0, 0, 0.71700, 0 -1, 0.42, 1, 0, 0, 0.48900, 1 -1, 0.56, 0, 0, 1, 0.56400, 2 -1, 0.62, 0, 1, 0, 0.66300, 2 -1, 0.50, 1, 0, 0, 0.64800, 1 1, 0.47, 0, 0, 1, 0.52000, 1 -1, 0.67, 0, 1, 0, 0.80400, 2 -1, 0.40, 0, 0, 1, 0.50400, 1 1, 0.42, 0, 1, 0, 0.48400, 1 1, 0.64, 1, 0, 0, 0.72000, 0 -1, 0.47, 1, 0, 0, 0.58700, 2 1, 0.45, 0, 1, 0, 0.52800, 1 -1, 0.25, 0, 0, 1, 0.40900, 0 1, 0.38, 1, 0, 0, 0.48400, 0 1, 0.55, 0, 0, 1, 0.60000, 1 -1, 0.44, 1, 0, 0, 0.60600, 1 1, 0.33, 1, 0, 0, 0.41000, 1 1, 0.34, 0, 0, 1, 0.39000, 1 1, 0.27, 0, 1, 0, 0.33700, 2 1, 0.32, 0, 1, 0, 0.40700, 1 1, 0.42, 0, 0, 1, 0.47000, 1 -1, 0.24, 0, 0, 1, 0.40300, 0 1, 0.42, 0, 1, 0, 0.50300, 1 1, 0.25, 0, 0, 1, 0.28000, 2 1, 0.51, 0, 1, 0, 0.58000, 1 -1, 0.55, 0, 1, 0, 0.63500, 2 1, 0.44, 1, 0, 0, 0.47800, 2 -1, 0.18, 1, 0, 0, 0.39800, 0 -1, 0.67, 0, 1, 0, 0.71600, 2 1, 0.45, 0, 0, 1, 0.50000, 1 1, 0.48, 1, 0, 0, 0.55800, 1 -1, 0.25, 0, 1, 0, 0.39000, 1 -1, 0.67, 1, 0, 0, 0.78300, 1 1, 0.37, 0, 0, 1, 0.42000, 1 -1, 0.32, 1, 0, 0, 0.42700, 1 1, 0.48, 1, 0, 0, 0.57000, 1 -1, 0.66, 0, 0, 1, 0.75000, 2 1, 0.61, 1, 0, 0, 0.70000, 0 -1, 0.58, 0, 0, 1, 0.68900, 1 1, 0.19, 1, 0, 0, 0.24000, 2 1, 0.38, 0, 0, 1, 0.43000, 1 -1, 0.27, 1, 0, 0, 0.36400, 1 1, 0.42, 1, 0, 0, 0.48000, 1 1, 0.60, 1, 0, 0, 0.71300, 0 -1, 0.27, 0, 0, 1, 0.34800, 0 1, 0.29, 0, 1, 0, 0.37100, 0 -1, 0.43, 1, 0, 0, 0.56700, 1 1, 0.48, 1, 0, 0, 0.56700, 1 1, 0.27, 0, 0, 1, 0.29400, 2 -1, 0.44, 1, 0, 0, 0.55200, 0 1, 0.23, 0, 1, 0, 0.26300, 2 -1, 0.36, 0, 1, 0, 0.53000, 2 1, 0.64, 0, 0, 1, 0.72500, 0 1, 0.29, 0, 0, 1, 0.30000, 2 -1, 0.33, 1, 0, 0, 0.49300, 1 -1, 0.66, 0, 1, 0, 0.75000, 2 -1, 0.21, 0, 0, 1, 0.34300, 0 1, 0.27, 1, 0, 0, 0.32700, 2 1, 0.29, 1, 0, 0, 0.31800, 2 -1, 0.31, 1, 0, 0, 0.48600, 1 1, 0.36, 0, 0, 1, 0.41000, 1 1, 0.49, 0, 1, 0, 0.55700, 1 -1, 0.28, 1, 0, 0, 0.38400, 0 -1, 0.43, 0, 0, 1, 0.56600, 1 -1, 0.46, 0, 1, 0, 0.58800, 1 1, 0.57, 1, 0, 0, 0.69800, 0 -1, 0.52, 0, 0, 1, 0.59400, 1 -1, 0.31, 0, 0, 1, 0.43500, 1 -1, 0.55, 1, 0, 0, 0.62000, 2 1, 0.50, 1, 0, 0, 0.56400, 1 1, 0.48, 0, 1, 0, 0.55900, 1 -1, 0.22, 0, 0, 1, 0.34500, 0 1, 0.59, 0, 0, 1, 0.66700, 0 1, 0.34, 1, 0, 0, 0.42800, 2 -1, 0.64, 1, 0, 0, 0.77200, 2 1, 0.29, 0, 0, 1, 0.33500, 2 -1, 0.34, 0, 1, 0, 0.43200, 1 -1, 0.61, 1, 0, 0, 0.75000, 2 1, 0.64, 0, 0, 1, 0.71100, 0 -1, 0.29, 1, 0, 0, 0.41300, 0 1, 0.63, 0, 1, 0, 0.70600, 0 -1, 0.29, 0, 1, 0, 0.40000, 0 -1, 0.51, 1, 0, 0, 0.62700, 1 -1, 0.24, 0, 0, 1, 0.37700, 0 1, 0.48, 0, 1, 0, 0.57500, 1 1, 0.18, 1, 0, 0, 0.27400, 0 1, 0.18, 1, 0, 0, 0.20300, 2 1, 0.33, 0, 1, 0, 0.38200, 2 -1, 0.20, 0, 0, 1, 0.34800, 0 1, 0.29, 0, 0, 1, 0.33000, 2 -1, 0.44, 0, 0, 1, 0.63000, 0 -1, 0.65, 0, 0, 1, 0.81800, 0 -1, 0.56, 1, 0, 0, 0.63700, 2 -1, 0.52, 0, 0, 1, 0.58400, 1 -1, 0.29, 0, 1, 0, 0.48600, 0 -1, 0.47, 0, 1, 0, 0.58900, 1 1, 0.68, 1, 0, 0, 0.72600, 2 1, 0.31, 0, 0, 1, 0.36000, 1 1, 0.61, 0, 1, 0, 0.62500, 2 1, 0.19, 0, 1, 0, 0.21500, 2 1, 0.38, 0, 0, 1, 0.43000, 1 -1, 0.26, 1, 0, 0, 0.42300, 0 1, 0.61, 0, 1, 0, 0.67400, 0 1, 0.40, 1, 0, 0, 0.46500, 1 -1, 0.49, 1, 0, 0, 0.65200, 1 1, 0.56, 1, 0, 0, 0.67500, 0 -1, 0.48, 0, 1, 0, 0.66000, 1 1, 0.52, 1, 0, 0, 0.56300, 2 -1, 0.18, 1, 0, 0, 0.29800, 0 -1, 0.56, 0, 0, 1, 0.59300, 2 -1, 0.52, 0, 1, 0, 0.64400, 1 -1, 0.18, 0, 1, 0, 0.28600, 1 -1, 0.58, 1, 0, 0, 0.66200, 2 -1, 0.39, 0, 1, 0, 0.55100, 1 -1, 0.46, 1, 0, 0, 0.62900, 1 -1, 0.40, 0, 1, 0, 0.46200, 1 -1, 0.60, 1, 0, 0, 0.72700, 2 1, 0.36, 0, 1, 0, 0.40700, 2 1, 0.44, 1, 0, 0, 0.52300, 1 1, 0.28, 1, 0, 0, 0.31300, 2 1, 0.54, 0, 0, 1, 0.62600, 0
Test data.
# people_test.txt # -1, 0.51, 1, 0, 0, 0.61200, 1 -1, 0.32, 0, 1, 0, 0.46100, 1 1, 0.55, 1, 0, 0, 0.62700, 0 1, 0.25, 0, 0, 1, 0.26200, 2 1, 0.33, 0, 0, 1, 0.37300, 2 -1, 0.29, 0, 1, 0, 0.46200, 0 1, 0.65, 1, 0, 0, 0.72700, 0 -1, 0.43, 0, 1, 0, 0.51400, 1 -1, 0.54, 0, 1, 0, 0.64800, 2 1, 0.61, 0, 1, 0, 0.72700, 0 1, 0.52, 0, 1, 0, 0.63600, 0 1, 0.30, 0, 1, 0, 0.33500, 2 1, 0.29, 1, 0, 0, 0.31400, 2 -1, 0.47, 0, 0, 1, 0.59400, 1 1, 0.39, 0, 1, 0, 0.47800, 1 1, 0.47, 0, 0, 1, 0.52000, 1 -1, 0.49, 1, 0, 0, 0.58600, 1 -1, 0.63, 0, 0, 1, 0.67400, 2 -1, 0.30, 1, 0, 0, 0.39200, 0 -1, 0.61, 0, 0, 1, 0.69600, 2 -1, 0.47, 0, 0, 1, 0.58700, 1 1, 0.30, 0, 0, 1, 0.34500, 2 -1, 0.51, 0, 0, 1, 0.58000, 1 -1, 0.24, 1, 0, 0, 0.38800, 1 -1, 0.49, 1, 0, 0, 0.64500, 1 1, 0.66, 0, 0, 1, 0.74500, 0 -1, 0.65, 1, 0, 0, 0.76900, 0 -1, 0.46, 0, 1, 0, 0.58000, 0 -1, 0.45, 0, 0, 1, 0.51800, 1 -1, 0.47, 1, 0, 0, 0.63600, 0 -1, 0.29, 1, 0, 0, 0.44800, 0 -1, 0.57, 0, 0, 1, 0.69300, 2 -1, 0.20, 1, 0, 0, 0.28700, 2 -1, 0.35, 1, 0, 0, 0.43400, 1 -1, 0.61, 0, 0, 1, 0.67000, 2 -1, 0.31, 0, 0, 1, 0.37300, 1 1, 0.18, 1, 0, 0, 0.20800, 2 1, 0.26, 0, 0, 1, 0.29200, 2 -1, 0.28, 1, 0, 0, 0.36400, 2 -1, 0.59, 0, 0, 1, 0.69400, 2

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
Visual Studio Live
Microsoft MLADS Conference
DevIntersection Conference
Machine Learning Week
Ai4 Conference
G2E Conference
iSC West Conference
You must be logged in to post a comment.