数据挖掘_实验二 数据预处理常用方法与应用


实验二 数据预处理常用方法与应用

【实验目的】

1 掌握随机抽样的常用方法。

2 掌握变量规范化的常用方法。

3 掌握常见距离的定义及计算方法。

4 掌握二元变量相似度、连续变量余弦相似度计算方法。

5 掌握Mahalanobis距离的计算方法。

【实验类型】

设计型

【实验学时】

2学时

【实验环境】

                Windows 7以上操作系统

                Python3.0以上版本

                Pycharm开发环境

                Spyder开发环境

【实验要求】

一、请随机生成1000个二维数据点,从中分别随机抽取约75%,50%,25%的数据点,并绘图展示抽取数据点的情况。

参考输出结果:

0pDRLd.png

code:

import matplotlib.pyplot as plt
import random as rd

x = [rd.gauss(0, 1) for i in range(1000)]
y = [rd.gauss(0, 1) for i in range(1000)]


def f(x, y, p):
    xx = []
    yy = []
    for j in range(1000):
        if rd.random() >= p:
            xx.append(x[j])
            yy.append(y[j])
    return xx, yy


def paint(xx, yy, str_1, str_2):
    plt.subplot(str_1)
    plt.title(str_2+str(len(xx)))
    plt.scatter(xx, yy, s=[0.5])


x1, y1 = f(x, y, 0.25)
x2, y2 = f(x, y, 0.5)
x3, y3 = f(x, y, 0.75)
paint(x, y, 221, "all--")
paint(x1, y1, 222, "75%--")
paint(x2, y2, 223, "50%--")
paint(x3, y3, 224, "25%--")
plt.show()

二、请计算生成正弦函数序列和余弦函数序列,并绘图展示。将正弦序列和余弦序列添加随机偏差(噪音)后再次绘图,观察噪音对数据的影响。

参考输出结果:

0pD2sH.png

code:

from math import *
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-6*pi, 6*pi, 0.1)
y = np.sin(x)
z = np.cos(x)

y1 = y+np.random.randn(len(y))
z1 = y+np.random.randn(len(z))


def paint(xx, yy, zz, str_1):
    plt.subplot(str_1)
    plt.plot(xx, yy)
    plt.plot(xx, zz)


paint(x, y, z, 211)
paint(x, y1, z1, 212)
plt.show()

三、验证几类变量变换的效果,包括:指数变换、> 1幂变换、对数变换、(0,1)幂变换、< 0幂变换、正弦变换,绘图演示各类变换的效果。

参考输出结果:

 

0pDgQe.png

code:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(1, 50, 100)
y1 = np.exp(x)
y2 = x**3
y3 = np.log10(x)
y4 = np.sqrt(x)
y5 = 1/x
y6 = np.sin(x)


def paint(x, y, str_1, str_2):
    plt.subplot(str_2)
    plt.title(r"{}".format(str_1))
    plt.plot(x, y)


paint(x, y1, "$y=e^x$", 231)
paint(x, y2, "$y=x^3$", 232)
paint(x, y3, "$y=log_{10}x$", 233)
paint(x, y4, "$y=\sqrt{x}$", 234)
paint(x, y5, '$y=\\frac{1}{x}$', 235)
paint(x, y6, "$y=sin(x)$", 236)

plt.show()
""" 
输出函数式参考: https://stackoverflow.com/questions/4028267/how-to-render-latex-markup-using-python/58496145#58496145
"""

四、为了提出变量量纲对数据分析的影响,经常需要对变量进行一定的变换,其中常用的一种是标准化(normalization)变换(即将数据序列转换为期望值为0和方差为1的序列),转换公式为:

其中

为序列的均值,

为序列的样本标准差,即

  • (这儿借用了谷歌的api需要科学网络才能显示这四个公式)

请随机生成一个序列,并生成它的标准化序列,将两个序列通过绘图展示出来。

参考输出结果(其中随机生成的序列为期望值1000,标准差200,长度1000的正态分布序列):

 

0pD6zD.png

code:

