数据挖掘习题选做--第三章:ChiMerge离散法

数据挖掘概念与技术习题选做

第三章习题

这里写图片描述

import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm   # 导入统计模型模块
data = np.array([13,15,16,16,19,20,20,21,22,22,25,25,25,25,30,33,33,35,35,35,35,36,40,45,46,52,70])

# 创建一个空字典用于储存每个箱的数据
box_dict = {}

for i in range(0, int(len(data) / 3)):
    box_dict["box"+ str(i)] = []    # 创建一定数量的空箱子用来装填数据

for n in range(0, len(data), 3):
    mean = round((data[n] + data[n+1] + data[n+2]) / 3, 1)  # 每三个数计算平均值,保留一位小数
    for m in range(0,3):
        box_dict["box"+ str(int(n/3))].append(mean)  # 将光滑后的均值填入每个箱中

# 打印每个箱的数据值
print("\n使用深度为3的箱均值光滑后的数据为:\n")
for key, value in box_dict.items():
    print("箱子"+str(key)+"中的值为:", value)


# 用不超过四分位数Q1和Q3的1.5个IQR来确定离群点
Q1_index = int(len(data)/ 4)
Q3_index = int(len(data) / 4 * 3)
IQR = data[Q3_index] - data[Q1_index]

for value in data:
    if value < data[Q1_index] - 1.5 * IQR or value > data[Q3_index] + 1.5 * IQR:
        print("\n检测出的离群点为:", value)


# 用线性回归来光滑数据
x = np.linspace(1, 27, 27)  # 定义x的值

est = sm.OLS(data, x).fit()  # 用最小二乘法拟合

print(est.summary())

fig = plt.figure()
ax = fig.add_subplot(111)
y = 1.9912 * x + 0.079
ax.plot(x, data, '.')
ax.plot(x, y)
plt.show()

(a) 用Python实现箱均值光滑
运行结果为:
这里写图片描述

(b) 四分位数Q1和Q3的1.5个IQR来确定离群点
这里写图片描述

(c) 最小二乘法线性回归拟合光滑
这里使用了统计学工具,和R语言一样,生成一系列指标参数作为评价参考:
这里写图片描述
绘制结果:
这里写图片描述

这里写图片描述

import numpy as np
import matplotlib.pyplot as plt

data = np.array([13,15,16,16,19,20,20,21,22,22,25,25,25,25,30,33,33,35,35,35,35,36,40,45,46,52,70])

def min_max(data, min=0.0, max=1.0):
    """定义最小-最大规范化函数"""
    min_max_data = []
    for value in data:
        value = (value-np.min(data)) / (np.max(data)-np.min(data)) * (max - min) + min  # 最小最大规范化公式
        value = round(value, 2)   # 保留两位小数
        min_max_data.append(value)
    return min_max_data

mm_data = min_max(data)
# 打印最小最大规范结果
print("\n最小-最大规范化结果为:\n", mm_data)


def sigma(list):
    """定义一个求标准差的函数"""
    variance = 0
    for value in list:
        variance += (value - np.average(list)) ** 2
    sigma = np.sqrt(variance)
    return sigma


def z_percent(data):
    """定义z分数规范化函数"""
    z_data = []
    for value in data:
        value = (value - np.average(data)) / np.average(data)
        value = round(value, 2)
        z_data.append(value)
    return z_data

z_data = z_percent(data)
print("z分数规范化结果为:\n", z_data)


def little_num(data):
    """定义小数定标规范化"""
    j = 0
    while True:
        value_mp = np.max(np.abs(data)) / (10 ** j)
        if value_mp < 1:
            break
        j += 1
    result = data / (10 ** j)
    return result

little_data = little_num(data)
print("小数定标规范化结果为:\n", little_data)

计算结果为:
这里写图片描述

这里写图片描述

import numpy as np
import matplotlib.pyplot as plt

age = np.array([23,23,27,27,39,41,47,49,50,52,54,54,56,57,58,58,60,61])
fat = np.array([9.5,26.5,7.8,17.8,31.4,25.9,27.4,27.2,31.2,34.6,42.5,28.8,33.4,30.2,34.1,32.9,41.2,35.7])

def sigma(list):
    """定义一个求标准差的函数"""
    variance = 0
    for value in list:
        variance += (value - np.average(list)) ** 2
    sigma = np.sqrt(variance)
    return sigma


def z_percent(data):
    """定义z分数规范化函数"""
    z_data = []
    for value in data:
        value = (value - np.average(data)) / np.average(data)
        value = round(value, 2)
        z_data.append(value)
    return z_data

z_age = z_percent(age)
z_fat = z_percent(fat)
print("age数据z分数规范化结果为:\n", z_age)
print("fat数据z分数规范化结果为:\n", z_fat)


def covariance(data1, data2):
    """计算两组数据的协方差"""
    sum = 0
    for i in range(len(data1)):
        sum += (data1[i] - np.average(data1)) * (data2[i] - np.average(data2))
    covariance = sum / len(data1)
    return covariance

