JavaScript 模式比较

Posted

技术标签:

【中文标题】JavaScript 模式比较【英文标题】:JavaScript Pattern Comparison 【发布时间】:2017-11-26 02:40:44 【问题描述】:

我正在研究一个使用 nodeJs 的小型机器学习理论算法。 我的目标是将许多数组模式与一个源模式进行比较,然后返回如何 类似,它们以百分比表示。例如,pattern1 可能与源模式 80% 相似。

确定一个数组与另一个数组的相似度百分比的最佳方法是什么?

到目前为止我做了什么..

//source   
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]

//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]

由于我选择了基于百分比的结果,我认为我的源模式应该基于数组中从第一个值到第二个值的百分比变化。

 var percentChange = (firstVal, secondVal) => 
        var pChange = ((parseFloat(secondVal) - firstVal) / 
         Math.abs(firstVal)) * 100.00;

        //To avoid NaN , Infinity , and Zero

        if(!pChange || pChange == 0)
            return 0.00000001
        
        return pChange;
    

在这里,我将从我的源序列生成我的源模式

       var storePattern = function(sequence)
           var pattern = [];
           for(var i = 0 ; i < sequence.length ; i++)
               let $change = percentChange(sequence[i] , sequence[i + 1]);
               if(i != sequence.length && $change )
                    pattern.push($change)
                
            
    return pattern;
     



   var sourcePattern = storePattern(soureSequence);

现在我将创建更多模式进行比较

   var testPattern1 = storePattern(sequence1);
   var testPattern2 = storePattern(sequence2);

下面是我的比较函数

 var processPattern = function(source , target)
    var simularityArray = [];

    for(var i = 0 ; i < target.length ; i++)
        //Compare percent change at indexof testPattern to sourcePattern of same index
        let change = Math.abs(percentChange(target[i] , source[i]));
        simularityArray.push(100.00 - change);
    

    var rating = simularityArray.reduce((a,b) => 
        return a + b
    );

    //returns percent rating based of average of similarity pattern

    rating = rating / parseFloat(source.length + ".00");
    return rating;

现在我可以尝试估计相似度

var similarityOfTest1 = processPattern(sourcePattern , testPattern1)

我的问题是 这只适用于相同范围内的序列 值.. 例如 0.50 , 0.52 .. 这些值的百分比变化不会0.20 , 0.22 相同,但值差异相同,即 -> 0.02

我想过一个基于价值的差异模式,但现在我迷路了。

将考虑所有答案。感谢您的帮助!

【问题讨论】:

所以你试图找出两个数组之间的差异以产生一个百分比?还是您的意思是各个数组值之间的差异? IMO 两个数组“不同”的规则完全取决于为什么这种差异很重要,或者您使用它的目的。本质上,processPattern 是一个fitness function,您应该相应地注意其设计的注意事项。 @Arrow 我的理论是,各个数组值之间的差异最终将决定每个模式与源模式的相似程度的总体百分比。 @James 差异很重要,因为它是迄今为止尝试在每种模式之间找到相似特征的唯一方法......而不是百分比或价值的差异。 余弦相似度如何作为相似度度量? en.wikipedia.org/wiki/Cosine_similarity 【参考方案1】:

使用reduce来获得与平均值的差异。

//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]

function diff(sequence)
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]
   var delta = soureSequence.reduce(function (r, a, i, aa) 
        i && r.push(a - sequence[i]);
        return r;
    , []),
    average = delta.reduce(function (a, b)  return a + b; ) / delta.length;
    
    return delta:delta, average:average

console.log('sequence1',diff(sequence1));
console.log('sequence2',diff(sequence2));

【讨论】:

【参考方案2】:

根据我的经验,两个向量(数组)的相似性是使用点积 ex 来衡量的。就像它在该链接中所说的那样,您将数组的每个相应元素相乘,将它们相加,然后除以每个数组的大小(每个组件的平方和的平方根)。 Rosetta Code 有一个dot product in javascript 的示例,复制到这里

// dotProduct :: [Int] -> [Int] -> Int
const dotProduct = (xs, ys) => 
    const sum = xs => xs ? xs.reduce((a, b) => a + b, 0) : undefined;

    return xs.length === ys.length ? (
        sum(zipWith((a, b) => a * b, xs, ys))
    ) : undefined;


// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => 
    const ny = ys.length;
    return (xs.length <= ny ? xs : xs.slice(0, ny))
        .map((x, i) => f(x, ys[i]));

所以,你会打电话

const score1 = dotProduct(sourceSequence, sequence1);
const score2 = dotProduct(sourceSequence, sequence2);

并且哪个更大是更接近 sourceSequence 的序列。

【讨论】:

我认为这接近我想要实现的目标。使用这种方法,假设我有 100 个测试模式用于测试我如何按顺序对它们进行排名,排名比例是多少?例如,我原来的方法会产生一个百分比分数。 点积计算两个向量并返回一个介于 0 和 1 之间的数字,包括 0 和 1。 1是最大相似度,0是最小相似度。因此,如果需要,您可以乘以 100 以获得百分比分数。注意,1 并不意味着它们是完全相同的向量。如果sequence2和sequence1类似,但每个元素乘以相同的常数,它们的点积为1【参考方案3】:

我不确定您是否需要为此使用机器学习。你有一个源模式,你有一些输入,你基本上想要执行模式的差异。

机器学习可用于查找模式,假设您有一些用于测量错误的启发式方法(如果您使用无监督学习技术)或者您有样本集来训练网络。

但是,如果您只是想测量一种模式和另一种模式之间的差异,那么只需执行 diff 操作。您需要做的是确定测量的差异以及如何标准化结果。

【讨论】:

【参考方案4】:

我不知道您希望如何准确地衡量相似度。我通过计算相应项目的差异并累积这些差异来查看源数组的总和会产生多少偏差。您可以按照自己喜欢的方式进行计算。

function check([x,...xs],[y,...ys], state = sumSource: 0, sumDiff: 0)
  state.sumSource += x;
  state.sumDiff += Math.abs(x-y);
  return xs.length ? check(xs,ys,state) : (100 - 100 * state.sumDiff / state.sumSource).toFixed(4) + "% similarity";


var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60],
    sequence1     = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60],
    sequence2     = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62];

console.log(check(soureSequence,sequence1));
console.log(check(soureSequence,sequence2));

【讨论】:

以上是关于JavaScript 模式比较的主要内容,如果未能解决你的问题,请参考以下文章

javascript 写状态模式

从ES6重新认识JavaScript设计模式: 单例模式

JavaScript设计模式

JavaScript中的设计模式:状态模式

常用的javascript设计模式

细品 javascript 设计模式(策略模式)