kmeans new functionalities - classes done, with help+doc+examples in progress

nix
Pierre Alexandre Tremblay 5 years ago
parent 3ec019e410
commit 4fbd3d2558

@ -1,70 +1,114 @@
FluidKMeans : FluidRealTimeModel { FluidKMeans : FluidRealTimeModel {
var clusters, maxiter; var clusters, maxiter;
*new {|server, numClusters = 4, maxIter = 100| *new {|server, numClusters = 4, maxIter = 100|
^super.new(server,[numClusters,maxIter]) ^super.new(server,[numClusters,maxIter])
.numClusters_(numClusters) .numClusters_(numClusters)
.maxIter_(maxIter); .maxIter_(maxIter);
} }
numClusters_{|n| clusters = n.asInteger} numClusters_{|n| clusters = n.asInteger}
numClusters{ ^clusters } numClusters{ ^clusters }
maxIter_{|i| maxiter = i.asInteger} maxIter_{|i| maxiter = i.asInteger}
maxIter{ ^maxiter } maxIter{ ^maxiter }
prGetParams{^[this.numClusters,this.maxIter,-1,-1];} prGetParams{^[this.numClusters,this.maxIter,-1,-1];}
fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);} fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);}
fit{|dataSet, action| fit{|dataSet, action|
actions[\fit] = [ actions[\fit] = [
numbers( FluidMessageResponse, _, this.numClusters ,_), numbers( FluidMessageResponse, _, this.numClusters ,_),
action action
]; ];
this.prSendMsg(this.fitMsg(dataSet)); this.prSendMsg(this.fitMsg(dataSet));
} }
fitPredictMsg{|dataSet, labelSet| fitPredictMsg{|dataSet, labelSet|
^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id) ^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id)
} }
fitPredict{|dataSet, labelSet,action| fitPredict{|dataSet, labelSet,action|
actions[\fitPredict] = [ actions[\fitPredict] = [
numbers(FluidMessageResponse, _, this.numClusters, _), numbers(FluidMessageResponse, _, this.numClusters, _),
action action
]; ];
this.prSendMsg(this.fitPredictMsg(dataSet,labelSet)); this.prSendMsg(this.fitPredictMsg(dataSet,labelSet));
} }
predictMsg{|dataSet, labelSet| predictMsg{|dataSet, labelSet|
^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id) ^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id)
} }
predict{ |dataSet, labelSet, action| predict{ |dataSet, labelSet, action|
actions[\predict] = [ actions[\predict] = [
numbers(FluidMessageResponse, _, this.numClusters, _), numbers(FluidMessageResponse, _, this.numClusters, _),
action action
]; ];
this.prSendMsg(this.predictMsg(dataSet,labelSet)); this.prSendMsg(this.predictMsg(dataSet,labelSet));
} }
predictPointMsg{|buffer| predictPointMsg{|buffer|
^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer)) ^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer))
} }
predictPoint { |buffer, action| predictPoint { |buffer, action|
actions[\predictPoint] = [number(FluidMessageResponse,_,_),action]; actions[\predictPoint] = [number(FluidMessageResponse,_,_),action];
this.prSendMsg(this.predictPointMsg(buffer)) this.prSendMsg(this.predictPointMsg(buffer))
} }
kr{|trig, inputBuffer,outputBuffer| fitTransformMsg{|srcDataSet, dstDataSet|
^FluidKMeansQuery.kr(K2A.ar(trig), ^this.prMakeMsg(\fitTransform, id, srcDataSet.id, dstDataSet.id)
this, clusters, maxiter, }
this.prEncodeBuffer(inputBuffer),
this.prEncodeBuffer(outputBuffer)); fitTransform{|srcDataSet, dstDataSet,action|
actions[\fitTransform] = [nil,action];
this.prSendMsg(this.fitTransformMsg(srcDataSet,dstDataSet));
}
transformMsg{|srcDataSet, dstDataSet|
^this.prMakeMsg(\transform, id, srcDataSet.id, dstDataSet.id)
}
transform{ |srcDataSet, dstDataSet, action|
actions[\transform] = [nil,action];
this.prSendMsg(this.transformMsg(srcDataSet,dstDataSet));
}
transformPointMsg{ |sourceBuffer, targetBuffer|
^this.prMakeMsg(\transformPoint, id,
this.prEncodeBuffer(sourceBuffer),
this.prEncodeBuffer(targetBuffer),
["/b_query", targetBuffer.asUGenInput]);
} }
transformPoint { |sourceBuffer, targetBuffer, action|
actions[\transformPoint] = [nil,{action.value(targetBuffer)}];
this.prSendMsg(this.transformPointMsg(sourceBuffer, targetBuffer));
}
getMeansMsg{|dataSet| ^this.prMakeMsg(\getMeans, id, dataSet.asUGenInput) }
getMeans{ |dataSet, action|
actions[\getMeans] = [nil, action];
this.prSendMsg(this.getMeansMsg(dataSet));
}
setMeansMsg{|dataSet| ^this.prMakeMsg(\setMeans, id, dataSet.asUGenInput) }
setMeans{ |dataSet, action|
actions[\setMeans] = [nil, action];
this.prSendMsg(this.setMeansMsg(dataSet));
}
kr{|trig, inputBuffer,outputBuffer|
^FluidKMeansQuery.kr(K2A.ar(trig),
this, clusters, maxiter,
this.prEncodeBuffer(inputBuffer),
this.prEncodeBuffer(outputBuffer));
}
} }
FluidKMeansQuery : FluidRTQuery {} FluidKMeansQuery : FluidRTQuery {}

