数据集 Node.js 中的最近邻

Posted

技术标签:

【中文标题】数据集 Node.js 中的最近邻【英文标题】:nearest neighbour in dataset Node.js 【发布时间】:2012-12-28 22:41:24 【问题描述】:

我有一个将数据保存到 MongoDB 的 Node.js 应用程序。 给定一个文档,我想在数据库中找到最相似的文档。

我的想法是实现某种最近邻算法,将所有记录作为训练序列并返回最相似的文档(包括关于这两个文档的相似程度的某种百分比。)

例如在我的数据库中有这些记录...

 name: "Bill",   age: 10,  pc: "Mac",      ip: "68.23.13.8" 
 name: "Alice",  age: 22,  pc: "Windows",  ip: "193.186.11.3" 
 name: "Bob",    age: 12,  pc: "Windows",  ip: "56.89.22.1" 

...我想找到最接近这个的文档

 name: "Tom", age: 10, pc: "Mac", ip: "68.23.13.10" 
// algorithm returns "Bill", .76 

是否有任何 Node 模块/实现采用任何类型的对象/参数并返回其最近的邻居?

【问题讨论】:

你有多少条记录?它们经常更新吗? 我希望有很多 (>5000) 条记录。保存后,它们不会更新,但新记录可能随时到达。 这不是通常作为独立模块实现的东西。这更像是一个算法的事情。更多的是一种艺术。每个人都有不同的需求。解决方案往往是高度定制的。通常,人们使用框架(和大量知识)来构建他们的解决方案。可能最简单的方法是(如果您有资源)使用 Solr 来索引您的数据。然后使用 MoreLikeThis 组件查询:wiki.apache.org/solr/MoreLikeThis 在概念层面上,这个问题有两个因素。一个相似度函数,它接受 2 个文档并返回一个表示它们相似程度的数字。以及重新索引整个集合的频率和数量的策略(提示,每次添加新文档时比较所有对可能不切实际,这是二次时间!) 【参考方案1】:

这样做的一个直接方法是计算两个文档之间的差异,差异越大,距离越大。您可以使用最大可能的差异对差异进行归一化,这应该为您提供可以相互比较的相对距离。

看看这个问题,计算 json 文档的差异。

Delta encoding for JSON objects

【讨论】:

如果 ip 仅从 68.23.13.8 更改为 68.23.13.10(即属性的非常小的变化),这是否也会考虑在内?你手头有代码吗? 这将完全取决于差异算法。我发布的问题中的大多数算法只是检查任何字符串更改,而不是区分单个字符串。【参考方案2】:

这是一些示例代码。它假定您可以对每个请求运行搜索。如果要修改它,请确保所有相似度函数都返回一个介于 0 和 1 之间的数字。

function tokenize(string) 
  var tokens = [];
  for (var i = 0; i < string.length-1; i++) 
    tokens.push(string.substr(i,2));
  

  return tokens.sort();


function intersect(a, b)

  var ai=0, bi=0;
  var result = new Array();

  while( ai < a.length && bi < b.length )
  
     if      (a[ai] < b[bi] ) ai++; 
     else if (a[ai] > b[bi] ) bi++; 
     else /* they're equal */
     
       result.push(a[ai]);
       ai++;
       bi++;
     
  

  return result;


function sum(items) 
  var sum = 0;
  for (var i = 0; i < items.length; i++) 
    sum += items[i];
  

  return sum;


function wordSimilarity(a, b) 
  var left   = tokenize(a);
  var right  = tokenize(b);
  var middle = intersect(left, right);

  return (2*middle.length) / (left.length + right.length);


function ipSimilarity(a, b) 
  var left  = a.split('.');
  var right = b.split('.');

  var diffs = [];
  for (var i = 0; i < 4; i++) 
    var diff1 = 255-left[i];
    var diff2 = 255-right[i];
    var diff  = Math.abs(diff2-diff1);

    diffs[i] = diff;
  

  var distance = sum(diffs)/(255*4);

  return 1 - distance;


function ageSimilarity(a, b) 
  var maxAge   = 100;
  var diff1    = maxAge-a;
  var diff2    = maxAge-b;
  var diff     = Math.abs(diff2-diff1);
  var distance = diff / maxAge;

  return 1-distance;


function recordSimilarity(a, b) 
  var fields = [
    name:'name', measure:wordSimilarity,
    name:'age',  measure:ageSimilarity,
    name:'pc',   measure:wordSimilarity,
    name:'ip',   measure:ipSimilarity
  ];

  var sum = 0;
  for (var i = 0; i < fields.length; i++) 
    var field   = fields[i];
    var name    = field.name;
    var measure = field.measure;
    var sim     = measure(a[name], b[name]);

    sum += sim;
  

  return sum / fields.length;


function findMostSimilar(items, query) 
  var maxSim = 0;
  var result = null;

  for (var i = 0; i < items.length; i++) 
    var item = items[i];
    var sim  = recordSimilarity(item, query);

    if (sim > maxSim) 
      maxSim = sim;
      result = item;
    
  

  return result


var items = [
   name: "Bill",   age: 10,  pc: "Mac",      ip: "68.23.13.8" ,
   name: "Alice",  age: 22,  pc: "Windows",  ip: "193.186.11.3" ,
   name: "Bob",    age: 12,  pc: "Windows",  ip: "56.89.22.1" 
];

var query  =  name: "Tom", age: 10, pc: "Mac", ip: "68.23.13.10" ;
var result = findMostSimilar(items, query);

console.log(result);

【讨论】:

这就像一个魅力。但是我在ipSimilarity() 上遇到了 TypeError。我通过重命名sum() 方法解决了这个问题。谢谢。

以上是关于数据集 Node.js 中的最近邻的主要内容,如果未能解决你的问题,请参考以下文章

高维数据中的最近邻?

给定距离矩阵的 Python 中的最近邻

使用Node.js如何实现K最近邻分类算法?

为集合 A 中的所有点查找集合 B 中的最近邻的算法

k-d树的最近邻搜索算法

R语言如何实现K最近邻算法?