皮尔逊相关性与余弦相似度

皮尔逊相关性是什么

皮尔逊是一种相关性度量方法,主要依靠计算得出的皮尔逊相关系数度量。
皮尔逊相关系数输出范围为-1到+1,0代表无相关性,负值为负相关,正值为正相关。

几何上来讲,皮尔逊相关系数是余弦相似度在维度值缺失情况下的一种改进。
皮尔逊系数就是在使用cos计算两个向量(cos = a • b / |a|•|b|)时进行中心化。

余弦相似度(余弦距离)

计算的是两个向量在空间中的夹角大小, 值域为[-1, 1]: 1代表夹角为0°, 完全重叠/完全相似; -1代表夹角为180°, 完全相反方向/毫不相似.
余弦相似度的问题是: 其计算严格要求"两个向量必须所有维度上都有数值", 比如:v1 = (1, 2, 4), v2=(3, -1, null), 那么这两个向量由于v2中第三个维度有null, 无法进行计算.然而, 实际我们做数据挖掘的过程中, 向量在某个维度的值常常是缺失的, 比如v2=(3, -1, null), v2数据采集或者保存中缺少一个维度的信息, 只有两个维度. 那么, 我们一个很朴素的想法就是, 我们在这个地方填充一个值, 不就满足了"两个向量必须所有维度上都有数值"的严格要求了吗? 填充值的时候, 我们一般这个向量已有数据的平均值, 所以v2填充后变成v2=(3, -1, 1), 接下来我们就可以计算cos了.

中心化是什么

而皮尔逊相关系数的思路是, 我把这些null的维度都填上0, 然后让所有其他维度减去这个向量各维度的平均值, 这样的操作叫作中心化.
中心化的意思是说, 对每个向量, 我先计算所有元素的平均值avg, 然后向量中每个维度的值都减去这个avg, 得到的这个向量叫做被中心化的向量.
机器学习, 数据挖掘要计算向量余弦相似度的时候, 由于向量经常在某个维度上有数据的缺失, 预处理阶段都要对所有维度的数值进行中心化处理.

皮尔逊系数公式

皮尔逊相关系数计算公式
观察以上皮尔逊系数的公式:

分子部分: 每个向量的每个数字要先减掉向量各个数字的平均值, 这就是在中心化.

分母部分: 两个根号式子就是在做取模运算, 里面的所有的 r 也要减掉平均值, 其实也就是在做中心化.

结论

皮尔逊相关系数是余弦相似度在维度值缺失情况下的一种改进.

一些其它定义

欧氏距离

欧式距离,即欧几里得距离,是最常见的两点之间的距离表示法,它定义在欧几里得空间中,例如x = (x1,x2,…,xn)和y = (y1,y2,…,yn)的欧式距离可表示为:

在这里插入图片描述

协方差

协方差是一个反映两个随机变量相关程度的指标,如果一个变量跟随着另一个变量同时变大或者变小,那么这两个变量的协方差就是正值,反之相反。
在这里插入图片描述
虽然协方差能反映两个随机变量的相关程度(协方差大于0的时候表示两者正相关,小于0的时候表示两者负相关),但是协方差值的大小并不能很好地度量两个随机变量的关联程度,例如,现在二维空间中分布着一些数据,我们想知道数据点坐标X轴和Y轴的相关程度,如果X与Y的相关程度较小但是数据分布的比较离散,这样会导致求出的协方差值较大,用这个值来度量相关程度是不合理的。
皮尔逊相关性与余弦相似度_第1张图片
Pearson相关系数是用协方差除以两个变量的标准差得到的。为了更好的度量两个随机变量的相关程度,引入了Pearson相关系数,其在协方差的基础上除以了两个随机变量的标准差,容易得出,pearson是一个介于-1和1之间的值,当两个变量的线性关系增强时,相关系数趋于1或-1;当一个变量增大,另一个变量也增大时,表明它们之间是正相关的,相关系数大于0;如果一个变量增大,另一个变量却减小,表明它们之间是负相关的,相关系数小于0;如果相关系数等于0,表明它们之间不存在线性相关关系

皮尔逊代码实现

#手动实现pearson

import math
import numpy as np

#获取两个向量平均值
def calcMean(x,y):
   sum_x=0
   sum_y=0

   for i in x.flat:
      sum_x+=i
   for i in y.flat:
      sum_y+=i

   n=len(x)

   x_mean = float(sum_x+0.0)/n
   y_mean = float(sum_y+0.0)/n


   return  x_mean,y_mean

#求两个向量的pearson系数
def calcPearson9(x,y):
   x_mean,y_mean = calcMean(x,y)
   n = len(x)
   sumTop = 0.0
   sumBottom = 0.0
   x_pow = 0.0
   y_pow = 0.0

   for i in range(n):
      sumTop +=(x[i]-x_mean)*(y[i]-y_mean)
   for i in range(n):
      x_pow += pow(x[i]-x_mean,2)
   for i in range(n):
      y_pow += pow(y[i]-y_mean,2)
   sumBottom = math.sqrt(x_pow *y_pow)
   p = sumTop / sumBottom
   return p

if __name__ == '__main__':
   x1 = np.random.random_integers(0, 10, (100, 1))
   x2 = np.random.random_integers(0, 10, (100, 1))

   p=calcPearson9(x1,x2)
   print(p)

pearsonr(x,y):
1)输入:x为特征,y为目标变量.
2)输出:r: 相关系数 [-1,1]之间,p-value: p值。
注: p值越小,表示相关系数越显著,一般p值在500个样本以上时有较高的可靠性。

import numpy as np
from scipy.stats import pearsonr


#设定向量长度
l=100
#生成闭区间[0,10]上离散均匀分布的整数值,(a,b)为a行b列
#生成三个向量
x1=np.random.random_integers(0,10,l)
x2=np.random.random_integers(0,10,l)


p12 = pearsonr(x1,x2)
print(p12)

余弦相似度代码实现

import  jieba
import  numpy as np
import re

def get_word(s1,s2):
   #s1为句子1 s2为句子2 返回余弦相似度
   #分词
   cut1 = jieba.cut(s1)
   cut2 = jieba.cut(s2)

   #split可以把字符串转为列表
   list_word1 = (','.join(cut1)).split(',')
   list_word2 = (','.join(cut2)).split(',')

   #set构造一个集合,且不重复,可以据此找出两句中重合的词汇
   key_word = list(set(list_word1+list_word2))

   #构造两个词频矩阵
   word_vector1 = np.zeros(len(key_word))
   word_vector2 = np.zeros(len(key_word))

   #计算词频
   for i in range(len(key_word)):
      for j in range(len(list_word1)):
         if key_word[i] == list_word1[j]:
            word_vector1[i]+=1
      for k in range(len(list_word2)):
         if key_word[i] == list_word2[k]:
            word_vector2[i]+=1
   #输出分别的词频向量
   return word_vector1,word_vector2

def cos(vec1,vec2):
   #dot为矩阵乘法
   #linalg.norm()为求范数
   dist = float(np.dot(vec1,vec2)/(np.linalg.norm(vec1) * np.linalg.norm(vec2)))
   return dist




if __name__ == '__main__':
    s1 = "很高兴见到你"
    s2 = '我也很高兴见到你'

    vec1,vec2 = get_word(s1,s2)

    dist = cos(vec1,vec2)
    print(dist)

你可能感兴趣的:(python数据分析)