전제 조건: 가장 가까운 K 이웃
해시테이블 자바
소개
키, 몸무게, 나이 등의 수치적 특성을 갖는 항목의 데이터 세트가 있다고 가정해 보겠습니다. 기능 개수가 다음과 같은 경우 N 항목을 점으로 표현할 수 있습니다. N -차원 격자. 새 항목이 주어지면 해당 항목에서 세트의 다른 모든 항목까지의 거리를 계산할 수 있습니다. 우리는 케이 가장 가까운 이웃을 선택하고 이러한 이웃이 대부분 어디에 분류되어 있는지 확인합니다. 거기에서 새 항목을 분류합니다.
그래서 문제는 된다 항목 사이의 거리를 계산하는 방법. 이에 대한 해결책은 데이터 세트에 따라 다릅니다. 값이 실수인 경우 일반적으로 유클리드 거리를 사용합니다. 값이 범주형이거나 이진형인 경우 일반적으로 해밍 거리를 사용합니다.
연산:
Given a new item: 1. Find distances between new item and all other items 2. Pick k shorter distances 3. Pick the most common class in these k distances 4. That class is where we will classify the new item
데이터 읽기
입력 파일을 다음 형식으로 만듭니다.
Height Weight Age Class 1.70 65 20 Programmer 1.90 85 33 Builder 1.78 76 31 Builder 1.73 74 24 Programmer 1.81 75 35 Builder 1.73 70 75 Scientist 1.80 71 63 Scientist 1.75 69 25 Programmer
각 항목은 선이며 '클래스' 아래에서 항목이 분류된 위치를 확인할 수 있습니다. 기능 이름('높이' 등) 아래의 값은 해당 기능에 대한 항목의 값입니다. 모든 값과 기능은 쉼표로 구분됩니다.
이 데이터 파일을 작업 디렉터리에 배치하세요. 데이터2 그리고 데이터 . 하나를 선택하고 내용을 있는 그대로 이름이 지정된 텍스트 파일에 붙여넣습니다. 데이터 .
파일('data.txt'라는 이름)에서 읽고 입력을 줄별로 분할합니다.
f = open('data.txt' 'r'); lines = f.read().splitlines(); f.close();
파일의 첫 번째 줄에는 끝에 'Class' 키워드가 있는 기능 이름이 포함됩니다. 우리는 기능 이름을 목록에 저장하려고 합니다.
# Split the first line by commas # remove the first element and # save the rest into a list. The # list now holds the feature # names of the data set. features = lines[0].split(' ')[:-1];
그런 다음 데이터 세트 자체로 이동합니다. 항목을 이름이 지정된 목록에 저장합니다. 아이템 해당 요소는 사전(각 항목당 하나씩)입니다. 이러한 항목 사전의 키는 기능 이름과 항목 클래스를 보유하는 '클래스'입니다. 결국 우리는 목록의 항목을 섞기를 원합니다(항목의 순서가 이상한 경우를 대비한 안전 조치입니다).
items = []; for i in range(1 len(lines)): line = lines[i].split(' '); itemFeatures = {'Class' : line[-1]}; # Iterate through the features for j in range(len(features)): # Get the feature at index j f = features[j]; # The first item in the line # is the class skip it v = float(line[j]); # Add feature to dict itemFeatures[f] = v; # Append temp dict to items items.append(itemFeatures); shuffle(items);
데이터 분류
저장된 데이터로 아이템 이제 분류기를 구축하기 시작합니다. 분류기를 위해 우리는 새로운 함수를 생성할 것입니다 나누다 . 항목 목록을 분류하려는 항목을 입력으로 사용하고 케이 가장 가까운 이웃의 수.
만약에 케이 데이터 세트의 총 항목 수보다 더 가까운 이웃을 가질 수 없으므로 분류를 진행하지 않습니다. (또는 k를 아이템 오류 메시지를 반환하는 대신 길이)
if(k > len(Items)): # k is larger than list # length abort return 'k larger than list length';
우리는 분류할 항목과 훈련 세트에 있는 모든 항목 사이의 거리를 계산하려고 합니다. 케이 최단 거리. 현재 가장 가까운 이웃을 유지하기 위해 다음과 같은 목록을 사용합니다. 이웃 . 최소의 각 요소는 분류할 항목으로부터의 거리에 대한 값과 이웃이 속해 있는 클래스에 대한 값 두 개를 보유합니다. 일반화된 유클리드 공식을 통해 거리를 계산합니다(예: N 치수). 그런 다음 가장 많이 나타나는 클래스를 선택하겠습니다. 이웃 그리고 그것이 우리의 선택이 될 것입니다. 코드에서:
def Classify(nItem k Items): if(k > len(Items)): # k is larger than list # length abort return 'k larger than list length'; # Hold nearest neighbors. # First item is distance # second class neighbors = []; for item in Items: # Find Euclidean Distance distance = EuclideanDistance(nItem item); # Update neighbors either adding # the current item in neighbors # or not. neighbors = UpdateNeighbors(neighbors item distance k); # Count the number of each # class in neighbors count = CalculateNeighborsClass(neighbors k); # Find the max in count aka the # class with the most appearances. return FindMax(count);
구현해야 할 외부 기능은 다음과 같습니다. 유클리드거리 업데이트이웃 NeighborsClass 계산 그리고 FindMax .
유클리드 거리 구하기
두 벡터 x와 y에 대한 일반화된 유클리드 공식은 다음과 같습니다.
distance = sqrt{(x_{1}-y_{1})^2 + (x_{2}-y_{2})^2 + ... + (x_{n}-y_{n})^2}
코드에서:
셀레늄 기초Python3
def EuclideanDistance(x y): # The sum of the squared # differences of the elements S = 0; for key in x.keys(): S += math.pow(x[key]-y[key] 2); # The square root of the sum return math.sqrt(S);
이웃 업데이트 중
우리는 이웃 목록을 가지고 있습니다(최대 길이는 다음과 같습니다). 케이 ) 그리고 우리는 주어진 거리에 따라 목록에 항목을 추가하려고 합니다. 먼저 우리는 이웃 길이가 있다 케이 . 그 수가 적으면 거리에 관계없이 항목을 추가합니다(목록을 최대로 채워야 하기 때문에). 케이 품목 거부를 시작하기 전에). 그렇지 않은 경우 항목이 목록에 최대 거리가 있는 항목보다 거리가 짧은지 확인합니다. 이것이 사실이라면 최대 거리가 있는 항목을 새 항목으로 교체합니다.
최대 거리 항목을 더 빨리 찾기 위해 목록을 오름차순으로 정렬합니다. 따라서 목록의 마지막 항목은 최대 거리를 갖습니다. 새로운 상품으로 교환하여 다시 정리하도록 하겠습니다.
이 프로세스의 속도를 높이기 위해 전체 목록을 정렬할 필요 없이 목록에 새 항목을 삽입하는 삽입 정렬을 구현할 수 있습니다. 이에 대한 코드는 다소 길며 간단하더라도 튜토리얼이 중단될 수 있습니다.
def UpdateNeighbors(neighbors item distance k): if(len(neighbors) > distance): # If yes replace the last # element with new item neighbors[-1] = [distance item['Class']]; neighbors = sorted(neighbors); return neighbors;
NeighborsClass 계산
여기서는 가장 자주 나타나는 클래스를 계산해 보겠습니다. 이웃 . 이를 위해 우리는 다음과 같은 다른 사전을 사용할 것입니다. 세다 여기서 키는 다음에 나타나는 클래스 이름입니다. 이웃 . 키가 존재하지 않으면 키를 추가하고 그렇지 않으면 값을 증가시킵니다.
def CalculateNeighborsClass(neighbors k): count = {}; for i in range(k): if(neighbors[i][1] not in count): # The class at the ith index # is not in the count dict. # Initialize it to 1. count[neighbors[i][1]] = 1; else: # Found another item of class # c[i]. Increment its counter. count[neighbors[i][1]] += 1; return count;
FindMax
이 함수에 사전을 입력하겠습니다. 세다 우리는 구축 NeighborsClass 계산 그리고 우리는 그것의 최대값을 반환할 것입니다.
def FindMax(countList): # Hold the max maximum = -1; # Hold the classification classification = ''; for key in countList.keys(): if(countList[key] > maximum): maximum = countList[key]; classification = key; return classification maximum;
결론
이것으로 이 kNN 튜토리얼이 끝났습니다.
이제 새 항목 설정을 분류할 수 있습니다. 케이 당신이 적합하다고 생각하는대로. 일반적으로 k에는 홀수가 사용되지만 반드시 그럴 필요는 없습니다. 새 항목을 분류하려면 기능 이름과 항목을 특징짓는 값이 포함된 사전을 만들어야 합니다. 분류의 예:
newItem = {'Height' : 1.74 'Weight' : 67 'Age' : 22}; print Classify(newItem 3 items);
위 접근 방식의 전체 코드는 다음과 같습니다.
# Python Program to illustrate # KNN algorithm # For pow and sqrt import math from random import shuffle ###_Reading_### def ReadData(fileName): # Read the file splitting by lines f = open(fileName 'r') lines = f.read().splitlines() f.close() # Split the first line by commas # remove the first element and save # the rest into a list. The list # holds the feature names of the # data set. features = lines[0].split(' ')[:-1] items = [] for i in range(1 len(lines)): line = lines[i].split(' ') itemFeatures = {'Class': line[-1]} for j in range(len(features)): # Get the feature at index j f = features[j] # Convert feature value to float v = float(line[j]) # Add feature value to dict itemFeatures[f] = v items.append(itemFeatures) shuffle(items) return items ###_Auxiliary Function_### def EuclideanDistance(x y): # The sum of the squared differences # of the elements S = 0 for key in x.keys(): S += math.pow(x[key] - y[key] 2) # The square root of the sum return math.sqrt(S) def CalculateNeighborsClass(neighbors k): count = {} for i in range(k): if neighbors[i][1] not in count: # The class at the ith index is # not in the count dict. # Initialize it to 1. count[neighbors[i][1]] = 1 else: # Found another item of class # c[i]. Increment its counter. count[neighbors[i][1]] += 1 return count def FindMax(Dict): # Find max in dictionary return # max value and max index maximum = -1 classification = '' for key in Dict.keys(): if Dict[key] > maximum: maximum = Dict[key] classification = key return (classification maximum) ###_Core Functions_### def Classify(nItem k Items): # Hold nearest neighbours. First item # is distance second class neighbors = [] for item in Items: # Find Euclidean Distance distance = EuclideanDistance(nItem item) # Update neighbors either adding the # current item in neighbors or not. neighbors = UpdateNeighbors(neighbors item distance k) # Count the number of each class # in neighbors count = CalculateNeighborsClass(neighbors k) # Find the max in count aka the # class with the most appearances return FindMax(count) def UpdateNeighbors(neighbors item distance k ): if len(neighbors) < k: # List is not full add # new item and sort neighbors.append([distance item['Class']]) neighbors = sorted(neighbors) else: # List is full Check if new # item should be entered if neighbors[-1][0] > distance: # If yes replace the # last element with new item neighbors[-1] = [distance item['Class']] neighbors = sorted(neighbors) return neighbors ###_Evaluation Functions_### def K_FoldValidation(K k Items): if K > len(Items): return -1 # The number of correct classifications correct = 0 # The total number of classifications total = len(Items) * (K - 1) # The length of a fold l = int(len(Items) / K) for i in range(K): # Split data into training set # and test set trainingSet = Items[i * l:(i + 1) * l] testSet = Items[:i * l] + Items[(i + 1) * l:] for item in testSet: itemClass = item['Class'] itemFeatures = {} # Get feature values for key in item: if key != 'Class': # If key isn't 'Class' add # it to itemFeatures itemFeatures[key] = item[key] # Categorize item based on # its feature values guess = Classify(itemFeatures k trainingSet)[0] if guess == itemClass: # Guessed correctly correct += 1 accuracy = correct / float(total) return accuracy def Evaluate(K k items iterations): # Run algorithm the number of # iterations pick average accuracy = 0 for i in range(iterations): shuffle(items) accuracy += K_FoldValidation(K k items) print accuracy / float(iterations) ###_Main_### def main(): items = ReadData('data.txt') Evaluate(5 5 items 100) if __name__ == '__main__': main()
산출:
0.9375
출력은 기계마다 다를 수 있습니다. 코드에는 Fold Validation 기능이 포함되어 있지만 알고리즘의 정확도를 계산하기 위해 존재하는 알고리즘과는 관련이 없습니다.
퀴즈 만들기