Model library K-Nearest Neighbors (KNN)
Statistical model reference

K-Nearest Neighbors (KNN)

Review when to use this method, its data requirements, implementation patterns, and interpretation guidance.

Description

A simple yet effective non-parametric method that classifies or predicts based on the majority class or average value of the k nearest data points. KNN makes no assumptions about data distribution and adapts to complex decision boundaries through local approximations, making it useful for classification, regression, recommendation systems, and as a baseline for more complex models when prior knowledge about data structure is limited. The algorithm's performance heavily depends on distance metric selection and feature scaling.

Use Cases
  • classification
  • regression
  • recommendation systems
  • missing value imputation
  • anomaly detection
  • pattern recognition
Requirements
  • Sample Size: small, medium
  • Missing Data: none, random
  • Data Distribution: any
  • Relationship Type: distance-based, non-linear, local
Variable Types
Dependent Variables
  • continuous
  • categorical
  • binary
  • ordinal
Independent Variables
  • continuous
  • categorical
Implementation
from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV

# Create preprocessing and modeling pipeline
pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('knn', KNeighborsClassifier())
])

# Parameter grid for tuning
param_grid = {
    'knn__n_neighbors': [3, 5, 7, 9],
    'knn__weights': ['uniform', 'distance'],
    'knn__p': [1, 2]  # 1: Manhattan, 2: Euclidean
}

# Classification with tuned parameters
grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(X_train, y_train)

# Regression model
knn_reg = Pipeline([
    ('scaler', StandardScaler()),
    ('knn', KNeighborsRegressor(n_neighbors=5))
])
knn_reg.fit(X_train, y_train)

# Best parameters
print(grid.best_params_)

# Visualize decision boundaries (for 2D data)
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train)
plt.title('KNN Decision Boundary')
plt.show()
Documentation
library(caret)
library(FNN)

# Scale features
preProc <- preProcess(train_data, method=c("center", "scale"))
train_scaled <- predict(preProc, train_data)
test_scaled <- predict(preProc, test_data)

# Classification with tuned parameters
ctrl <- trainControl(method="cv", number=5)
knn_fit <- train(
  y ~ ., 
  data = train_scaled,
  method = "knn",
  trControl = ctrl,
  tuneGrid = expand.grid(k = 1:10),
  metric = "Accuracy"
)

# Regression
knn_reg <- knn.reg(
  train = train_scaled[, -which(names(train_scaled) == "y")],
  test = test_scaled[, -which(names(test_scaled) == "y")],
  y = train_scaled$y,
  k = 5
)

# Plot results
plot(knn_fit)
plot(test_scaled$y, knn_reg$pred, main="Actual vs Predicted")
Documentation
KNN
  /TARGET target_var
  /FEATURES var1 var2 var3
  /NEIGHBORS 5
  /DISTANCE MINKOWSKI(2)
  /WEIGHTS DISTANCE
  /PRINT CONFUSION
  /SAVE PREDICTED(pred_knn) NEIGHBORS(neighbors).

* For regression:
KNN
  /TARGET target_var
  /FEATURES var1 var2 var3
  /NEIGHBORS 5
  /TYPE REGRESSION
  /PRINT SUMMARY.
Documentation
/* Classification */
PROC KNN DATA=train 
  TESTDATA=test
  K=5
  METHOD=EUCLIDEAN
  STANDARDIZE=STD;
  INPUT var1-var8 / LEVEL=INTERVAL;
  TARGET target_var / LEVEL=NOMINAL;
  SCORE OUT=scored;
RUN;

/* Regression */
PROC KNN DATA=train 
  TESTDATA=test
  K=5
  METHOD=EUCLIDEAN
  STANDARDIZE=STD
  TYPE=REGRESSION;
  INPUT var1-var8 / LEVEL=INTERVAL;
  TARGET target_var / LEVEL=INTERVAL;
RUN;
Documentation
* Classification
knn y x1 x2 x3, k(5) distance(euclidean) weight(inverse)
predict yhat

* Regression
knnreg y x1 x2 x3, k(5) distance(minkowski) 

* Find optimal k
knn tune y x1-x3, krange(1 10) cv(5)
Documentation
Synthetic Data Example

Comprehensive synthetic datasets demonstrating KNN's ability to handle different distance metrics and neighborhood sizes

R Code for Data Generation and Analysis
# Generate synthetic data with different patterns
set.seed(123)
library(ggplot2)

# Cluster pattern
n <- 200
cluster1 <- data.frame(
  x1 = rnorm(n/2, mean=-1, sd=0.5),
  x2 = rnorm(n/2, mean=-1, sd=0.5),
  y = "Class1"
)
cluster2 <- data.frame(
  x1 = rnorm(n/2, mean=1, sd=0.5),
  x2 = rnorm(n/2, mean=1, sd=0.5),
  y = "Class2"
)
df_cluster <- rbind(cluster1, cluster2)

