成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript機(jī)器學(xué)習(xí)之KNN算法

enrecul101 / 1825人閱讀

摘要:是的縮寫,它是一種監(jiān)督學(xué)習(xí)算法。每一個(gè)機(jī)器學(xué)習(xí)算法都需要數(shù)據(jù),這次我將使用數(shù)據(jù)集。其數(shù)據(jù)集包含了個(gè)樣本,都屬于鳶尾屬下的三個(gè)亞屬,分別是山鳶尾變色鳶尾和維吉尼亞鳶尾。四個(gè)特征被用作樣本的定量分析,它們分別是花萼和花瓣的長度和寬度。

譯者按: 機(jī)器學(xué)習(xí)原來很簡單啊,不妨動手試試!

原文: Machine Learning with JavaScript : Part 2

譯者: Fundebug

為了保證可讀性,本文采用意譯而非直譯。另外,本文版權(quán)歸原作者所有,翻譯僅用于學(xué)習(xí)。另外,我們修正了原文代碼中的錯(cuò)誤

上圖使用plot.ly所畫。

上次我們用JavaScript實(shí)現(xiàn)了線性規(guī)劃,這次我們來聊聊KNN算法。

KNN是k-Nearest-Neighbours的縮寫,它是一種監(jiān)督學(xué)習(xí)算法。KNN算法可以用來做分類,也可以用來解決回歸問題。

GitHub倉庫: machine-learning-with-js

KNN算法簡介

簡單地說,KNN算法由那離自己最近的K個(gè)點(diǎn)來投票決定待分類數(shù)據(jù)歸為哪一類

如果待分類的數(shù)據(jù)有這些鄰近數(shù)據(jù),NY: 7, NJ: 0, IN: 4,即它有7個(gè)NY鄰居,0個(gè)NJ鄰居,4個(gè)IN鄰居,則這個(gè)數(shù)據(jù)應(yīng)該歸類為NY

假設(shè)你在郵局工作,你的任務(wù)是為郵遞員分配信件,目標(biāo)是最小化到各個(gè)社區(qū)的投遞旅程。不妨假設(shè)一共有7個(gè)街區(qū)。這就是一個(gè)實(shí)際的分類問題。你需要將這些信件分類,決定它屬于哪個(gè)社區(qū),比如上東城、曼哈頓下城等。

最壞的方案是隨意分配信件分配給郵遞員,這樣每個(gè)郵遞員會拿到各個(gè)社區(qū)的信件。

最佳的方案是根據(jù)信件地址進(jìn)行分類,這樣每個(gè)郵遞員只需要負(fù)責(zé)鄰近社區(qū)的信件。

也許你是這樣想的:"將鄰近3個(gè)街區(qū)的信件分配給同一個(gè)郵遞員"。這時(shí),鄰近街區(qū)的個(gè)數(shù)就是k。你可以不斷增加k,直到獲得最佳的分配方案。這個(gè)k就是分類問題的最佳值。

KNN代碼實(shí)現(xiàn)

像上次一樣,我們將使用mljs的KNN模塊ml-knn來實(shí)現(xiàn)。

每一個(gè)機(jī)器學(xué)習(xí)算法都需要數(shù)據(jù),這次我將使用IRIS數(shù)據(jù)集。其數(shù)據(jù)集包含了150個(gè)樣本,都屬于鳶尾屬下的三個(gè)亞屬,分別是山鳶尾、變色鳶尾和維吉尼亞鳶尾。四個(gè)特征被用作樣本的定量分析,它們分別是花萼和花瓣的長度和寬度。

1. 安裝模塊
$ npm install [email protected] csvtojson prompt

ml-knn: k-Nearest-Neighbours模塊,不同版本的接口可能不同,這篇博客使用了2.0.0

csvtojson: 用于將CSV數(shù)據(jù)轉(zhuǎn)換為JSON

prompt: 在控制臺輸入輸出數(shù)據(jù)

2. 初始化并導(dǎo)入數(shù)據(jù)

IRIS數(shù)據(jù)集由加州大學(xué)歐文分校提供。

curl https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data > iris.csv

假設(shè)你已經(jīng)初始化了一個(gè)NPM項(xiàng)目,請?jiān)?strong>index.js中輸入以下內(nèi)容:

const KNN = require("ml-knn");
const csv = require("csvtojson");
const prompt = require("prompt");

var knn;

const csvFilePath = "iris.csv"; // 數(shù)據(jù)集
const names = ["sepalLength", "sepalWidth", "petalLength", "petalWidth", "type"];

let seperationSize; // 分割訓(xùn)練和測試數(shù)據(jù)

let data = [],
    X = [],
    y = [];

let trainingSetX = [],
    trainingSetY = [],
    testSetX = [],
    testSetY = [];

seperationSize用于分割數(shù)據(jù)和測試數(shù)據(jù)

使用csvtojson模塊的fromFile方法加載數(shù)據(jù):

