My least weekend project. A javascript simulation of 2D heat diffusion. Vanilla JS. Source code is here
My least weekend project. A javascript simulation of 2D heat diffusion. Vanilla JS. Source code is here
PCA application sample for analysis of stock markets using python
PCA is a mathematical method for compressing multidimensional data into a less dimensional version. That data reduction helps to make analysis more simpler. More information about principle component analysis and its math is here. With this project I tried to analyse stock market data with PCA decomposition.
# Data
I used "Borsa Istanbul 100" a.k.a. "Bist100" stock market index symbols. It is an index of Turkey stocks that covers top 100 biggest components. Gathered 5 basic financial ratios for each symbol around internet and here is the raw result (ticks.raw.csv):
These are some common financial indicators to measure fair price of a company. I picked 5 of many indicators which i wanted in my sample analyse. Different choices made among the indicators will change the whole result.Therefore, it is important to make the right choices. Raw data columns has various ranges. For instance price to earning range is 1.43 to 244.74 and price to book value range is 0.29 to 30.51. Too much numerical difference between columns affects their impact on the result which is not wanted. Thats why applied following steps to balance them:
Here is the result (ticks.norm.csv):
Afer data fetch and normalization I pushed an other single row to final data. It is "Referance" point. An imaginary stock with perfect ratios. All the indicators equals to 1. That point will help me to figure out better stocks after PCA decomposition.
# PCA
Raw data contains one label dimension (symbol column) and 5 feature dimensions. With PCA calculation, reduced that information to 2 component dimentions. These dimentions contains primary characteristic information of whole 6 dimention data. Sklearn liblary has built in PCA tools to make that happened. Pandas and matplotlib will help to visualize reduced data in scatter plot. These steps in pca.py file. Here is the result plot:
Closer to Referrance point means better results:

