本文数据为真实数据,但是数据量少,不能作为科学用途,数据来源数据集上kaggle,点击dataset,搜prostate cancer,第二个就是,本文所用数据为100条,文章最后有本文所使用数据,如果需要自行提取,另附笔者学习的视频
题目
医学上判断肿瘤需要通过"radius",“texture”,“perimeter”,“area”,“smoothness”,“symmetry”
,“compactness”,"fractal_dimension"等数据来判断肿瘤是否为恶性,现在有一组数据,请用knn方法来进行分析肿瘤的良性恶性(良性肿瘤用“B”,恶性肿瘤用“M”表示)
部分数据样例如图所示:
如图所示,id为序号,diagnosis_result为肿瘤判断结果,也是我们所需要求出的,剩余量为条件变量(分类依据)
完整代码
#导入文件
import csv
import random
with open(r'F:\prostate-cancer(1)\Prostate_Cancer.csv') as file:
reader = csv.DictReader(file)
data = [row for row in reader]
n = len(data)//3
test_data = data[0: n]
train_data = data[n: ]
#求距离
def distance(d1, d2):
res = 0
for key in ("radius","texture","perimeter",
"area","smoothness","compactness","symmetry","fractal_dimension"):
res += (float(d1[key]) - float(d2[key])) ** 2
return res**0.5
#knn算法
#定义K值
k = 5
def knn(data):
#1.求距离
res = [
{"result": train["diagnosis_result"], "distance": distance(data, train)}
for train in train_data
]
#2.排序
res=sorted(res, key=lambda item: item['distance'])
res2 = res[0: k]
#判断类别
reslut = {"M":0,"B":0}
for key in res2:
if key['result'] == "M":
reslut["M"] += 1
else:
reslut["B"] += 1
if reslut["M"]>reslut['B']:
# print("M")
return "M"
else:
# print("B")
return "B"
#----------------------------------------------------------------------#
#正确率判断
sum = 0
m = 0
for data in test_data:
sum += 1
if knn(data) == data["diagnosis_result"]:
m += 1
last = m/sum
print(last)
详解代码
导入文件
这个文件的格式是.csv,我们可以将它直接转化为字典模式`
#导入文件
import csv
with open(r'F:\prostate-cancer(1)\Prostate_Cancer.csv') as file:
reader = csv.DictReader(file)#转化为字典
data = [row for row in reader]#使得每一个字典数据为列表中的元素
对数据进行分类
对这100条数据分类,由于数据不多,我们按照1/3为测试数据,2/3为训练数据的方式分类(如果数据有很多,我们可以采用1/10为测试数据)
n = len(data)//3 #在这里我们采取了整除
test_data = data[0: n]
train_data = data[n: ]
求距离函数
这是knn算法的重要步骤之一,python有很多种距离,本文采用的是最常见的欧式距离,即 √(x1-x2)²+(y1-y2)²…,随着条件簇的增多,我们写的参数越多
#求距离
def distance(d1, d2):
res = 0
for key in ("radius","texture","perimeter",
"area","smoothness","compactness","symmetry","fractal_dimension"):
res += (float(d1[key]) - float(d2[key])) ** 2
return res**0.5
函数传入两个参数后,我们定义一个元组,定义一个变量key依次遍历,元组中的值,而传入的d1和d2都是我们列表中的字典,这样我们可以求得字典所对应键值的value值,同时我们又发现value值为字符串模式,且存在大量小数,采用转型变成float型进行运算,并返回开方值
KNN函数
先随机设定k值(但是要合理)
k = 5
knn函数
def knn(data):
#1.求距离
res = [
{"result": train["diagnosis_result"], "distance": distance(data, train)}
for train in train_data
]
#2.排序
res=sorted(res, key=lambda item: item['distance'])
res2 = res[0: k]
#判断类别
reslut = {"M":0,"B":0}
for key in res2:
if key['result'] == "M":
reslut["M"] += 1
else:
reslut["B"] += 1
if reslut["M"]>reslut['B']:
# print("M")
return "M"
else:
# print("B")
return "B"
在knn函数中,我们先定义一个输出列表,列表内容为一系列字典,字典的一个key-value值为所使用的训练数据的肿瘤良恶性结果;一个key-value值为距离判断,用来执行距离函数,并依次为依据排序,这个列表的输出结果为每一次所调用的训练数据肿瘤良恶性判断和输入的测试数据与所调用的训练数据各个判断簇的距离
随后对列表按照距离升序排序,取前k个
并进行数据统计,数据次数多的为该测试数据在knn算法后的良恶性情况输出结果
正确率判断
将所有的测试数据进行测试判断,并将knn函数的返回值和测试数据原来的结果进行比较,得到正确率,修改k值,得到最佳解
#正确率判断
sum = 0
m = 0
for data in test_data:
sum += 1
if knn(data) == data["diagnosis_result"]:
m += 1
last = m/sum
print(last)
代码改进
该代码有改进之处:
1.由于数据少,存在偶然情况,所以我们可以把每行数据看成整体并对数据进行随机排列,使得训练组和测数组的数据多样化,减少偶然误差
2.对于测试数据和训练数据之间的距离,应该添加权重,即距离近的权重大,距离远的权重小,从而减少误差
改进后的代码
import csv
import random
with open(r'F:\prostate-cancer(1)\Prostate_Cancer.csv') as file:
reader = csv.DictReader(file)
datas = [row for row in reader]
#对数据进行随机排序
random.shuffle(datas)
n = len(datas)//3
test_set = datas[0:n]
train_set = datas[n:]
def distance(d1,d2):
res = 0
for key in ("radius","texture","perimeter",
"area","smoothness","compactness","symmetry","fractal_dimension"):
res += (float(d1[key])-float(d2[key]))**2
return res**0.5
k = 6
def knn(data):
res = [
{"result":train["diagnosis_result"],"distance":distance(data,train)}
for train in train_set
]
res = sorted(res,key = lambda item:item['distance'])
#取前K个值
res2 = res[0:k]
#加权平均(result是最终判据)
result = {'B':0,'M':0}
#总长度
sum_dist = 0
for r1 in res2:
sum_dist += r1['distance']
#逐个分类加和
for r2 in res2:
result[r2["result"]] += 1-r2["distance"]/sum_dist
#print(result)
if result['B'] > result['M']:
return 'B'
else:
return 'M'
#----------------------------------------------------------------------#
#求正确率
correct = 0
for test in test_set:
result = test['diagnosis_result']
result2 = knn(test)
if result == result2:
correct = correct + 1;
print("正确率为:" + str(correct/len(test_set)))
所用文件
链接:https://pan.baidu.com/s/1JAWOu2mO_GSfwTu_6Z5YVg
提取码:3zhs
复制这段内容后打开百度网盘手机App,操作更方便哦