from math import *
import matplotlib.pyplot as plt
import numpy as np
y1 = np.random.normal(1000, 200, 1000)

sd = sqrt(sum((y1-np.average(y1))**2))/(len(y1)-1)
y2 = (y1-np.average(y1))/sd

print(np.mean(y2), np.std(y2))

plt.subplot(211)
plt.plot(y1)
plt.subplot(212)
plt.plot(y2)
plt.show()

五、距离计算

向量间的闵可夫斯基距离的定义如下:

0pDyRO.png

其中当r=1时成为街区距离,为不同分量差绝对值的和

当r=2时即为欧几里得距离

当r=+infinity时,等于所有分量差绝对值中最大的一个

编写函数实现三种距离的计算,并对下面4个二维向量分别计算其三种距离定义的距离矩阵。

0pDhdI.png

参考输出结果如下:

0pDfeA.png

code:

import math
import re

infinity = float("inf")


def d(point1, point2, r):
    global infinity
    sum = 0.0
    if r != infinity:
        for i in range(len(point1)):
            sum += (abs(point1[i]-point2[i])**r)
        sum **= (1/r)
    else:
        for i in range(len(point1)):
            xyabs_ = abs(point1[i]-point2[i])
            sum = sum if sum > xyabs_ else xyabs_
    return sum


def ma(list_1, r):
    list_2 = []
    for i in list_1:
        list_3 = []
        for j in list_1:
            list_3.append(d(i, j, r))
        list_2.append(list_3)
    return list_2


def out(list_):
    for i in list_:
        for j in i:
            print("{}\t".format(j), end="")
        print()
    print()


list1 = [[0, 2], [2, 0], [3, 1], [5, 1]]
print("Data Matrix:")
out(list1)
print("City Block Distance:")
out(ma(list1, 1))
print("Euclid Distance:")
out(ma(list1, 2))
print("Distance with Element Max Difference:")
out(ma(list1, infinity))

"""
题目中的距离公式不是太容易理解,下面的文档有一些不错的解释
闵可夫斯基距离详解:https://wenku.baidu.com/view/35296aa3ec630b1c59eef8c75fbfc77da3699700.html
"""

""" 
尝试了一下参考图中的那种输出,没有成功;
此代码的输出:
Data Matrix:
0       2
2       0
3       1
5       1

City Block Distance:
0.0     4.0     4.0     6.0
4.0     0.0     2.0     4.0
4.0     2.0     0.0     2.0
6.0     4.0     2.0     0.0

Euclid Distance:
0.0     2.8284271247461903      3.1622776601683795      5.0990195135927845 

2.8284271247461903      0.0     1.4142135623730951      3.1622776601683795 

3.1622776601683795      1.4142135623730951      0.0     2.0
5.0990195135927845      3.1622776601683795      2.0     0.0

Distance with Element Max Difference:
0       2       3       5
2       0       1       3
3       1       0       2
5       3       2       0

"""

六、二元变量的相似度衡量可以使用简单匹配系数(SMC)或Jaccard系数

设x和y是两个对象,都由n个二元属性组成,这样两个对象可生成如下四个量(频率):

0pD4ot.png

简单匹配系数(Simple Matching Coefficient, SMC)定义为:

0pDTW8.png

Jaccard系数(Jaccard Coefficient)的定义为:

0pDIFP.png

编写两个函数分别实现连个系数的计算,并生成两个随机序列调用函数计算。

参考输出结果:

0pDoJf.png

code

import numpy as np


def fun_count(a, b):
    count00 = 0
    count11 = 0
    count10 = 0
    count01 = 0
    for i in range(0, len(a)):
        if a[i] == 0:
            if a[i] == b[i]:
                count00 += 1
            else:
                count01 += 1
        else:
            """ a[i]==1 """
            if a[i] == b[i]:
                count11 += 1
            else:
                count10 += 1
    return count00, count01, count10, count11


def fun_SCM(a, b):
    f00, f01, f10, f11 = fun_count(a, b)
    SCM = ((f11+f00)*1.0)/(f00+f01+f10+f11)
    return SCM