covariance = covariance(age, fat)                    # 协方差
r_ab = covariance / (sigma(age) * sigma(fat))   # 计算相关系数
print("相关系数为:", r_ab)
if r_ab > 0:
    print("这两组数据呈正相关")
elif r_ab == 0:
    print("这两组数据相互独立")
else:
    print("这两组数据负相关")

print("两组数据的协方差为:", covariance)

这里写图片描述

这里写图片描述

C h i M e r g e 是一种基于 χ 2 的离散化方法,采用自底向上的策略,递归地找出最邻近的区间,然后合并它们,形成较大的区间。与决策树分析一样, C h i m e r g e 是监督的,使用了类信息。其基本思想是,对于精确的离散化,相对类频率在一个区间内应当完全一致。因此如果两个邻近区间具有非常类似的分布,则这个区间可以合并,否则,它们应当保持分开。

C h i M e r g e 过程如下:初始时,把数值属性 A 的每个不同值看作一个区间。对于每对相邻区间进行 χ 2 检验,具有最小 χ 2 的相邻区间合并在一起,因为低 χ 2 值表明它们具有相似的类分布。该合并过程递归地进行,直到满足预定义的终止条件。

编写程序用 C h i M e r g e 方法实现对鸢尾花属性的离散化。说明:本程序以iris.data 的属性sepal_length为例,输出6个属性区间,并打印对应的类别信息。参考一些资料,从头到尾自己代码实现,正确性不能保证,但基本思路应该没问题。

代码如下

# -*- coding: utf-8 -*-
__author__ = "Yunfan Yang"


import numpy as np

# 读取数据并简单处理
def read_data(filename):
    with open(filename, 'r') as f:
        content  = f.read()
    iris_list = content.strip().split('\n')  # 生成一个鸢尾花列表,储存4个属性值和一个类别值
    return iris_list
# 鸢尾花4个属性值列表
# sepal_length = []
# sepal_width = []
# petal_length = []
# petal_width = []


def initial_interval(iris_list):
    """初始化属性区间"""
    sepal_length = []  # 这里以sepal_length属性为例
    for value in iris_list:
        temp_list = value.strip().split(',')   # 单独储存每个鸢尾花到一个临时列表中
        initial_set = {"interval":[]}  # 创建字典用来储存属性区间的元素(属性数值)
        initial_set["interval"].append(temp_list[0])


        # 定义一个空元组用来储存类别信息,'Iris-setosa'-> (1,0,0), 'Iris-versicolor'-> (0,1,0), 'Iris-virginica' -> (0,0,1)
        if temp_list[4] == 'Iris-setosa':
            class_tuple = [1,0,0]
        if temp_list[4] == 'Iris-versicolor':
            class_tuple = [0,1,0]
        if temp_list[4] == 'Iris-virginica':
            class_tuple = [0,0,1]

        interval_class = (initial_set, class_tuple) # 构造形如({'interval': ['4.9']}, [1, 0, 0])的数据结构用来储存属性值(区间)与相应的类别
        sepal_length.append(interval_class)    # 将所有sepal_length属性区间对应列表整合在一个列表中
        sepal_length.sort(key=lambda x: x[0]["interval"][0])  # 按照属性值大小,从小到大排列每个区间

    return sepal_length



# 这里怎么计算卡方
# ==============================================================================================
# 区间:          |类别Iris-setosa | 类别Iris-versicolor| 类别Iris-virginica | i行计算1的总个数   |
# ----------------|---------------|--------------------|--------------------|------------------|
# ['4.6']         |       1       |         0          |         0          |        1         |
# ----------------|---------------|--------------------|--------------------|------------------|
# ['4.7','4.8']   |       0       |         1          |         2          |        3         |
# ----------------|---------------|--------------------|--------------------|------------------|
# j列计算1的总个数 |       1       |           1        |         2          | 4(矩阵里1的总个数) |
#==============================================================================================
# 根据每个属性值区间所对应的类别数计算卡方值,因为要比较相邻两个区间的卡方值,这里计算两行三列的数据卡方值


# A = [1,0,0]
# B = [0,1,0]
def chi2(A, B):
    """定义卡方计算函数"""
    table = np.array([A, B])
    e_ij = 0
    sum_chi2 = 0   # 初始化卡方和的值
    for i in range(2):
        for j in range(len(A)):
            e_ij = np.sum(table[:,j]) * np.sum(table[i,:]) / np.sum(table)  # 计算每个期望频度
            if e_ij != 0:
                sum_chi2 += (table[i][j] - e_ij) ** 2 / e_ij
    return sum_chi2

# sum_chi2 = chi2(A, B)
# print(sum_chi2)


# I1 = ({'interval': ['4.9']}, [1, 0, 0])
# I2 = ({'interval': ['5.0']}, [0, 1, 0])
def merge(I1, I2):
    """定义合并函数,使得({'interval': ['4.9']}, [1, 0, 0])和({'interval': ['5.0']}, [0, 1, 0])
    能够合并为({'interval': ['4.9', '5.0']}, [1, 1, 0])"""
    for value in I2[0]["interval"]:
        I1[0]["interval"].append(value)   # 前部分填充

    for i in range(3):
        I1[1][i] += I2[1][i]              # 后部分相加

    return I1