csv(
    {
        noheader: true,
        headers: names
    })
    .fromFile(csvFilePath)
    .on("json", (jsonObj) =>
    {
        data.push(jsonObj); // 將數(shù)據(jù)集轉(zhuǎn)換為JS對象數(shù)組
    })
    .on("done", (error) =>
    {
        seperationSize = 0.7 * data.length;
        data = shuffleArray(data);
        dressData();
    });

我們將seperationSize設(shè)為樣本數(shù)目的0.7倍。注意,如果訓(xùn)練數(shù)據(jù)集太小的話,分類效果將變差。

由于數(shù)據(jù)集是根據(jù)種類排序的,所以需要使用shuffleArray函數(shù)對數(shù)據(jù)進(jìn)行混淆,這樣才能方便分割出訓(xùn)練數(shù)據(jù)。這個(gè)函數(shù)的定義請參考StackOverflow的提問How to randomize (shuffle) a JavaScript array?:

function shuffleArray(array)
{
    for (var i = array.length - 1; i > 0; i--)
    {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}
3. 轉(zhuǎn)換數(shù)據(jù)

數(shù)據(jù)集中每一條數(shù)據(jù)可以轉(zhuǎn)換為一個(gè)JS對象:

{
 sepalLength: ‘5.1’,
 sepalWidth: ‘3.5’,
 petalLength: ‘1.4’,
 petalWidth: ‘0.2’,
 type: ‘Iris-setosa’ 
}

在使用KNN算法訓(xùn)練數(shù)據(jù)之前,需要對數(shù)據(jù)進(jìn)行這些處理:

將屬性(sepalLength, sepalWidth,petalLength,petalWidth)由字符串轉(zhuǎn)換為浮點(diǎn)數(shù). (parseFloat)

將分類 (type)用數(shù)字表示

function dressData()
{
    let types = new Set(); 
    data.forEach((row) =>
    {
        types.add(row.type);
    });
    let typesArray = [...types]; 

    data.forEach((row) =>
    {
        let rowArray, typeNumber;
        rowArray = Object.keys(row).map(key => parseFloat(row[key])).slice(0, 4);
        typeNumber = typesArray.indexOf(row.type); // Convert type(String) to type(Number)

        X.push(rowArray);
        y.push(typeNumber);
    });

    trainingSetX = X.slice(0, seperationSize);
    trainingSetY = y.slice(0, seperationSize);
    testSetX = X.slice(seperationSize);
    testSetY = y.slice(seperationSize);

    train();
}
4. 訓(xùn)練數(shù)據(jù)并測試
function train()
{
    knn = new KNN(trainingSetX, trainingSetY,
    {
        k: 7
    });
    test();
}

train方法需要2個(gè)必須的參數(shù): 輸入數(shù)據(jù),即花萼和花瓣的長度和寬度;實(shí)際分類,即山鳶尾、變色鳶尾和維吉尼亞鳶尾。另外,第三個(gè)參數(shù)是可選的,用于提供調(diào)整KNN算法的內(nèi)部參數(shù)。我將k參數(shù)設(shè)為7,其默認(rèn)值為5。

訓(xùn)練好模型之后,就可以使用測試數(shù)據(jù)來檢查準(zhǔn)確性了。我們主要對預(yù)測出錯(cuò)的個(gè)數(shù)比較感興趣。

function test()
{
    const result = knn.predict(testSetX);
    const testSetLength = testSetX.length;
    const predictionError = error(result, testSetY);
    console.log(`Test Set Size = ${testSetLength} and number of Misclassifications = ${predictionError}`);
    predict();
}

比較預(yù)測值與真實(shí)值,就可以得到出錯(cuò)個(gè)數(shù):

function error(predicted, expected)
{
    let misclassifications = 0;
    for (var index = 0; index < predicted.length; index++)
    {
        if (predicted[index] !== expected[index])
        {
            misclassifications++;
        }
    }
    return misclassifications;
}
5. 進(jìn)行預(yù)測(可選)

任意輸入屬性值,就可以得到預(yù)測值

function predict()
{
    let temp = [];
    prompt.start();
    prompt.get(["Sepal Length", "Sepal Width", "Petal Length", "Petal Width"], function(err, result)
    {
        if (!err)
        {
            for (var key in result)
            {
                temp.push(parseFloat(result[key]));
            }
            console.log(`With ${temp} -- type =  ${knn.predict(temp)}`);
        }
    });
}
6. 完整程序

完整的程序index.js是這樣的:

const KNN = require("ml-knn");
const csv = require("csvtojson");
const prompt = require("prompt");

var knn;

const csvFilePath = "iris.csv"; // 數(shù)據(jù)集
const names = ["sepalLength", "sepalWidth", "petalLength", "petalWidth", "type"];

let seperationSize; // 分割訓(xùn)練和測試數(shù)據(jù)

let data = [],
    X = [],
    y = [];

let trainingSetX = [],
    trainingSetY = [],
    testSetX = [],
    testSetY = [];


csv(
    {
        noheader: true,
        headers: names
    })
    .fromFile(csvFilePath)
    .on("json", (jsonObj) =>
    {
        data.push(jsonObj); // 將數(shù)據(jù)集轉(zhuǎn)換為JS對象數(shù)組
    })
    .on("done", (error) =>
    {
        seperationSize = 0.7 * data.length;
        data = shuffleArray(data);
        dressData();
    });

function dressData()
{
    let types = new Set(); 
    data.forEach((row) =>
    {
        types.add(row.type);
    });
    let typesArray = [...types]; 

    data.forEach((row) =>
    {
        let rowArray, typeNumber;
        rowArray = Object.keys(row).map(key => parseFloat(row[key])).slice(0, 4);
        typeNumber = typesArray.indexOf(row.type); // Convert type(String) to type(Number)

        X.push(rowArray);
        y.push(typeNumber);
    });

    trainingSetX = X.slice(0, seperationSize);
    trainingSetY = y.slice(0, seperationSize);
    testSetX = X.slice(seperationSize);
    testSetY = y.slice(seperationSize);

    train();
}


// 使用KNN算法訓(xùn)練數(shù)據(jù)
function train()
{
    knn = new KNN(trainingSetX, trainingSetY,
    {
        k: 7
    });
    test();
}


// 測試訓(xùn)練的模型
function test()
{
    const result = knn.predict(testSetX);
    const testSetLength = testSetX.length;
    const predictionError = error(result, testSetY);
    console.log(`Test Set Size = ${testSetLength} and number of Misclassifications = ${predictionError}`);
    predict();
}


// 計(jì)算出錯(cuò)個(gè)數(shù)
function error(predicted, expected)
{
    let misclassifications = 0;
    for (var index = 0; index < predicted.length; index++)
    {
        if (predicted[index] !== expected[index])
        {
            misclassifications++;
        }
    }
    return misclassifications;
}


// 根據(jù)輸入預(yù)測結(jié)果
function predict()
{
    let temp = [];
    prompt.start();
    prompt.get(["Sepal Length", "Sepal Width", "Petal Length", "Petal Width"], function(err, result)
    {
        if (!err)
        {
            for (var key in result)
            {
                temp.push(parseFloat(result[key]));
            }
            console.log(`With ${temp} -- type =  ${knn.predict(temp)}`);
        }
    });
}


// 混淆數(shù)據(jù)集的順序
function shuffleArray(array)
{
    for (var i = array.length - 1; i > 0; i--)
    {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}

在控制臺執(zhí)行node index.js

$ node index.js

輸出如下:

Test Set Size = 45 and number of Misclassifications = 2
prompt: Sepal Length:  1.7
prompt: Sepal Width:  2.5
prompt: Petal Length:  0.5
prompt: Petal Width:  3.4
With 1.7,2.5,0.5,3.4 -- type =  2
參考鏈接

K NEAREST NEIGHBOR 算法

安德森鳶尾花卉數(shù)據(jù)集

歡迎加入我們Fundebug的全棧BUG監(jiān)控交流群: 622902485

版權(quán)聲明:
轉(zhuǎn)載時(shí)請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/07/10/javascript-machine-learning-knn/

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/84018.html

相關(guān)文章

  • 機(jī)器學(xué)習(xí)之 K-近鄰算法

    摘要:近鄰算法通過測量不同特征值之間的距離方法進(jìn)行分類。對于近鄰算法來說,它是一個(gè)特殊的沒有模型的算法,但是我們將其訓(xùn)練數(shù)據(jù)集看作是模型。算法優(yōu)缺點(diǎn)近鄰算法是一個(gè)比較簡單的算法,有其優(yōu)點(diǎn)但也有缺點(diǎn)。 k-近鄰算法通過測量不同特征值之間的距離方法進(jìn)行分類。 k-近鄰算法原理 對于一個(gè)存在標(biāo)簽的訓(xùn)練樣本集,輸入沒有標(biāo)簽的新數(shù)據(jù)后,將新數(shù)據(jù)的每個(gè)特征與樣本集中數(shù)據(jù)對應(yīng)的特征進(jìn)行比較,根據(jù)算法選擇樣...

    Jensen 評論0 收藏0
  • 機(jī)器學(xué)習(xí)之多項(xiàng)式回歸與模型泛化

    摘要:還提供了,將多項(xiàng)式特征數(shù)據(jù)歸一化和線性回歸組合在了一起,大大方便的編程的過程。在機(jī)器學(xué)習(xí)算法中,主要的挑戰(zhàn)來自方差,解決的方法主要有降低模型復(fù)雜度降維增加樣本數(shù)使用驗(yàn)證集模型正則化。 多項(xiàng)式回歸 多項(xiàng)式回歸使用線性回歸的基本思路 非線性曲線如圖: showImg(https://segmentfault.com/img/bVbkn4q?w=372&h=252); 假設(shè)曲線表達(dá)式為:$y...

    huhud 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<