# Checkerboard pattern
x1 <- runif(n, -2, 2)
x2 <- runif(n, -2, 2)
df_checker <- data.frame(
  x1,
  x2,
  y = factor(ifelse((x1 > 0 & x2 > 0) | (x1 < 0 & x2 < 0), "Class1", "Class2"))
)

# Visualize datasets
ggplot(df_cluster, aes(x1, x2, color=y)) + geom_point() + ggtitle("Cluster Pattern")
ggplot(df_checker, aes(x1, x2, color=y)) + geom_point() + ggtitle("Checkerboard Pattern")

# Train-test split
set.seed(456)
train_idx <- sample(1:n, 0.7*n)
train_cluster <- df_cluster[train_idx, ]
test_cluster <- df_cluster[-train_idx, ]
train_checker <- df_checker[train_idx, ]
test_checker <- df_checker[-train_idx, ]

# Scale features
scale_fn <- function(train, test) {
  means <- apply(train[,1:2], 2, mean)
  sds <- apply(train[,1:2], 2, sd)
  train_scaled <- as.data.frame(scale(train[,1:2], center=means, scale=sds))
  test_scaled <- as.data.frame(scale(test[,1:2], center=means, scale=sds))
  train_scaled$y <- train$y
  test_scaled$y <- test$y
  list(train=train_scaled, test=test_scaled)
}

cluster_scaled <- scale_fn(train_cluster, test_cluster)
checker_scaled <- scale_fn(train_checker, test_checker)

# Fit KNN models with different k
library(class)
k_values <- c(1, 3, 5, 10, 20)
results <- data.frame()

for (k in k_values) {
  # Cluster pattern
  pred_cluster <- knn(
    train = cluster_scaled$train[,1:2],
    test = cluster_scaled$test[,1:2],
    cl = cluster_scaled$train$y,
    k = k
  )
  acc_cluster <- mean(pred_cluster == cluster_scaled$test$y)
  
  # Checkerboard pattern
  pred_checker <- knn(
    train = checker_scaled$train[,1:2],
    test = checker_scaled$test[,1:2],
    cl = checker_scaled$train$y,
    k = k
  )
  acc_checker <- mean(pred_checker == checker_scaled$test$y)
  
  results <- rbind(results, data.frame(
    k = k,
    accuracy_cluster = acc_cluster,
    accuracy_checker = acc_checker
  ))
}

# Plot accuracy vs k
ggplot(results, aes(k)) +
  geom_line(aes(y=accuracy_cluster, color="Cluster Pattern")) +
  geom_line(aes(y=accuracy_checker, color="Checkerboard Pattern")) +
  labs(title="KNN Performance by k Value", y="Accuracy", color="Pattern") +
  scale_x_continuous(breaks=k_values)

# Create decision boundary plots
library(gridExtra)

generate_boundary_plot <- function(df, k, title) {
  # Create grid
  rng <- apply(df[,1:2], 2, range)
  x1_seq <- seq(rng[1,1], rng[2,1], length=100)
  x2_seq <- seq(rng[1,2], rng[2,2], length=100)
  grid <- expand.grid(x1=x1_seq, x2=x2_seq)
  
  # Predict on grid
  grid$pred <- knn(
    train = df[,1:2],
    test = grid[,1:2],
    cl = df$y,
    k = k
  )
  
  # Plot
  ggplot(grid, aes(x1, x2, fill=pred)) +
    geom_tile(alpha=0.3) +
    geom_point(data=df, aes(color=y), size=2) +
    ggtitle(paste(title, "(k =", k, ")")) +
    theme_minimal()
}

p1 <- generate_boundary_plot(cluster_scaled$train, 3, "Cluster Pattern")
p2 <- generate_boundary_plot(checker_scaled$train, 10, "Checkerboard Pattern")
grid.arrange(p1, p2, ncol=2)

# Print results
cat("Accuracy by k value:\n")
print(results)
Copy this code into your R environment to generate synthetic data and perform analysis with this model.
Expected Analysis Results
Console Output
Accuracy by k value:
   k accuracy_cluster accuracy_checker
1  1           0.950           0.783
2  3           0.967           0.850
3  5           0.967           0.883
4 10           0.950           0.917
5 20           0.933           0.900

Optimal k for Cluster Pattern: 3 or 5
Optimal k for Checkerboard Pattern: 10
Visualizations
Plot 1
Plot 2
Plot 3
These results are from running the R code on synthetic data. Your actual results may vary depending on your data.
Interpretation Guide

Need help interpreting the results of your K-Nearest Neighbors (KNN) analysis? Our comprehensive interpretation guide explains:

  • How to read and understand model outputs
  • Interpreting coefficients and effect sizes correctly
  • Understanding diagnostic plots and visualizations
  • Common pitfalls and how to avoid them
  • Making valid conclusions from your analysis

Statistical assistant