def fun_J(a, b):
    f00, f01, f10, f11 = fun_count(a, b)
    J = (f11*1.0)/(f01+f10+f11)
    return J


a = np.random.randint(0, 2, 100)
b = np.random.randint(0, 2, 100)

print("Vector a is:")
print(a)

print("Vector b is:")
print(b)

print("SCM coefficient:")
print(fun_SCM(a, b))
print("Jaccard coefficient")
print(fun_J(a, b))

七、余弦相似度是衡量数值向量相似度的一种方法,设x和y是两个n元向量,则余弦相似度定义为

0pDHSS.png

0pDbQg.png

 

编写函数实现余弦相似度的计算,并调用函数计算下面两个向量的余弦相似度。

参考输出结果:

 

0pDqyQ.png

code


def fun_xy(a, b):
    sum = 0.0
    for i in range(len(a)):
        sum += (a[i]*b[i])
    return sum


def fun_len(x):
    sum = 0.0
    for i in x:
        sum += i**2
    return sum**(1/2)


def fun_cosxy(x, y):
    return (fun_xy(x, y)*1.0)/(fun_len(x)*fun_len(y))


x = (3, 2, 0, 5, 0, 0, 0, 2, 0, 0)
y = (1, 0, 0, 0, 0, 0, 0, 1, 0, 2)

print("Vetor Angle Consine:{}".format(fun_cosxy(x, y)))

八、从统计学的观点看,计算多维向量的距离时,应该使用mahalanobis距离,其定义为:

0pDLLj.png

属性间协方差的定义如下所示:

0pDjwn.png

0pDzF0.png

实现欧几里得距离、使用方差逆矩阵调整的距离、使用协方差逆矩阵调整的距离三类距离的计算函数,并构造两个随机向量验证三种距离的不同。

参考输出结果:

0pDvoq.png

code

from math import *
import re
import numpy as np


# 计算两个矩阵的乘积
# numpy的对应函数 np.linalg.dot(X,Y)
def i_matrix_mul(X, Y):
    rrow = np.size(X, axis=0)
    rcol = np.size(Y, axis=1)
    rmid = np.size(X, axis=1)
    rel = np.linspace(0.0, 0.0, rrow*rcol).reshape(rrow, rcol)
    for r in range(rrow):
        for c in range(rcol):
            rel[r, c] = 0.0
            for mid in range(rmid):
                rel[r, c] += X[r, mid] * Y[mid, c]
    return rel


# 计算期望值(均值),对应np.average
def i_mean(x):
    return sum(x)/len(x)


# 计算样本方差
# 注意,numpy.var计算的是总体的,使用时需要调整
def i_var(x):
    x_mean = i_mean(x)
    return sum((x-x_mean)**2)/(len(x)-1)


# 计算样本标准差
# 注意,numpy.std计算的是总体的,使用时需要调整
def i_std(x):
    x_mean = i_mean(x)
    return sqrt(i_var(x))


# 序列标准化
def i_norm_vec(x):
    x_mean = i_mean(x)
    x_std = i_std(x)
    return (x-x_mean)/x_std


# 计算两个向量的协方差
# numpy的对应方法 np.cov(x,y),但是返回协方差矩阵
def i_cov(x, y):
    x_av = np.average(x)
    y_av = np.average(y)
    return sum((x-x_av)*(y-y_av))/(len(x)-1)


# 计算一个numpy矩阵的协方差(每行是一个变量)
# numpy的对应方法 np.cov(X)
def i_cov_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        for j in range(i, vc):
            cm[j, i] = cm[i, j] = i_cov(X[i, ...], X[j, ...])
    return cm


# 计算方差矩阵,(一般不用这个函数,这里为实验演示添加)
def i_var_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        cm[i, i] = i_cov(X[i, ...], X[i, ...])
    return cm


# 计算两个向量的相关系数(先标准化再计算协方差)
# numpy的对应方法 np.corrcoef(x,y)
def i_cor(x, y):
    x_s = i_norm_vec(x)
    y_s = i_norm_vec(y)
    return i_cov(x_s, y_s)


