I. A métrica da distância
Primeiro, o número de recursos (colunas) em um conjunto de dados não é um fator na seleção de uma métrica de distância para uso em kNN. Existem alguns estudos publicados direcionados exatamente a essa questão, e as bases usuais para comparação são:
a distribuição estatística subjacente dos seus dados;
a relação entre os recursos que compõem seus dados (eles são independentes - isto é, como é a matriz de covariância); e
o espaço de coordenadas a partir do qual seus dados foram obtidos.
Se você não tem conhecimento prévio das distribuições das quais seus dados foram amostrados, pelo menos um estudo (bem documentado e completo) conclui que a distância euclidiana é a melhor escolha.
Métrica YEuclidiana usada em Mecanismos de Recomendação da Web em grande escala, bem como em pesquisas acadêmicas atuais. As distâncias calculadas por Euclidiano têm significado intuitivo e as escalas de computação - ou seja, a distância euclidiana é calculada da mesma maneira, independentemente de os dois pontos estarem em duas dimensões ou em vinte e duas dimensões.
Só falhou algumas vezes, cada um desses casos a distância euclidiana falhou porque o sistema de coordenadas (cartesiano) subjacente era uma má escolha. E você geralmente reconhece isso porque, por exemplo, os comprimentos do caminho (distâncias) não são mais aditivos - por exemplo, quando o espaço métrico é um tabuleiro de xadrez, a distância de Manhattan é melhor que a Euclidiana, da mesma forma quando o espaço métrico é a Terra e suas distâncias são trans - vôos continentais, uma métrica de distância adequada para um sistema de coordenadas polares é uma boa idéia (por exemplo, Londres para Viena é de 2,5 horas, Viena para São Petersburgo é mais 3 horas, mais ou menos na mesma direção, mas Londres para St Petersburg não é de 5,5 horas, é um pouco mais de 3 horas.)
Mas, além dos casos em que seus dados pertencem a um sistema de coordenadas não cartesiano, a escolha da métrica de distância geralmente não é material. (Veja esta postagem de blog de um estudante de CS, comparando várias métricas de distância examinando seu efeito no classificador kNN - o quadrado do chi fornece os melhores resultados, mas as diferenças não são grandes; um estudo mais abrangente está no artigo acadêmico, Estudo Comparativo de Funções de distância para os vizinhos mais próximos - Mahalanobis (essencialmente euclidiano normalizado para explicar a covariância da dimensão) foi o melhor neste estudo.
Uma condição importante: para que os cálculos da métrica à distância sejam significativos, você deve redimensionarseus dados - raramente é possível criar um modelo kNN para gerar previsões precisas sem fazer isso. Por exemplo, se você está construindo um modelo de kNN para prever o desempenho atlético, e suas variáveis de expectativa são altura (cm), peso (kg), gordura corporal (%) e pulso em repouso (batimentos por minuto), um ponto de dados típico pode algo parecido com isto: [180.4, 66.1, 11.3, 71]. Claramente, o cálculo da distância será dominado pela altura, enquanto a contribuição por% de gordura corporal será quase insignificante. Dito de outra forma, se os dados fossem informados de maneira diferente, de modo que o peso corporal estivesse em gramas em vez de quilogramas, o valor original de 86,1 seria 86.100, o que teria um grande efeito sobre os resultados, exatamente o que você não usa. não quero.
X_new = (X_old - mu) / sigma
II A estrutura de dados
Se você está preocupado com o desempenho da estrutura do kd-tree, o A Voronoi Tessellation é um contêiner conceitualmente simples, mas que melhora drasticamente o desempenho e dimensiona melhor que o kd-Trees.
Essa não é a maneira mais comum de persistir os dados de treinamento de kNN, embora a aplicação do VT para esse fim, bem como as consequentes vantagens de desempenho, estejam bem documentadas (consulte, por exemplo, este relatório da Microsoft Research ). O significado prático disso é que, desde que você esteja usando uma linguagem 'mainstream' (por exemplo, no Índice TIOBE ), você deverá encontrar uma biblioteca para executar a TV. Eu sei que em Python e R, existem várias opções para cada idioma (por exemplo, o pacote voronoi para R disponível no CRAN )
O uso de um VT para kNN funciona assim:
A partir dos seus dados, selecione aleatoriamente w points - esses são os seus centros Voronoi. Uma célula Voronoi encapsula todos os pontos vizinhos que estão mais próximos de cada centro. Imagine se você atribuir uma cor diferente a cada um dos centros de Voronoi, para que cada ponto atribuído a um determinado centro seja pintado dessa cor. Contanto que você tenha uma densidade suficiente, isso mostrará muito bem os limites de cada centro de Voronoi (como o limite que separa duas cores.
Como selecionar os Centros Voronoi? Eu uso duas orientações ortogonais. Depois de selecionar aleatoriamente os pontos w, calcule o VT para seus dados de treinamento. Em seguida, verifique o número de pontos de dados atribuídos a cada centro Voronoi - esses valores devem ser os mesmos (dada densidade uniforme de pontos no espaço de dados). Em duas dimensões, isso causaria um VT com blocos do mesmo tamanho. Essa é a primeira regra, aqui está a segunda. Selecione w por iteração - execute seu algoritmo kNN com w como parâmetro variável e meça o desempenho (tempo necessário para retornar uma previsão consultando o VT).
Imagine que você tenha um milhão de pontos de dados ... Se os pontos persistissem em uma estrutura de dados 2D comum ou em uma árvore kd, você executaria, em média, alguns milhões de cálculos de distância para cadanovos pontos de dados cuja variável de resposta você deseja prever. Obviamente, esses cálculos são realizados em um único conjunto de dados. Com um V / T, a busca pelo vizinho mais próximo é realizada em duas etapas, uma após a outra, contra duas populações diferentes de dados - primeiro contra os centros Voronoi, depois que o centro mais próximo é encontrado, os pontos dentro da célula correspondentes a esse centro é pesquisado para encontrar o vizinho mais próximo real (por cálculos sucessivos de distância) Combinados, essas duas pesquisas são muito mais rápidas que uma única pesquisa de força bruta. É fácil ver: para 1 milhão de pontos de dados, suponha que você selecione 250 centros Voronoi para otimizar seu espaço de dados. Em média, cada célula Voronoi terá 4.000 pontos de dados. Portanto, em vez de realizar em média 500.000 cálculos de distância (força bruta), você realiza muito menos, em média apenas 125 + 2.000.
III Cálculo do resultado (a variável de resposta prevista)
Há duas etapas para calcular o valor previsto a partir de um conjunto de dados de treinamento kNN. O primeiro é identificar n ou o número de vizinhos mais próximos a serem usados para esse cálculo. A segunda é como ponderar sua contribuição para o valor previsto.
Com o primeiro componente, é possível determinar o melhor valor de n resolvendo um problema de otimização (muito semelhante à otimização de mínimos quadrados). Essa é a teoria; na prática, a maioria das pessoas apenas usa n = 3. De qualquer forma, é simples executar o algoritmo kNN em um conjunto de instâncias de teste (para calcular valores previstos) para n = 1, n = 2, n = 3, etc. e plotar o erro como uma função de n. Se você quer apenas um valor plausível para n começar, novamente, basta usar n = 3.
O segundo componente é como ponderar a contribuição de cada um dos vizinhos (assumindo n> 1).
A técnica de ponderação mais simples é apenas multiplicar cada vizinho por um coeficiente de ponderação, que é apenas 1 / (dist * K), ou o inverso da distância desse vizinho à instância de teste, frequentemente multiplicado por alguma constante derivada empiricamente, K. I não sou fã dessa técnica porque geralmente sobrecarrega demais os vizinhos mais próximos (e concomitantemente sobrecarrega os vizinhos mais distantes); o significado disso é que uma determinada previsão pode ser quase inteiramente dependente de um único vizinho, o que, por sua vez, aumenta a sensibilidade do algoritmo ao ruído.
Uma função de ponderação deve melhor, que evita substancialmente essa limitação é a função gaussiana , que em python se parece com isso:
def weight_gauss(dist, sig=2.0) :
return math.e**(-dist**2/(2*sig**2))
Para calcular um valor previsto usando seu código kNN, identifique os n vizinhos mais próximos do ponto de dados cuja variável de resposta deseja prever ('instância de teste') e chame a função weight_gauss, uma vez para cada um dos n vizinhos, passando na distância entre cada vizinho, o ponto de teste. Essa função retornará o peso para cada vizinho, que será usado como coeficiente desse vizinho no cálculo da média ponderada.