Я выполняю m-кратную перекрестную проверку с помощью собственной пользовательской функции k-ближайшего соседа, и мои значения точности не только редко меняются для введенных обучающих и тестовых наборов, но и общая точность довольно низкая. Я тестирую свои функции в наборе данных "fglass.dat", причем документ "fglass.grp" представляет собой используемый для определения того, какие столбцы должны быть удалены (m-кратно) и используется в качестве набора тестов для KNN. И хотя я считаю, что моя функция «createFolds», которая отвечает за извлечение этого тестового столбца, работает, я не знаю, как определить правильные типы классов в моем коде в моей функции KNN. Как я должен определить тип класса для "glass.dat" для всех 214 строк? «fragArray» - это данные «fglass.dat», а «iterArray» - данные «fglass.grp».
Используя выходные данные #Debugging, одни и те же несколько индексов trainSample из моего евклидова уравнения расстояния обнаруживаются почти все время, что приводит к тому, что typeIndex всегда одинаков для каждого прогона. Это приводит к тому, что вычисление цикла точности работает только для этого одного типа класса по сравнению со всеми другими типами классов (например, если typeIndex = 5 для всех testSamples, тогда все индексы с 1 по 7, которые не являются 5, неверны), что приводит к такая же плохая точность. Итак, из того, что я могу сказать, проблема в том, что «typeIndex» никогда не меняется.
def EuclidCalc(data1, data2, length):
distance = 0
for point in range(length):
#for this project, data1 (test data) has only 1 element here
distance += math.pow(data1 - data2[point], 2)
distance = math.sqrt(distance)
return distance
def KNNPredict(trainFold, testFold, classInfo, k):
fragTypes = [] #array to store all the calculated fragment types
totalCorrect = 0 #used for accuracy
runCount = 0
#for all test samples in the test fold
for testSample in range(len(testFold)):
#Attempt to calculate the correct fragment type within this for loop
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# create distance and (k) nearest neighbors arrays
distances = []
nearestNeighbors = [] #length = k
for trainSample in range(len(trainFold)):
#find the Euclidean distance between samples
distance = EuclidCalc(testFold[testSample], trainFold[trainSample], len(trainFold[trainSample]))
distances.append([distance, trainSample]) #record the current sample with its corresponding distance
#sort distances array in ascending order
distances = sorted(distances)
if(runCount < 1):
print("3 closest distances: ", distances[0:3])
#find the (k) nearest neighbors in the trainFold array
for kNeighbor in range(k):
neighborIndex = distances[kNeighbor][1]
nearestNeighbors.append(classInfo[neighborIndex]) #record the found nearest neighbor type
if(runCount < 1):
print("neigbhors: ", nearestNeighbors)
classVotes = {} #create dictionary for the votes, this is more flexible for the number of class types
for neighbor in range(len(nearestNeighbors)):
vote = nearestNeighbors[neighbor] #return classType
#either add vote to existing collection of the same class type,
#or create a new class vote type
if vote in classVotes: #if class type votes were already done
classVotes[vote] = classVotes[vote] + 1 #add another vote to the same class type
else:
classVotes[vote] = 1 #create a new tally of votes for this class type
if(runCount < 1):
print("all classes with their number of votes: ", classVotes)
typeIndex = max(classVotes.keys(), key=(lambda keyVal: classVotes[keyVal])) #determine which type got the most votes
if(runCount < 1):
print("chosen type: ", typeIndex)
input("Press Enter to continue")
#record calculated fragment type
fragTypes.append(typeIndex)
runCount = runCount + 1
for fragment in range(len(fragTypes)):
correctType = int(classInfo[fragment]) #find the correct type for each test fold fragment
#print("correct type: ", correctType)
#print("found type: ", fragTypes[fragment])
#input("Press Enter to continue")
if (int(fragTypes[fragment]) == correctType):
totalCorrect = totalCorrect + 1
accuracy = float(totalCorrect/float(len(classInfo))) #convert accuracy to a float between 0 and 1
return accuracy
def createFolds(fragArray, iterArray):
iterNum = 1 #iteration number in iterArray
randomClass = 0 #the type class associated with the iteration
extractArray = fragArray #use this array to remove the test column
folds = [] #store all train and test folds here
#while all iteration types are still being found
while (iterNum < len(iterArray) + 1):
#for all iterations
for iterationVal in range(len(iterArray)):
if(int(iterArray[iterationVal][1]) == iterNum): #if the iterations match
randomClass = iterArray[iterationVal][0] #get the "random" class column index associated with the iteration
testSet = [row[randomClass - 1] for row in fragArray] #separate the test class column from fragArray
trainSet = np.delete(extractArray, (randomClass - 1), 1) #remove the test class column from extractArray
trainSet = trainSet.tolist()
folds.append([trainSet, testSet]) #save training and test arrays as a fold
extractArray = fragArray #reset extract array
iterNum = iterNum + 1
return folds
def KNNCrossCalc(fragArray, iterArray, k):
classInfo = [row[len(fragArray[0]) - 1] for row in fragArray]
#return training and test dataset folds as a single total fold
folds = createFolds(fragArray, iterArray)
#print(np.array(indexArray).shape)
#To get the training set of each fold: folds[fold of choice][0]
#To get the test set of each fold: folds[fold of choice][1]
#DEBUGGING!!!!!!!!!!!!!!!
#print(np.array(folds[0][0]).shape) = (214, 9)
#print(np.array(folds[0][1]).shape) = (214, )
totalAccuracy = 0
for foldNum in range(len(folds)): #for each collection of folds
#find the accuracy for each fold using KNN
accuracy = KNNPredict(folds[foldNum][0], folds[foldNum][1], classInfo, k)
#print("Fold ", (foldNum + 1), " accuracy: ", (accuracy * 100), "%")
#accumulate all accuracy calculations in totalAccuracy
totalAccuracy = totalAccuracy + accuracy
#calculate the average accuracy for this run for all folds
averageAccuracy = float(totalAccuracy / len(folds))
print("\nAverage accuracy for all folds: ", (averageAccuracy* 100), "%")