You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
3.5 KiB
Plaintext

TITLE:: FluidKNNRegressor
summary:: Regression with K Nearest Neighbours
categories:: Regression
related:: Classes/FluidKNNClassifier, Classes/FluidDataSet
DESCRIPTION::
A nearest-neighbor regressor. A continuous value is predicted for each point as the (weighted) average value of its nearest neighbors.
https://scikit-learn.org/stable/modules/neighbors.html#regression
CLASSMETHODS::
METHOD:: new
Create a new KNN regressor on the server
ARGUMENT:: server
The server to run this model on.
INSTANCEMETHODS::
METHOD:: fit
Map a source link::Classes/FluidDataSet:: to a one-dimensional target; both datasets need to have the same number of points.
ARGUMENT:: sourceDataset
Source data
ARGUMENT:: targetDataset
Target data
ARGUMENT:: action
Run when done
METHOD:: predict
Apply learned mapping to a link::Classes/FluidDataSet:: and write to an output dataset
ARGUMENT:: sourceDataset
data to regress
ARGUMENT:: targetDataset
output data
ARGUMENT:: k
number of neigbours to consider in mapping, min 1
ARGUMENT:: uniform
Whether to weight neighbours by distance when producing new point
ARGUMENT:: action
Run when done
METHOD:: predictPoint
Apply learned mapping to a data point in a link::Classes/Buffer::
ARGUMENT:: buffer
data point
ARGUMENT:: k
number of neigbours to consider in mapping, min 1
ARGUMENT:: uniform
Whether the neighbours should be weighted by distance (default) or uniformly
ARGUMENT:: action
Run when done
EXAMPLES::
code::
//Make a simple mapping between a ramp and a sine cycle, test with an exponentional ramp
(
~source = FluidDataSet(s,\knn_regress_src);
~target = FluidDataSet(s,\knn_regress_tgt);
~test = FluidDataSet(s,\knn_regress_test);
~output = FluidDataSet(s,\knn_regress_out);
~tmpbuf = Buffer.alloc(s,1);
~regressor = FluidKNNRegressor(s);
)
//Make source, target and test data
(
~sourcedata = 128.collect{|i|i/128};
~targetdata = 128.collect{|i| sin(2*pi*i/128) };
~testdata = 128.collect{|i|(i/128)**2};
~source.load(
Dictionary.with(
*[\cols -> 1,\data -> Dictionary.newFrom(
~sourcedata.collect{|x, i| [i.asString, [x]]}.flatten)])
);
~target.load(
d = Dictionary.with(
*[\cols -> 1,\data -> Dictionary.newFrom(
~targetdata.collect{|x, i| [i.asString, [x]]}.flatten)]);
);
~test.load(
Dictionary.with(
*[\cols -> 1,\data -> Dictionary.newFrom(
~testdata.collect{|x, i| [i.asString, [x]]}.flatten)])
);
~targetdata.plot
~source.print;
~target.print;
~test.print;
)
// Now make a regressor and fit it to the source and target, and predict against test
//grab the output data whilst we're at it, so we can inspect
(
~outputdata = Array(128);
~regressor.fit(~source, ~target);
~regressor.predict(~test, ~output, 1, action:{
~output.dump{|x| 128.do{|i|
~outputdata.add(x["data"][i.asString][0])
}};
});
)
//We should see a single cycle of a chirp
~outputdata.plot;
::
subsection:: Server Side Queries
code::
//Setup
(
~inputPoint = Buffer.alloc(s,1);
~predictPoint = Buffer.alloc(s,2);
~avgBuf = Buffer.alloc(s,10,2);
~pitchingBus = Bus.control;
~catchingBus = Bus.control;
)
(
~regressor.inBus_(~pitchingBus).outBus_(~catchingBus).inBuffer_(~inputPoint).outBuffer_(~predictPoint);
~inputSynth = {
var input = Saw.kr(2).linlin(-1,1,0,1);
var trig = Impulse.kr(ControlRate.ir/10);
BufWr.kr(input,~inputPoint,0);
Out.kr(~pitchingBus.index,[trig]);
};
~inputSynth.play(~regressor.synth,addAction:\addBefore);
~outputSynth = {
Poll.kr(In.kr(~catchingBus.index),BufRd.kr(1,~predictPoint,0),"mapped value")
};
~outputSynth.play(~regressor.synth,addAction:\addAfter);
~outputSynth.scope
)
::