美文网首页
机器学习-有监督学习-分类算法-K最近邻法(KNN)-原理、Py

机器学习-有监督学习-分类算法-K最近邻法(KNN)-原理、Py

作者: 精神秃头生信小伙儿 | 来源:发表于2021-10-04 20:44 被阅读0次

    基本原理

    首先放一张各大网站用烂的图

    image.png

    KNN的基本思想是比较简单的,就是假设我们有红色和蓝色得到数据点,然后我们新加入一个绿色点,根据绿色点最近的点是红色最多还是蓝色最多,这个用距离来衡量(常用的是欧式距离),来判断绿色的点属于哪个类别,而附近点的数目取多少(即k值大小)来判断,也是比较重要的,一般来说网上看到很多都是默认30或20以下,1~20左右,然后可以用k=1-20,分别拟合预测数据,来根据预测结果的好坏选择合适的k值。数据维度比较高的话,我们可以先用PCA降维,再用KNN分类预测。不过,如果你的训练集当中,某一类别的占比非常之高,这就可能造成很大的误差,这时候用KNN怎么优化预测结果大概率都是占比高的那个类别,因此在这种情况下,最好不要使用KNN。

    R应用

    R的话,做knn可以用class里面的knn函数,或者用caret里面的train函数,method设置成knn。因为caret可以直接进行交叉验证根据结果选择最佳k值,因此用其是比较方便的。

    以下提供了两种包的实现方式,使用来自bioconductor的白血病基因表达数据集。

    rm(list=ls())
    library(leukemiasEset)  # 白血病数据集
    library(class)  # 分类用的R包,包含一个简易的knn
    library(caret)  # 同样包含knn,但功能更加全面强大,可以直接进行交叉验证
    library(purrr)  # 方便手动写迭代函数,计算best k。
    
    
    data("leukemiasEset")
    exprdata <- exprs(leukemiasEset)
    exprtrain <- as.data.frame(t(exprdata))
    # PCA
    pca.exprtrain <- prcomp(exprtrain, scale = TRUE)
    cumvar <- round(cumsum(pca.exprtrain$sdev**2/sum(pca.exprtrain$sdev**2))*100, 2)
    names(cumvar) <- paste("PC", 1:length(cumvar), sep="")
    # Select the least number of principal components so that the sum of the cumulative proportion of variance is >95%
    inputSet <- as.data.frame(pca.exprtrain$x[, 1:which(cumvar>95)[1]])
    inputSet$type <- leukemiasEset$LeukemiaType
    # KNN
    # By manually dividing the data set into a training set and a test set by 7:3
    train.ind <- sample(1:nrow(inputSet), 0.7*nrow(inputSet), replace = FALSE)
    train <- inputSet[train.ind, ]
    x.train <- train[, -ncol(train)]
    y.train <- train$type
    test <- inputSet[-train.ind, ]
    x.test <- test[, -ncol(test)]
    y.test <- test$type
    bestknn <- function(kvalue){
        knn.predict <- knn(x.train, x.test, y.train, k=kvalue)
        confusion <- as.matrix(table(knn.predict, y.test))
        acc <- sum(diag(confusion))/sum(confusion)
    }
    knnacc <- map_dbl(1:20, bestknn)
    # best k
    which(knnacc == max(knnacc))[length(which(knnacc == max(knnacc)))]
    
    # Run knn with caret and perform k-fold cross-validation
    control <- trainControl(method="cv", number=5, savePredictions = TRUE, classProbs = TRUE)
    set.seed(123)
    knn.caret <- train(type~., data=train, method="knn", 
                 metric="Accuracy", trControl=control, tuneGrid=expand.grid(k=seq(1, 20)))
    knn.caret
    knnPredict <- predict(knn.caret, newdata=test)
    confusionMatrix(knnPredict, y.test)
    

    Python应用

    Python的话为了简便起见用了手写数字数据集来先降维后预测,同样也是分为7:3分割数据集的模式和交叉验证的模式,选取k=1-20,分别计算准确率,取使其最高的k。

    from sklearn import datasets
    from sklearn.decomposition import PCA
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.model_selection import train_test_split, cross_val_score
    from sklearn.metrics import accuracy_score
    import numpy as np
    
    
    digits = datasets.load_digits()
    # PCA
    pca = PCA(digits.data.shape[1])
    pca.fit(digits.data)
    n_index = np.where(np.cumsum(pca.explained_variance_ratio_) > 0.95)[0][0]
    digits_pca = pca.transform(digits.data)[:, 0:n_index+1]
    x_train, x_test, y_train, y_test = train_test_split(
        digits_pca,
        digits.target,
        train_size=0.3,
        stratify=digits.target
    )
    # KNN with 7:3 training and test sets
    acc1 = []
    for k in range(1, 21):
        knn = KNeighborsClassifier(k)
        knn.fit(x_train, y_train)
        y_pred = knn.predict(x_test)
        acc1.append(accuracy_score(y_test, y_pred))
    k_best1 = np.where(acc1==max(acc1))[0][0]+1
    # KNN with cv
    acc2 = []
    for k in range(1, 21):
        knn = KNeighborsClassifier(k)
        scores = cross_val_score(knn, digits_pca, digits.target, cv=10, scoring="accuracy")
        acc2.append(scores.mean())
    k_best2 = np.where(acc2==max(acc2))[0][0]+1
    

    相关文章

      网友评论

          本文标题:机器学习-有监督学习-分类算法-K最近邻法(KNN)-原理、Py

          本文链接:https://www.haomeiwen.com/subject/kghwnltx.html