# 计算一个numpy矩阵的相关系数阵(每行是一个变量)
# numpy的对应方法 np.corrcoef(X)
def i_cor_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        for j in range(i, vc):
            cm[i, j] = i_cov(X[i, ...], X[i, ...])
    return cm


# 计算矩阵的逆,注意,未检查奇异矩阵
# numpy的对应函数np.lialq.inv(Y)
# 其实当不能从下面找到交换行时,就可以判断奇异矩阵了
def i_matrx_inv(Y):
    X = np.copy(Y)  # 不破换原来的矩阵
    n = np.size(X, axis=0)
    rel = np.identity(n)
    """  先变为右上三角举证 """
    for i in range(n):
        """ 如果(i,i)位置为0则从下面行向上交换 """
        if abs(X[i, i]) < 1e-5:
            for r in range(i+1, n):
                if X[r, i] > 1e-5:
                    X[i, ...], X[r, ...] = X[r, ...], X[i, ...]
                    rel[i, ...], rel[r, ...] = rel[r, ...], rel[i, ...]  # 伴随矩阵要一块变化
                    break
        """ 如果找不到,可以触发异常,是奇异矩阵 """
        """ 当前行(i,j)位置变为1 """
        t = float(X[i, i])
        for j in range(i, n):
            """ 只需处理i后面的列就可以,因为前面的已经都变成0了 """
            X[j, j] /= t
        for j in range(n):
            """伴随矩阵要一块变化且要变化所有的列 """
            rel[i, j] /= t
        """ 将所有下面行的相应位置变为0 """
        for row in range(i+1, n):
            rh = float(X[row, i])
            for col in range(i, n):
                """ 这里不必处理所有的列,因为前面已经都变为0了 """
                X[row, col] -= rh*X[i, col]
            for col in range(n):
                """ 伴随矩阵要一块变化并且要处理所有的列 """
                rel[row, col] -= rh*rel[i, col]
    for i in range(n-1, 0, -1):
        for row in range(i-1, -1, -1):
            rh = float(X[row, i])
            for col in range(n):
                """ 伴随矩阵变化,要处理所有的列 """
                rel[row, col] -= rh*rel[i, col]
    return rel


# 计算欧几里得距离
# 也可以用numpy的计算模的函数完成计算np.linalg.norm(x-y)
def dist(x, y):
    return sqrt(sum([(x[i]-y[i]) ** 2 for i in range(len(x))]))


# 距离计算的例子,生成两个相关序列,观察其不同的距离
np.random.seed(856479)
a = np.random.randn(100)  # 标准正态分布的序列
b = 50*a+10000  # 期望值为10000,方差为2500的正态分布,且与a完全线性相关
m = np.vstack((a, b))


# 首尾两个点的距离
fp = np.array([a[0], b[0]])
lp = np.array([a[99], b[99]])
print("Two data points:")
print(fp)
print(lp)
print()


# 完全未调整的距离
print("Unadjusted diatance :{}".format(dist(fp, lp)))
print()


# 计算相关矩阵
dv = (fp-lp).reshape(1, 2)
dv_t = dv.T
print("Difference vector")
print(dv)
print("Transposed difference vecyor:")
print(dv_t)
print()


# 经过方差调整的距离
print("Adjusted only by variance:")
m_var = i_var_matrix(m)
m_var_inv = i_matrx_inv(m_var)
print("Variance Matrix:")
print(m_var)
print("Inver variance matrix:")
print(m_var_inv)
print("Distance by variance:")
print(np.sqrt(i_matrix_mul(i_matrix_mul(dv, m_var_inv), dv_t)))
print()

# 经协方差矩阵调整的距离
print("Adjusted by covariance:")
m_cov = i_cov_matrix(m)
m_cov_inv = i_matrx_inv(m_cov)
print("Covariance matrix:")
print(m_cov)
print("Inverse covariance matrix:")
print(m_cov_inv)
print("Distance by covariance:")
print(np.sqrt(i_matrix_mul(i_matrix_mul(dv, m_cov_inv), dv_t)))

【实验目的】

