2010-03-09 55 views
1

我试图实现两组数据在php中的相关系数的计算。 我只是尝试这样做,可以在这个网址 http://answers.oreilly.com/topic/1066-how-to-find-similar-users-with-python/PHP中的Pearson相关性

我的执行中发现的移植python脚本如下:

class LB_Similarity_PearsonCorrelation implements LB_Similarity_Interface{ 
public function similarity($user1, $user2){ 

    $sharedItem = array(); 
    $pref1 = array(); 
    $pref2 = array(); 

    $result1 = $user1->fetchAllPreferences(); 
    $result2 = $user2->fetchAllPreferences(); 

    foreach($result1 as $pref){ 
     $pref1[$pref->item_id] = $pref->rate; 
    } 

    foreach($result2 as $pref){ 
     $pref2[$pref->item_id] = $pref->rate; 
    } 

    foreach ($pref1 as $item => $preferenza){ 
     if(key_exists($item,$pref2)){ 
      $sharedItem[$item] = 1; 
     } 
    } 

    $n = count($sharedItem); 
    if ($n == 0) return 0; 

    $sum1 = 0;$sum2 = 0;$sumSq1 = 0;$sumSq2 = 0;$pSum = 0; 

    foreach ($sharedItem as $item_id => $pre) { 
     $sum1 += $pref1[$item_id]; 
     $sum2 += $pref2[$item_id]; 

     $sumSq1 += pow($pref1[$item_id],2); 
     $sumSq2 += pow($pref2[$item_id],2); 

     $pSum += $pref1[$item_id] * $pref2[$item_id]; 
    } 

    $num = $pSum - (($sum1 * $sum2)/$n); 
    $den = sqrt(($sumSq1 - pow($sum1,2)/$n) * ($sumSq2 - pow($sum2,2)/$n)); 
    if ($den == 0) return 0; 
    return $num/$den; 

} 
} 

澄清,以更好地理解代码,该方法返回fetchAllPreferences回一组对象实际上是项目,将它们变成一个数组以便于管理

我不确定这个实现是否正确,特别是我对分母的计算的正确性有一些怀疑。

欢迎任何建议。

在此先感谢!

+0

你们是不是要写出这个公式? http://upload.wikimedia.org/math/2/2/d/22d8661430d51f01217a3426466aae8b.png – Anthony 2010-03-09 12:01:46

+0

是的。我也使用Excel来检查结果,看起来是正确的。 但我也想要一个双重检查。 – 2010-03-09 12:06:14

+0

是user1和user2的X和Y,还是有很多X和Ys(trig/calc从来就不是我的强项,但是搞清楚如何拍电脑来做数学是我喜​​欢的)。 – Anthony 2010-03-09 12:16:45

回答

4

您的算法看起来数学上正确但数值不稳定。明确找出正方形的总和是灾难的秘诀。如果你有像array(10000000001, 10000000002, 10000000003)这样的号码怎么办?用于计算方差的数值稳定的单程算法可以是found on Wikipedia,并且可以将相同的原理应用于计算协方差。

更简单一点,如果你不太在意速度,你可以使用两遍。在第一遍中找到平均值,然后在第二遍中使用教科书公式计算方差和协方差。

+0

我的算法从不处理这个大数字,速度不是关键点,因为这个计算是离线完成的。但我真的很喜欢你的答案,肯定会进入主题。谢谢! – 2010-03-10 13:45:33

1

这是我的解决方案:

function php_correlation($x,$y){ 
    if(count($x)!==count($y)){return -1;} 
    $x=array_values($x); 
    $y=array_values($y);  
    $xs=array_sum($x)/count($x); 
    $ys=array_sum($y)/count($y);  
    $a=0;$bx=0;$by=0; 
    for($i=0;$i<count($x);$i++){  
     $xr=$x[$i]-$xs; 
     $yr=$y[$i]-$ys;  
     $a+=$xr*$yr;   
     $bx+=pow($xr,2); 
     $by+=pow($yr,2); 
    } 
    $b = sqrt($bx*$by); 
    if($b==0) return 0; 
    return $a/$b; 
} 

http://profprog.ru/korrelyaciya-na-php-php-simple-pearson-correlation/