【问题标题】:Where can I find practical example of KNN in java using weka在哪里可以找到使用 weka 的 Java 中 KNN 的实际示例
【发布时间】:2020-01-04 10:28:56
【问题描述】:

我一直在寻找使用 weka 实现 KNN 的实际示例,但我发现的所有内容都太笼统了,无法理解它需要能够工作的数据(或者可能如何制作它需要的对象)工作)以及它显示的结果,也许以前使用过它的人有一个更好的例子,比如现实的事物(产品、电影、书籍等),而不是你在代数上看到的典型字母。

所以我可以弄清楚如何在我的案例中实施它(这是向使用 KNN 的活跃用户推荐菜肴),将不胜感激,谢谢。

我试图通过这个链接来理解https://www.ibm.com/developerworks/library/os-weka3/index.html,但我什至不明白他们是如何得到这个结果的,他们是如何得到公式的

第 1 步:确定距离公式

Distance = SQRT( ((58 - Age)/(69-35))^2) + ((51000 - Income)/(150000-38000))^2 )

为什么总是 /(69-35) 和 /(150000-38000) ?

编辑:

这是我尝试过但没有成功的代码,如果有人可以为我清除它,我很感激,我也通过结合这 2 个答案来完成此代码:

这个答案显示了如何获得 knn:

How to get the nearest neighbor in weka using java

这个告诉我如何创建实例(我真的不知道它们对 weka 是什么)Adding a new Instance in weka

所以我想出了这个:

public class Wekatest {