1 掌握随机抽样的常用方法。

2 掌握变量规范化的常用方法。

3 掌握常见距离的定义及计算方法。

4 掌握二元变量相似度、连续变量余弦相似度计算方法。

5 掌握Mahalanobis距离的计算方法。

【实验类型】

设计型

【实验学时】

2学时

【实验环境】

                Windows 7以上操作系统

                Python3.0以上版本

                Pycharm开发环境

                Spyder开发环境

【实验要求】

一、请随机生成1000个二维数据点,从中分别随机抽取约75%,50%,25%的数据点,并绘图展示抽取数据点的情况。

参考输出结果:

0pDRLd.png

code:

import matplotlib.pyplot as plt
import random as rd

x = [rd.gauss(0, 1) for i in range(1000)]
y = [rd.gauss(0, 1) for i in range(1000)]


def f(x, y, p):
    xx = []
    yy = []
    for j in range(1000):
        if rd.random() >= p:
            xx.append(x[j])
            yy.append(y[j])
    return xx, yy


def paint(xx, yy, str_1, str_2):
    plt.subplot(str_1)
    plt.title(str_2+str(len(xx)))
    plt.scatter(xx, yy, s=[0.5])


x1, y1 = f(x, y, 0.25)
x2, y2 = f(x, y, 0.5)
x3, y3 = f(x, y, 0.75)
paint(x, y, 221, "all--")
paint(x1, y1, 222, "75%--")
paint(x2, y2, 223, "50%--")
paint(x3, y3, 224, "25%--")
plt.show()

二、请计算生成正弦函数序列和余弦函数序列,并绘图展示。将正弦序列和余弦序列添加随机偏差(噪音)后再次绘图,观察噪音对数据的影响。

参考输出结果:

0pD2sH.png

code:

from math import *
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-6*pi, 6*pi, 0.1)
y = np.sin(x)
z = np.cos(x)

y1 = y+np.random.randn(len(y))
z1 = y+np.random.randn(len(z))


def paint(xx, yy, zz, str_1):
    plt.subplot(str_1)
    plt.plot(xx, yy)
    plt.plot(xx, zz)


paint(x, y, z, 211)
paint(x, y1, z1, 212)
plt.show()

三、验证几类变量变换的效果,包括:指数变换、> 1幂变换、对数变换、(0,1)幂变换、< 0幂变换、正弦变换,绘图演示各类变换的效果。

参考输出结果:

 

0pDgQe.png

code:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(1, 50, 100)
y1 = np.exp(x)
y2 = x**3
y3 = np.log10(x)
y4 = np.sqrt(x)
y5 = 1/x
y6 = np.sin(x)


def paint(x, y, str_1, str_2):
    plt.subplot(str_2)
    plt.title(r"{}".format(str_1))
    plt.plot(x, y)


paint(x, y1, "$y=e^x$", 231)
paint(x, y2, "$y=x^3$", 232)
paint(x, y3, "$y=log_{10}x$", 233)
paint(x, y4, "$y=\sqrt{x}$", 234)
paint(x, y5, '$y=\\frac{1}{x}$', 235)
paint(x, y6, "$y=sin(x)$", 236)

plt.show()
""" 
输出函数式参考: https://stackoverflow.com/questions/4028267/how-to-render-latex-markup-using-python/58496145#58496145
"""

四、为了提出变量量纲对数据分析的影响,经常需要对变量进行一定的变换,其中常用的一种是标准化(normalization)变换(即将数据序列转换为期望值为0和方差为1的序列),转换公式为:

其中

为序列的均值,

为序列的样本标准差,即

  • (这儿借用了谷歌的api需要科学网络才能显示这四个公式)

请随机生成一个序列,并生成它的标准化序列,将两个序列通过绘图展示出来。

参考输出结果(其中随机生成的序列为期望值1000,标准差200,长度1000的正态分布序列):

 

0pD6zD.png

code:

from math import *
import matplotlib.pyplot as plt
import numpy as np
y1 = np.random.normal(1000, 200, 1000)