# Mg = merge(I1, I2)
# print(Mg)


def chiMerge(attribute_list, max_interval=6):     # 最大区间数为6
    """定义chiMerge函数,用来实现chimerge过程"""

    num_interval = len(attribute_list)  # 初始区间数为属性列表的长度

    while(num_interval > max_interval):  # 终止条件为区间数为6
        chi2_list = []                        # 创建储存卡方值的列表
        for i in range(len(attribute_list)-1):   # 遍历属性列表的区间信息
            chi2_value= chi2(attribute_list[i][1], attribute_list[i+1][1])  # 计算每个相邻区间的卡方值
            chi2_list.append(chi2_value)
        # print("chi2_list", chi2_list)
        min_chi2 = min(chi2_list)   # 求最小的卡方值
        # print("min_chi2:", min_chi2)
        min_index = chi2_list.index(min_chi2)    # 最小卡方值对应的索引
        attribute_list[min_index] = merge(attribute_list[min_index], attribute_list[min_index+1])  # 合并最小卡方值对应的属性区间
        del attribute_list[min_index+1]  # 删除最小值索引后的属性列表区间

        num_interval = len(attribute_list)

    return attribute_list


if __name__ == '__main__':

    filename = 'iris.data'   # 文件名
    iris_list = read_data(filename)  # 读取数据
    sepal_lengthList = initial_interval(iris_list)  # 初始化属性区间列表,这里以iris的第一个属性sepal_length为例
    result = chiMerge(sepal_lengthList)   # 进行ChiMerge离散化
    # print(result)
    # 打印相应信息
    for i in range(len(result)):

        print("\n第"+str(i+1)+"个sepal_length属性区间的值为:\n", result[i][0]["interval"])
        print("\n该区间所对应的类别信息为:")
        print("Iris-setosa: ", '*' * result[i][1][0],
              "\nIris-versicolor: ", '#' * result[i][1][1],
              "\nIris-virginica: ", '&' * result[i][1][2])

运行结果如下:

1个sepal_length属性区间的值为:
 ['4.3', '4.4', '4.4', '4.4', '4.5', '4.6', '4.6', '4.6', '4.6', '4.7', '4.7', '4.8', '4.8', '4.8', '4.8', '4.8', '4.9', '4.9', '4.9', '4.9']

该区间所对应的类别信息为:
Iris-setosa:  ******************** 
Iris-versicolor:   
Iris-virginica:  

第2个sepal_length属性区间的值为:
 ['4.9', '4.9']

该区间所对应的类别信息为:
Iris-setosa:   
Iris-versicolor:  # 
Iris-virginica:  &

第3个sepal_length属性区间的值为:
 ['5.0', '5.0', '5.0', '5.0', '5.0', '5.0', '5.0', '5.0', '5.0', '5.0', '5.1', '5.1', '5.1', '5.1', '5.1', '5.1', '5.1', '5.1', '5.1', '5.2', '5.2', '5.2', '5.2', '5.3', '5.4', '5.4', '5.4', '5.4', '5.4', '5.4', '5.5', '5.5']

该区间所对应的类别信息为:
Iris-setosa:  *************************** 
Iris-versicolor:  ##### 
Iris-virginica:  

第4个sepal_length属性区间的值为:
 ['5.5', '5.5', '5.5', '5.5', '5.5', '5.6', '5.6', '5.6', '5.6', '5.6', '5.6', '5.7', '5.7']

该区间所对应的类别信息为:
Iris-setosa:  ** 
Iris-versicolor:  ########## 
Iris-virginica:  &

第5个sepal_length属性区间的值为:
 ['5.7', '5.7', '5.7', '5.7', '5.7', '5.7', '5.8', '5.8', '5.8', '5.8', '5.8', '5.8', '5.8', '5.9', '5.9', '5.9', '6.0', '6.0', '6.0', '6.0', '6.0', '6.0', '6.1', '6.1', '6.1', '6.1', '6.1', '6.1', '6.2', '6.2', '6.2', '6.2', '6.3', '6.3', '6.3']

该区间所对应的类别信息为:
Iris-setosa:  * 
Iris-versicolor:  ####################### 
Iris-virginica:  &&&&&&&&&&&

第6个sepal_length属性区间的值为:
 ['6.3', '6.3', '6.3', '6.3', '6.3', '6.3', '6.4', '6.4', '6.4', '6.4', '6.4', '6.4', '6.4', '6.5', '6.5', '6.5', '6.5', '6.5', '6.6', '6.6', '6.7', '6.7', '6.7', '6.7', '6.7', '6.7', '6.7', '6.7', '6.8', '6.8', '6.8', '6.9', '6.9', '6.9', '6.9', '7.0', '7.1', '7.2', '7.2', '7.2', '7.3', '7.4', '7.6', '7.7', '7.7', '7.7', '7.7', '7.9']

该区间所对应的类别信息为:
Iris-setosa:   
Iris-versicolor:  ########### 
Iris-virginica:  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

猜你喜欢

转载自blog.csdn.net/weixin_40170902/article/details/79711662