@ -65,6 +65,46 @@ A link::Classes/FluidLabelSet:: to contain assignments.
ARGUMENT:: action ARGUMENT:: action
A function to run when complete, taking an array of the counts for each category as its argument. A function to run when complete, taking an array of the counts for each category as its argument.
METHOD:: fitTransform
Run link::Classes/FluidKMeans#*fit:: and link::Classes/FluidKMeans#*predict:: in a single pass: i.e. train the model on the incoming link::Classes/FluidDataSet:: and then return the learned clustering to the passed link::Classes/FluidLabelSet::
ARGUMENT:: srcDataSet
a link::Classes/FluidDataSet:: containing the data to fit and predict.
ARGUMENT:: dstDataSet
a link::Classes/FluidLabelSet:: to retrieve the predicted clusters.
ARGUMENT:: action
A function to run when the server responds
METHOD:: transformPoint
Given a trained object, return the cluster ID for a data point in a link::Classes/Buffer::
ARGUMENT:: sourceBuffer
a link::Classes/Buffer:: containing a data point.
ARGUMENT:: targetBuffer
a link::Classes/Buffer:: containing a data point.
ARGUMENT:: action
A function to run when the server responds, taking the ID of the cluster as its argument.
METHOD:: transform
Report cluster assignments for previously unseen data.
ARGUMENT:: srcDataSet
A link::Classes/FluidDataSet:: of data points.
ARGUMENT:: dstDataSet
A link::Classes/FluidLabelSet:: to contain assignments.
ARGUMENT:: action
A function to run when complete, taking an array of the counts for each category as its argument.
METHOD:: getMeans
Report cluster assignments for previously unseen data.
ARGUMENT:: dataSet
A link::Classes/FluidDataSet:: of data points.
ARGUMENT:: action
A function to run when complete, taking an array of the counts for each category as its argument.
METHOD:: setMeans
Report cluster assignments for previously unseen data.
ARGUMENT:: dataSet
A link::Classes/FluidDataSet:: of data points.
ARGUMENT:: action
A function to run when complete, taking an array of the counts for each category as its argument.
EXAMPLES:: EXAMPLES::
code:: code::
@ -147,6 +187,38 @@ w.front;
~kmeans.predictPoint(~inbuf,{|x|x.postln;}); ~kmeans.predictPoint(~inbuf,{|x|x.postln;});
:: ::
subsection:: Accessing the means
We can get and set the means for each cluster, their centroid.
code::
~centroids = FluidDataSet(s);
~kmeans.getMeans(~centroids, {~centroids.print});
~centroids.load(Dictionary.newFrom([\cols, 2, \data, Dictionary.newFrom([\0, [0.5,0.5], \1, [-0.5,0.5], \2, [0.5,-0.5], \3, [-0.5,-0.5]])]));
~centroids.print
~kmeans.setMeans(~centroids, {~kmeans.predict(~dataSet,~clusters,{~clusters.dump{|x|var count = 0.dup(4); x["data"].keysValuesDo{|k,v|count[v[0].asInteger] = count[v[0].asInteger] + 1;};count.postln}})});
~kmeans.free
~kmeans = FluidKMeans(s);
~kmeans.predict(~dataSet,~clusters)
::
subsection:: Cluster-distance Space
You can get the euclidian distance of a given point to each cluster.
code::
b = Buffer.sendCollection(s,[0.5,0.5])
c = Buffer(s)
~kmeans.transformPoint(b,c,{|x|x.query;x.getn(0,x.numFrames,{|y|y.postln})})
::
subsection:: Queries in a Synth subsection:: Queries in a Synth
This is the equivalent of predictPoint, but wholly on the server This is the equivalent of predictPoint, but wholly on the server

Loading…
Cancel
Save