sd = sqrt(sum((y1-np.average(y1))**2))/(len(y1)-1)
y2 = (y1-np.average(y1))/sd

print(np.mean(y2), np.std(y2))

plt.subplot(211)
plt.plot(y1)
plt.subplot(212)
plt.plot(y2)
plt.show()

五、距离计算

向量间的闵可夫斯基距离的定义如下:

0pDyRO.png

其中当r=1时成为街区距离,为不同分量差绝对值的和

当r=2时即为欧几里得距离

当r=+infinity时,等于所有分量差绝对值中最大的一个

编写函数实现三种距离的计算,并对下面4个二维向量分别计算其三种距离定义的距离矩阵。

0pDhdI.png

参考输出结果如下:

0pDfeA.png

code:

import math
import re

infinity = float("inf")


def d(point1, point2, r):
    global infinity
    sum = 0.0
    if r != infinity:
        for i in range(len(point1)):
            sum += (abs(point1[i]-point2[i])**r)
        sum **= (1/r)
    else:
        for i in range(len(point1)):
            xyabs_ = abs(point1[i]-point2[i])
            sum = sum if sum > xyabs_ else xyabs_
    return sum


def ma(list_1, r):
    list_2 = []
    for i in list_1:
        list_3 = []
        for j in list_1:
            list_3.append(d(i, j, r))
        list_2.append(list_3)
    return list_2


def out(list_):
    for i in list_:
        for j in i:
            print("{}\t".format(j), end="")
        print()
    print()


list1 = [[0, 2], [2, 0], [3, 1], [5, 1]]
print("Data Matrix:")
out(list1)
print("City Block Distance:")
out(ma(list1, 1))
print("Euclid Distance:")
out(ma(list1, 2))
print("Distance with Element Max Difference:")
out(ma(list1, infinity))

"""
题目中的距离公式不是太容易理解,下面的文档有一些不错的解释
闵可夫斯基距离详解:https://wenku.baidu.com/view/35296aa3ec630b1c59eef8c75fbfc77da3699700.html
"""

""" 
尝试了一下参考图中的那种输出,没有成功;
此代码的输出:
Data Matrix:
0       2
2       0
3       1
5       1

City Block Distance:
0.0     4.0     4.0     6.0
4.0     0.0     2.0     4.0
4.0     2.0     0.0     2.0
6.0     4.0     2.0     0.0

Euclid Distance:
0.0     2.8284271247461903      3.1622776601683795      5.0990195135927845 

2.8284271247461903      0.0     1.4142135623730951      3.1622776601683795 

3.1622776601683795      1.4142135623730951      0.0     2.0
5.0990195135927845      3.1622776601683795      2.0     0.0

Distance with Element Max Difference:
0       2       3       5
2       0       1       3
3       1       0       2
5       3       2       0

"""

六、二元变量的相似度衡量可以使用简单匹配系数(SMC)或Jaccard系数

设x和y是两个对象,都由n个二元属性组成,这样两个对象可生成如下四个量(频率):

0pD4ot.png

简单匹配系数(Simple Matching Coefficient, SMC)定义为:

0pDTW8.png

Jaccard系数(Jaccard Coefficient)的定义为:

0pDIFP.png

编写两个函数分别实现连个系数的计算,并生成两个随机序列调用函数计算。

参考输出结果:

0pDoJf.png

code

import numpy as np


def fun_count(a, b):
    count00 = 0
    count11 = 0
    count10 = 0
    count01 = 0
    for i in range(0, len(a)):
        if a[i] == 0:
            if a[i] == b[i]:
                count00 += 1
            else:
                count01 += 1
        else:
            """ a[i]==1 """
            if a[i] == b[i]:
                count11 += 1
            else:
                count10 += 1
    return count00, count01, count10, count11


def fun_SCM(a, b):
    f00, f01, f10, f11 = fun_count(a, b)
    SCM = ((f11+f00)*1.0)/(f00+f01+f10+f11)
    return SCM


def fun_J(a, b):
    f00, f01, f10, f11 = fun_count(a, b)
    J = (f11*1.0)/(f01+f10+f11)
    return J