using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Assets.Scripts { public class Module : MonoBehaviour { System.Random rnd; public GameObject[] Outputs; public List<GameObject> AvailableOutputs { get; set; } public GameObject GetOutput() { //Get an output and seal var op = AvailableOutputs.ElementAt(rnd.Next(AvailableOutputs.Count)); AvailableOutputs.Remove(op); return op; } public void Init(int seed) { rnd = new System.Random(seed); AvailableOutputs = Outputs.ToList(); } } }These are my test modules:
using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Assets.Scripts { public class WorldBuilder : MonoBehaviour { public GameObject[] Modules; public int Iterations; /// <summary> /// Random seed for debugging. /// </summary> public int Seed; System.Random rnd; List<GameObject> createdModules, availableModules; void Start() { rnd = new System.Random(Seed); BuildWorld(); } void BuildWorld() { createdModules = new List<GameObject>(); var initialModule = GameObject.Instantiate(Modules.ElementAt(rnd.Next(Modules.Count()))); initialModule.GetComponent<Module>().Init(Seed); createdModules.Add(initialModule); availableModules = createdModules; for (int i = 0; i < Iterations; i++) { var module = availableModules.ElementAt(rnd.Next(availableModules.Count)); var targetPoint = module.GetComponent<Module>().GetOutput(); //Shuffle and try every blocks to fit var shuffledBlocks = Modules.OrderBy(d => rnd.Next()).ToArray(); foreach (var sBlock in shuffledBlocks) { var candidate = GameObject.Instantiate(sBlock); candidate.GetComponent<Module>().Init(Seed); candidate.gameObject.transform.position = targetPoint.transform.position; candidate.transform.LookAt(targetPoint.transform.position + targetPoint.transform.forward); //Check if there is an any overlapping var bound = candidate.GetComponent<BoxCollider>().bounds; var isSafe = true; foreach (var item in createdModules) { if (bound.Intersects(item.GetComponent<BoxCollider>().bounds)) { //Try another module GameObject.Destroy(candidate); isSafe = false; break; } } if (isSafe) { //Module connected safely createdModules.Add(candidate); break; } } availableModules = createdModules.Where(d => d.GetComponent<Module>().AvailableOutputs.Any()).ToList(); if (!availableModules.Any()) { //No availabel output on any modules. Stop the proccess break; } } foreach (var item in createdModules) { //Disable overlap test colliders item.GetComponent<BoxCollider>().enabled = false; } } } }
public class Layer { public Neuron[] Neurons { get; set; } }
public enum NeuronTypes { Input, Hidden, Output } public class Neuron { public List<Synapse> Inputs { get; set; } public List<Synapse> Outputs { get; set; } public double Output { get; set; } public double TargetOutput { get; set; } public double Delta { get; set; } public double Bias { get; set; } int? maxInput { get; set; } public NeuronTypes NeuronType { get; set; } public Neuron(NeuronTypes neuronType, int? maxInput) { this.NeuronType = neuronType; this.maxInput = maxInput; this.Inputs = new List<Synapse>(); this.Outputs = new List<Synapse>(); } public bool AcceptConnection { get { return !(NeuronType == NeuronTypes.Hidden && maxInput.HasValue && Inputs.Count > maxInput); } } public double InputSignal { get { return Inputs.Sum(d => d.Weight * (d.Source.Output + Bias)); } } public double BackwardSignal() { if (Outputs.Any()) { Delta = Outputs.Sum(d => d.Target.Delta * d.Weight) * activatePrime(Output); } else { Delta = (Output - TargetOutput) * activatePrime(Output); } return Delta + Bias; } public void AdjustWeights(double learnRate, double momentum) { if (Inputs.Any()) { foreach (var synp in Inputs) { var adjustDelta = Delta * synp.Source.Output; synp.Weight -= learnRate * adjustDelta + synp.PreDelta * momentum; synp.PreDelta = adjustDelta; } } } public double ForwardSignal() { Output = activate(InputSignal); return Output; } double activatePrime(double x) { return x * (1 - x); } double activate(double x) { return 1 / (1 + Math.Pow(Math.E, -x)); } }
public class Synapse { public double Weight { get; set; } public Neuron Target { get; set; } public Neuron Source { get; set; } public double PreDelta { get; set; } public double Gradient { get; set; } public Synapse(double weight, Neuron target, Neuron source) { Weight = weight; Target = target; Source = source; } }
And the NeuralNetwork class, the maestro that pulls them together.public class NeuralNetwork { public double LearnRate = .5; public double Momentum = .3; public List<Layer> Layers { get; private set; } int? maxNeuronConnection; public int? Seed { get; set; } public NeuralNetwork(int inputs, int[] hiddenLayers, int outputs, int? maxNeuronConnection = null, int? seed = null) { this.Seed = seed; this.maxNeuronConnection = maxNeuronConnection; this.Layers = new List<Layer>(); buildLayer(inputs, NeuronTypes.Input); for (int i = 0; i < hiddenLayers.Length; i++) { buildLayer(hiddenLayers[i], NeuronTypes.Hidden); } buildLayer(outputs, NeuronTypes.Output); InitSnypes(); } void buildLayer(int nodeSize, NeuronTypes neuronType) { var layer = new Layer(); var nodeBuilder = new List<Neuron>(); for (int i = 0; i < nodeSize; i++) { nodeBuilder.Add(new Neuron(neuronType, maxNeuronConnection)); } layer.Neurons = nodeBuilder.ToArray(); Layers.Add(layer); } private void InitSnypes() { var rnd = Seed.HasValue ? new Random(Seed.Value) : new Random(); for (int i = 0; i < Layers.Count - 1; i++) { var layer = Layers[i]; var nextLayer = Layers[i + 1]; foreach (var node in layer.Neurons) { node.Bias = 0.1 * rnd.NextDouble(); foreach (var nNode in nextLayer.Neurons) { if (!nNode.AcceptConnection) continue; var snypse = new Synapse(rnd.NextDouble(), nNode, node); node.Outputs.Add(snypse); nNode.Inputs.Add(snypse); } } } } public double GlobalError { get { return Math.Round(Layers.Last().Neurons.Sum(d => Math.Pow(d.TargetOutput - d.Output, 2) / 2), 4); } } public void BackPropagation() { for (int i = Layers.Count - 1; i > 0; i--) { var layer = Layers[i]; foreach (var node in layer.Neurons) { node.BackwardSignal(); } } for (int i = Layers.Count - 1; i >= 1; i--) { var layer = Layers[i]; foreach (var node in layer.Neurons) { node.AdjustWeights(LearnRate, Momentum); } } } public double[] Train(double[] _input, double[] _outputs) { if (_outputs.Count() != Layers.Last().Neurons.Count() || _input.Any(d => d < 0 || d > 1) || _outputs.Any(d => d < 0 || d > 1)) throw new ArgumentException(); var outputs = Layers.Last().Neurons; for (int i = 0; i < _outputs.Length; i++) { outputs[i].TargetOutput = _outputs[i]; } var result = FeedForward(_input); BackPropagation(); return result; } public double[] FeedForward(double[] _input) { if (_input.Count() != Layers.First().Neurons.Count()) throw new ArgumentException(); var InputLayer = Layers.First().Neurons; for (int i = 0; i < _input.Length; i++) { InputLayer[i].Output = _input[i]; } for (int i = 1; i < Layers.Count; i++) { var layer = Layers[i]; foreach (var node in layer.Neurons) { node.ForwardSignal(); } } return Layers.Last().Neurons.Select(d => d.Output).ToArray(); } }
class ANN { static void Main(string[] args) { var network = new NeuralNetwork(2, new int[] { 4 }, 1); var inputData = new double[] { .3, .5 }; var output = network.FeedForward(inputData); Console.Write("Inputs: {0} {1} Output:{2} ", inputData[0], inputData[1],output[0]); Console.ReadLine(); } }
public partial class Form1 : Form { public NeuralNetwork network; public List<double[]> trainingData; Random rnd; int trainedTimes; public Form1() { InitializeComponent(); //For debugging int Seed = 1923; // 2 input neurons 2 hidden layers with 3 and 2 neurons and 1 outpu neuron network = new NeuralNetwork(2, new int[] { 3, 3 }, 1, null, Seed); //Generate Random Training Data trainingData = new List<double[]>(); rnd = new Random(Seed); var trainingDataSize = 75; for (int i = 0; i < trainingDataSize; i++) { var input1 = Math.Round(rnd.NextDouble(), 2); //input 1 var input2 = Math.Round(rnd.NextDouble(), 2); // input 2 var output = (input1+input2)/2 ; // output as avarage of inputs trainingData.Add(new double[] { input1, input2, output });// Training data set chart1.Series[0].Points.AddXY(i, output); } } public void Train(int times) { //Train network x0 times for (int i = 0; i < times; i++) { //shuffle list for better training var shuffledTrainingData = trainingData.OrderBy(d => rnd.Next()).ToList(); List<double> errors = new List<double>(); foreach (var item in shuffledTrainingData) { var inputs = new double[] { item[0], item[1] }; var output = new double[] { item[2] }; //Train current set network.Train(inputs, output); errors.Add(network.GlobalError); } } chart1.Series[1].Points.Clear(); for (int i = 0; i < trainingData.Count; i++) { var set = trainingData[i]; chart1.Series[1].Points.AddXY(i, network.FeedForward(new double[] { set[0], set[1] })[0]); } trainedTimes += times; TrainCounterlbl.Text = string.Format("Trained {0} times", trainedTimes); } private void Trainx1_Click(object sender, EventArgs e) { Train(1); } private void Trainx50_Click(object sender, EventArgs e) { Train(50); } private void Trainx500_Click(object sender, EventArgs e) { Train(500); } private void TestBtn_Click(object sender, EventArgs e) { var testData = new double[] { rnd.NextDouble(), rnd.NextDouble() }; var result = network.FeedForward(testData)[0]; MessageBox.Show(string.Format("Input 1:{0} {4} Input 2:{1} {4} Expected:{3} Result:{2} {4}", format(testData[0]), format(testData[1]), format(result), format((testData[0]+ testData[1])/2), Environment.NewLine)); } string format(double val) { return val.ToString("0.000"); } }
public double BackwardSignal() { if (Outputs.Any()) { Delta = Outputs.Sum(d => d.Target.Delta * d.Weight) * activatePrime(Output); } else { Delta = (Output - TargetOutput) * activatePrime(Output); } return Delta + Bias; }Then adjustment of weights at
public void AdjustWeights(double learnRate, double momentum) { if (Inputs.Any()) { foreach (var synp in Inputs) { var adjustDelta = Delta * synp.Source.Output; synp.Weight -= learnRate * adjustDelta + synp.PreDelta * momentum; synp.PreDelta = adjustDelta; } } }Back to demo application. Remember our application tries to find average of two input values. More we train better results we get. After training 50 times over artificial neural network, results begins to fit expected values.