数据挖掘概念与技术习题选做
第三章习题
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)
是一种基于 的离散化方法,采用自底向上的策略,递归地找出最邻近的区间,然后合并它们,形成较大的区间。与决策树分析一样, 是监督的,使用了类信息。其基本思想是,对于精确的离散化,相对类频率在一个区间内应当完全一致。因此如果两个邻近区间具有非常类似的分布,则这个区间可以合并,否则,它们应当保持分开。
过程如下:初始时,把数值属性 的每个不同值看作一个区间。对于每对相邻区间进行 检验,具有最小 的相邻区间合并在一起,因为低 值表明它们具有相似的类分布。该合并过程递归地进行,直到满足预定义的终止条件。
编写程序用 方法实现对鸢尾花属性的离散化。说明:本程序以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: &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&