a = np.random.randint(0, 2, 100)
b = np.random.randint(0, 2, 100)

print("Vector a is:")
print(a)

print("Vector b is:")
print(b)

print("SCM coefficient:")
print(fun_SCM(a, b))
print("Jaccard coefficient")
print(fun_J(a, b))

七、余弦相似度是衡量数值向量相似度的一种方法,设x和y是两个n元向量,则余弦相似度定义为

0pDHSS.png

0pDbQg.png

 

编写函数实现余弦相似度的计算,并调用函数计算下面两个向量的余弦相似度。

参考输出结果:

 

0pDqyQ.png

code


def fun_xy(a, b):
    sum = 0.0
    for i in range(len(a)):
        sum += (a[i]*b[i])
    return sum


def fun_len(x):
    sum = 0.0
    for i in x:
        sum += i**2
    return sum**(1/2)


def fun_cosxy(x, y):
    return (fun_xy(x, y)*1.0)/(fun_len(x)*fun_len(y))


x = (3, 2, 0, 5, 0, 0, 0, 2, 0, 0)
y = (1, 0, 0, 0, 0, 0, 0, 1, 0, 2)

print("Vetor Angle Consine:{}".format(fun_cosxy(x, y)))

八、从统计学的观点看,计算多维向量的距离时,应该使用mahalanobis距离,其定义为:

0pDLLj.png

属性间协方差的定义如下所示:

0pDjwn.png

0pDzF0.png

实现欧几里得距离、使用方差逆矩阵调整的距离、使用协方差逆矩阵调整的距离三类距离的计算函数,并构造两个随机向量验证三种距离的不同。

参考输出结果:

0pDvoq.png

code

from math import *
import re
import numpy as np


# 计算两个矩阵的乘积
# numpy的对应函数 np.linalg.dot(X,Y)
def i_matrix_mul(X, Y):
    rrow = np.size(X, axis=0)
    rcol = np.size(Y, axis=1)
    rmid = np.size(X, axis=1)
    rel = np.linspace(0.0, 0.0, rrow*rcol).reshape(rrow, rcol)
    for r in range(rrow):
        for c in range(rcol):
            rel[r, c] = 0.0
            for mid in range(rmid):
                rel[r, c] += X[r, mid] * Y[mid, c]
    return rel


# 计算期望值(均值),对应np.average
def i_mean(x):
    return sum(x)/len(x)


# 计算样本方差
# 注意,numpy.var计算的是总体的,使用时需要调整
def i_var(x):
    x_mean = i_mean(x)
    return sum((x-x_mean)**2)/(len(x)-1)


# 计算样本标准差
# 注意,numpy.std计算的是总体的,使用时需要调整
def i_std(x):
    x_mean = i_mean(x)
    return sqrt(i_var(x))


# 序列标准化
def i_norm_vec(x):
    x_mean = i_mean(x)
    x_std = i_std(x)
    return (x-x_mean)/x_std


# 计算两个向量的协方差
# numpy的对应方法 np.cov(x,y),但是返回协方差矩阵
def i_cov(x, y):
    x_av = np.average(x)
    y_av = np.average(y)
    return sum((x-x_av)*(y-y_av))/(len(x)-1)


# 计算一个numpy矩阵的协方差(每行是一个变量)
# numpy的对应方法 np.cov(X)
def i_cov_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        for j in range(i, vc):
            cm[j, i] = cm[i, j] = i_cov(X[i, ...], X[j, ...])
    return cm


# 计算方差矩阵,(一般不用这个函数,这里为实验演示添加)
def i_var_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        cm[i, i] = i_cov(X[i, ...], X[i, ...])
    return cm


# 计算两个向量的相关系数(先标准化再计算协方差)
# numpy的对应方法 np.corrcoef(x,y)
def i_cor(x, y):
    x_s = i_norm_vec(x)
    y_s = i_norm_vec(y)
    return i_cov(x_s, y_s)