    public static void main(String[] args) {

        ArrayList<Attribute> atts = new ArrayList<>();
        ArrayList<String> classVal = new ArrayList<>();
        // I don't really understand whats happening here
        classVal.add("A");
        classVal.add("B");
        classVal.add("C");
        classVal.add("D");
        classVal.add("E");
        classVal.add("F");

        atts.add(new Attribute("content", (ArrayList<String>) null));
        atts.add(new Attribute("@@class@@", classVal));

        // Here in my case the data to evaluate are dishes (plato mean dish in spanish)
        Instances dataRaw = new Instances("TestInstancesPlatos", atts, 0);

        // I imagine that every instance is like an Object that will be compared with the other instances, to get its neaerest neightbours (so an instance is like a dish for me)..

        double[] instanceValue1 = new double[dataRaw.numAttributes()];

        instanceValue1[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue1[1] = 0;

        dataRaw.add(new DenseInstance(1.0, instanceValue1));

        double[] instanceValue2 = new double[dataRaw.numAttributes()];

        instanceValue2[0] = dataRaw.attribute(0).addStringValue("Tunas");
        instanceValue2[1] = 1;

        dataRaw.add(new DenseInstance(1.0, instanceValue2));

        double[] instanceValue3 = new double[dataRaw.numAttributes()];

        instanceValue3[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue3[1] = 2;

        dataRaw.add(new DenseInstance(1.0, instanceValue3));

        double[] instanceValue4 = new double[dataRaw.numAttributes()];

        instanceValue4[0] = dataRaw.attribute(0).addStringValue("Hamburguers");
        instanceValue4[1] = 3;

        dataRaw.add(new DenseInstance(1.0, instanceValue4));

        double[] instanceValue5 = new double[dataRaw.numAttributes()];

        instanceValue5[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue5[1] = 4;

        dataRaw.add(new DenseInstance(1.0, instanceValue5));

        System.out.println("---------------------");

        weka.core.neighboursearch.LinearNNSearch knn = new LinearNNSearch(dataRaw);
        try {

            // This method receives the goal instance which you wanna know its neighbours and N (I don't really know what N is but I imagine it is the number of neighbours I want)
            Instances nearestInstances = knn.kNearestNeighbours(dataRaw.get(0), 1);
            // I expected the output to be the closes neighbour to dataRaw.get(0) which would be Pizzas, but instead I got some data that I don't really understand.


            System.out.println(nearestInstances);

        } catch (Exception e) {

            e.printStackTrace();
        }

    }

}

OUTPUT:

---------------------
@relation TestInstancesPlatos

@attribute content string
@attribute @@class@@ {A,B,C,D,E,F}

@data
Pizzas,A
Tunas,B
Pizzas,C
Hamburguers,D

使用了weka依赖:

<dependency>
        <groupId>nz.ac.waikato.cms.weka</groupId>
        <artifactId>weka-stable</artifactId>
        <version>3.8.0</version>
    </dependency>

【问题讨论】:

  • 69 是最高年龄,35 是最小年龄,减法得到你的范围,这将 58(我们想要找到距离的观察)与其他观察的差异标准化,但缩放到下降在 0(相等)和 1(最大可能差异)之间。这是根据收入和年龄来完成的,收入的规模大不相同。
  • @RobinGertenbach 谢谢你的称赞!

标签: weka knn


【解决方案1】:

KNN 是一种机器学习技术,通常被归类为“基于实例的预测器”。它获取分类样本的所有实例,并将它们绘制在 n 维空间中。

使用欧几里得距离等算法,KNN 在这个 n 维空间中寻找最近的点,并根据这些邻居估计它属于哪个类。如果它更接近蓝点,它是蓝色的,如果它更接近红点......

但是现在,我们如何将其应用于您的问题?

假设您只有两个属性,价格和卡路里(二维空间)。您想将客户分为三类:健康、垃圾食品、美食。有了这个,您可以在餐厅提供与客户偏好相似的优惠。

您有以下数据:

+-------+----------+-----------+
| Price | Calories | Food Type |
+-------+----------+-----------+
| $2    |    350   | Junk Food |
+-------+----------+-----------+
| $5    |    700   | Junk Food |
+-------+----------+-----------+
| $10   |    200   | Fit       |
+-------+----------+-----------+
| $3    |    400   | Junk Food |
+-------+----------+-----------+
| $8    |    150   | Fit       |
+-------+----------+-----------+
| $7    |    650   | Junk Food |
+-------+----------+-----------+
| $5    |    120   | Fit       |
+-------+----------+-----------+
| $25   |    230   | Gourmet   |
+-------+----------+-----------+
| $12   |    210   | Fit       |
+-------+----------+-----------+
| $40   |    475   | Gourmet   |
+-------+----------+-----------+
| $37   |    600   | Gourmet   |
+-------+----------+-----------+

现在,让我们看看它是在 2D 空间中绘制的:

接下来会发生什么?

对于每个新条目,算法都会计算到所有点(实例)的距离并找到最近的 k 个点。从这 k 个最近的类中,它定义了新条目的类。

取 k = 3,价值 15 美元和 165 卡。让我们找到最近的 3 个邻居:

这就是距离公式的用武之地。它实际上对每个点进行这种计算。然后对这些距离进行“排序”,最接近的 k 个距离构成最终类。

现在,为什么值 /(69-35) 和 /(150000-38000)?正如其他答案中提到的,这是由于标准化。我们的示例使用 price 和 cal。正如所见,卡路里比金钱更重要(每个价值更多单位)。为了避免不平衡,例如可以使卡路里对课程更有价值而不是价格(例如,这会扼杀 Gourmet 课程),需要使所有属性同样重要,因此需要使用归一化。

Weka 为您抽象了这些,但您也可以将其可视化。查看我为 Weka ML 课程制作的项目中的可视化示例:

注意,由于多于2维,所以图很多,但思路大同小异。

解释代码:

public class Wekatest {

    public static void main(String[] args) {
//These two ArrayLists are the inputs of your algorithm.
//atts are the attributes that you're going to pass for training, usually called X.
//classVal is the target class that is to be predicted, usually called y.
        ArrayList<Attribute> atts = new ArrayList<>();
        ArrayList<String> classVal = new ArrayList<>();
//Here you initiate a "dictionary" of all distinct types of restaurants that can be targeted.
        classVal.add("A");
        classVal.add("B");
        classVal.add("C");
        classVal.add("D");
        classVal.add("E");
        classVal.add("F");
// The next two lines initiate the attributes, one made of "content" and other pertaining to the class of the already labeled values.
        atts.add(new Attribute("content", (ArrayList<String>) null));
        atts.add(new Attribute("@@class@@", classVal));

//This loads a Weka object of data for training, using attributes and classes from a file "TestInstancePlatos" (or should happen).
//dataRaw contains a set of previously labelled instances that are going to be used do "train the model" (kNN actually doesn't tain anything, but uses all data for predictions)
        Instances dataRaw = new Instances("TestInstancesPlatos", atts, 0);


//Here you're starting new instances to test your model. This is where you can substitute for new inputs for production.
        double[] instanceValue1 = new double[dataRaw.numAttributes()];

//It looks you only have 2 attributes, a food product and a rating maybe.
        instanceValue1[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue1[1] = 0;

//You're appending this new instance to the model for evaluation.
        dataRaw.add(new DenseInstance(1.0, instanceValue1));

        double[] instanceValue2 = new double[dataRaw.numAttributes()];

        instanceValue2[0] = dataRaw.attribute(0).addStringValue("Tunas");
        instanceValue2[1] = 1;

        dataRaw.add(new DenseInstance(1.0, instanceValue2));

        double[] instanceValue3 = new double[dataRaw.numAttributes()];

        instanceValue3[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue3[1] = 2;

        dataRaw.add(new DenseInstance(1.0, instanceValue3));

        double[] instanceValue4 = new double[dataRaw.numAttributes()];

        instanceValue4[0] = dataRaw.attribute(0).addStringValue("Hamburguers");
        instanceValue4[1] = 3;

        dataRaw.add(new DenseInstance(1.0, instanceValue4));

        double[] instanceValue5 = new double[dataRaw.numAttributes()];

        instanceValue5[0] = dataRaw.attribute(0).addStringValue("Pizzas");
        instanceValue5[1] = 4;

        dataRaw.add(new DenseInstance(1.0, instanceValue5));

// After adding 5 instances, time to test:
        System.out.println("---------------------");

//Load the algorithm with data.
        weka.core.neighboursearch.LinearNNSearch knn = new LinearNNSearch(dataRaw);
//You're predicting the class of value 0 of your data raw values. You're asking the answer among 1 neighbor (second attribute)
        try {
            Instances nearestInstances = knn.kNearestNeighbours(dataRaw.get(0), 1);
//You will get a value among A and F, that are the classes passed.
           System.out.println(nearestInstances);

        } catch (Exception e) {

            e.printStackTrace();
        }

    }

}

你应该怎么做?

-> Gather data. 
-> Define a set of attributes that help you to predict which cousine you have (ex.: prices, dishes or ingredients (have one attribute for each dish or ingredient). 
-> Organize this data. 
-> Define a set of labels.
-> Manually label a set of data.
-> Load labelled data to KNN.
-> Label new instances by passing their attributes to KNN. It'll return you the label of the k nearest neighbors (good values for k are 3 or 5, have to test).
-> Have fun!

【讨论】:

  • 嘿,非常感谢你的解释,现在对我来说更清楚了,至少算法的工作方式,如果你也可以在你的答案中添加一些小代码并解释它,那就是黄金有价值的答案,我在我的问题中添加了我尝试过的代码,但我真的不明白它是如何工作的,如果你清楚我很感激,你是我迄今为止赏金的赢家:)
  • 我目前无法查看您提供给我的链接,但我会尽快查看
  • 这个“比萨”、“金枪鱼”等,是不是像餐馆里卖的产品?
  • 对于聚类,检查 K-means 算法。如果你想使用 KNN,你必须先定义一组“客户群”。
  • 是的,你可以做到。关于分类变量,您应该拥有每个类别的“列”,并且有一个布尔值来表示存在与否。如果您有大量未标记的数据,您可以使用聚类来查找聚类(将成为您的客户组),将它们设置为类,然后使用 KNN 为新用户提供建议。检查集群,它简单易用。
【解决方案2】:

它相当简单。 为了理解为什么总是 /(69-35) 和 /(150000-38000),首先需要了解 Normalization 的含义。

标准化
标准化通常意味着将变量缩放到 0 到 1 之间的值。
公式如下:

如果你仔细观察上面公式的分母,你会发现它是所有数字的最小值减去所有数字的最大值。

现在,回到你的问题...看看问题的第 5 行。它说如下。

最简单和最常见的距离计算是“归一化 欧几里得距离。”

在您的年龄列中,您可以看到最小值为 35,最大值为 69。类似地,在您的收入列中,您的最小值为 38k,最大值为 150k。

这就是您始终拥有 /(69-35) 和 /(150000-38000) 的确切原因。

希望你能理解。

和平

【讨论】:

  • 我现在明白了很多,如果你也可以添加代码示例,我很感激
  • 嘿@BugsForBreakfast,我不知道使用weka...但我可以用python代码解释你...你可以吗..?
  • 是的,我也了解 Python,也许我可以理解它在 python 中的工作原理并在 java 中实现,一切都会有所帮助
猜你喜欢
  • 1970-01-01
  • 2010-10-12
  • 2020-02-21
  • 2013-02-25
  • 2011-12-31
  • 1970-01-01
  • 2012-02-14
  • 2012-09-17
  • 1970-01-01
相关资源
最近更新 更多