"""
K-Nearest Neighbor

The k-nearest neighbor algorithm (k-NN) is a method for classifying objects by a majority vote of its neighbors, with the object being assigned to the class most common amongst its k nearest neighbors (k is typically small). k-NN is a type of instance-based learning, or lazy learning where the function is only approximated locally and all computation is deferred until classification.
"""


from smile.data import AttributeDataset,NominalAttribute
from smile.data.parser import DelimitedTextParser,IOUtils
from java.io import File
from jhplot import *
from smile.classification import KNN 
from jarray import zeros,array
from java.awt import Color
import java


# this function extract data[][] and label[] array from datasets
def getJavaArrays(dataset):
    rows=dataset.size()
    lst = [0.0]*rows
    twoDimArr = array([lst,[]], java.lang.Class.forName('[D'))
    data = dataset.toArray(twoDimArr)
    label = dataset.toArray(zeros(rows, "i"))
    return data,label

http="http://datamelt.org/examples/data/classification/toy/"
print "Reading data from",http
datasource="toy-train.txt"  
datasetName="Toy"
print Web.get(http+datasource)
parser =DelimitedTextParser()
parser.setDelimiter("[\t ]+")
parser.setResponseIndex(NominalAttribute("class"), 0)
dataset=parser.parse(datasetName,File(datasource))
print dataset
print "Classification.."

"""
The best choice of k depends upon the data; generally, larger values of k reduce the effect of noise on the classification, but make boundaries between classes less distinct. A good k can be selected by various heuristic techniques, e.g. cross-validation. In binary problems, it is helpful to choose k to be an odd number as this avoids tied votes.
"""
k=3
data,label=getJavaArrays(dataset)
knn =  KNN.learn(data, label, k); 

# now we will use another sample for prediction
print "Training finished. Get a new sample for predictions.."
datasource="toy-test.txt" #  (20k events) 
datasetName="Testing"
print Web.get(http+datasource)
dataset=parser.parse(datasetName,File(datasource))
data,label=getJavaArrays(dataset)

#print label
#print type(data)
prediction=knn.predict(data)
rows=dataset.size()


c1 = HPlot("Canvas",800,450,2,1)
c1.visible()
c1.setAutoRange()
c1.setGTitle("K-Nearest Neighbor (KNN)")

def applyStyle(p1,color,t): 
      p1.setSymbol(t); p1.setColor(color); p1.setSymbolSize(1); 
 
p1=P1D("Input true"); applyStyle(p1,Color.blue, 11);
p2=P1D("Input false"); applyStyle(p2,Color.red, 4); 
p1p=P1D("Predicted true"); applyStyle(p1p,Color.blue, 11);
p2p=P1D("Predicted false"); applyStyle(p2p,Color.red, 4);   

e=0.0
for i in range(rows):
    minput=data[i].tolist()
    expected=label[i]
    predicted=prediction[i] 
    if (expected>0): p1.add(minput[0],minput[1]) 
    else:            p2.add(minput[0],minput[1])
    if (predicted>0): p1p.add(minput[0],minput[1])
    else:             p2p.add(minput[0],minput[1])
    if (i%100==0): print "Input=",minput, " outcome=",expected," prediction=",predicted
    if (expected != predicted): e=e+1.0
e=e/rows
print "Error rate=",e

c1.cd(1,1)
c1.draw([p1,p2])
c1.cd(2,1)
c1.setAutoRange()
c1.draw([p1p,p2p])