# 计算一个numpy矩阵的相关系数阵(每行是一个变量)
# numpy的对应方法 np.corrcoef(X)
def i_cor_matrix(X):
    vc = np.size(X, axis=0)
    cm = np.linspace(0.0, 0.0, vc**2).reshape(vc, vc)
    for i in range(vc):
        for j in range(i, vc):
            cm[i, j] = i_cov(X[i, ...], X[i, ...])
    return cm


# 计算矩阵的逆,注意,未检查奇异矩阵
# numpy的对应函数np.lialq.inv(Y)
# 其实当不能从下面找到交换行时,就可以判断奇异矩阵了
def i_matrx_inv(Y):
    X = np.copy(Y)  # 不破换原来的矩阵
    n = np.size(X, axis=0)
    rel = np.identity(n)
    """  先变为右上三角举证 """
    for i in range(n):
        """ 如果(i,i)位置为0则从下面行向上交换 """
        if abs(X[i, i]) < 1e-5:
            for r in range(i+1, n):
                if X[r, i] > 1e-5:
                    X[i, ...], X[r, ...] = X[r, ...], X[i, ...]
                    rel[i, ...], rel[r, ...] = rel[r, ...], rel[i, ...]  # 伴随矩阵要一块变化
                    break
        """ 如果找不到,可以触发异常,是奇异矩阵 """
        """ 当前行(i,j)位置变为1 """
        t = float(X[i, i])
        for j in range(i, n):
            """ 只需处理i后面的列就可以,因为前面的已经都变成0了 """
            X[j, j] /= t
        for j in range(n):
            """伴随矩阵要一块变化且要变化所有的列 """
            rel[i, j] /= t
        """ 将所有下面行的相应位置变为0 """
        for row in range(i+1, n):
            rh = float(X[row, i])
            for col in range(i, n):
                """ 这里不必处理所有的列,因为前面已经都变为0了 """
                X[row, col] -= rh*X[i, col]
            for col in range(n):
                """ 伴随矩阵要一块变化并且要处理所有的列 """
                rel[row, col] -= rh*rel[i, col]
    for i in range(n-1, 0, -1):
        for row in range(i-1, -1, -1):
            rh = float(X[row, i])
            for col in range(n):
                """ 伴随矩阵变化,要处理所有的列 """
                rel[row, col] -= rh*rel[i, col]
    return rel


# 计算欧几里得距离
# 也可以用numpy的计算模的函数完成计算np.linalg.norm(x-y)
def dist(x, y):
    return sqrt(sum([(x[i]-y[i]) ** 2 for i in range(len(x))]))


# 距离计算的例子,生成两个相关序列,观察其不同的距离
np.random.seed(856479)
a = np.random.randn(100)  # 标准正态分布的序列
b = 50*a+10000  # 期望值为10000,方差为2500的正态分布,且与a完全线性相关
m = np.vstack((a, b))


# 首尾两个点的距离
fp = np.array([a[0], b[0]])
lp = np.array([a[99], b[99]])
print("Two data points:")
print(fp)
print(lp)
print()


# 完全未调整的距离
print("Unadjusted diatance :{}".format(dist(fp, lp)))
print()


# 计算相关矩阵
dv = (fp-lp).reshape(1, 2)
dv_t = dv.T
print("Difference vector")
print(dv)
print("Transposed difference vecyor:")
print(dv_t)
print()


# 经过方差调整的距离
print("Adjusted only by variance:")
m_var = i_var_matrix(m)
m_var_inv = i_matrx_inv(m_var)
print("Variance Matrix:")
print(m_var)
print("Inver variance matrix:")
print(m_var_inv)
print("Distance by variance:")
print(np.sqrt(i_matrix_mul(i_matrix_mul(dv, m_var_inv), dv_t)))
print()

# 经协方差矩阵调整的距离
print("Adjusted by covariance:")
m_cov = i_cov_matrix(m)
m_cov_inv = i_matrx_inv(m_cov)
print("Covariance matrix:")
print(m_cov)
print("Inverse covariance matrix:")
print(m_cov_inv)
print("Distance by covariance:")
print(np.sqrt(i_matrix_mul(i_matrix_mul(dv, m_cov_inv), dv_t)))

相关