机器学习:K近邻算法

本文来自同步博客

P.S. 不知道简书怎么显示数学公式以及更好的排版内容。所以如果觉得文章下面格式乱的话请自行跳转到上述链接。后续我将不再对数学公式进行截图,毕竟行内公式截图的话排版会很乱。看原博客地址会有更好的体验。

本文内容介绍机器学习的K近邻算法,用它处理分类问题。分类问题的目标是利用采集到的已经经过分类处理的数据来预测新数据属于何种类别。

K近邻算法

K近邻算法对给定的某个新数据,让它与采集到的样本数据点分别进行比较,从中选择最相似的K个点,然后统计这K个点中出现的各个类别的频数,并判定频数最高的类别作为新数据所属的类别。

这里有个问题是如何判定样本数据与新数据是否相似。常用的一种计算方法叫欧几里得距离。

欧几里得距离(Euclidean Distance)

假设有两个数据分别是:- X = (x\_1,x\_2,...,x\_n) -- Y = (y\_1,y\_2,...,y\_n) -。则-X--Y-的距离为:

D = \sqrt{\sum\_{i=1}^{n}(x\_i-y\_i)^2}

Python实现这个式子代码如下:

def euclidean_distance(x, y):
    if len(x) != len(y):
        warnings.warn('Input error')
    return sqrt( sum( [(x[i] - y[i])**2 for i in range(0, len(x))] ) )

print(euclidean_distance([1,2,3], [2,4,5]))

NumPy提供则可以用下面方法计算两个ndarray的距离:

np.linalg.norm(np.array([1,2,3]) - np.array([2,4,5]))

实现K近邻算法

接下来依照上面描述的算法原理实现K近邻算法。先定义一下输入数据的格式:

#二维测试数据的格式
dataset = {'k': [[1,2],[2,3],[3,1]], 'r':[[6,5],[7,7],[8,6]]}
new_features = [5,7]

我们假定样本数据的结构如dataset为一个字典类型的数据,字典的元素的关键字为类型名称,元素值为一个包含该类型所有样本点的列表。新数据为一个数据点。

所以K近邻算法的实现如下:

# KNN实现
def k_nearest_neighbors(data, predict, k=3):
    if len(data) >= k:
        warnings.warn('K less than total voting groups')
    # 计算距离
    distances = []
    for group in data:
        for features in data[group]:
            #distance = euclidean_distance(features, predict)
            distance = np.linalg.norm(np.array(features)-np.array(predict))
            distances.append([distance, group])
    # 排序后取前k项数据类别构成新数组
    votes = [i[1] for i in sorted(distances)[:k]]
    # 统计数组中频数最高的类别
    vote_result = Counter(votes).most_common(1)[0][0]
    return vote_result

# 调用KNN
result = k_nearest_neighbors(dataset, new_features, k=3)
print(result)

使用真实数据测试

UCI网站的机器学习数据库中可以找到Breast Cancer Wisconsin(Original)的真实统计数据。数据可以从这个链接下载,数据的描述可以看这个链接

看到数据描述中提到了数据每一列的定义如下:


乳癌数据描述

这份数据的预测目标是判断给定特征数据对应的乳癌情况,2表示良性、4表示恶性。

根据描述我们先处理一下下载到的数据,给它的每一列加上个列名。这样在Python里面就可以把它当成一个CSV文件处理。我这里把它保存到了一个名为breast-cancer-wisconsin.data的文件里。形状如下:

数据格式

数据里面还有一些统计不到的数据,用英文问号?表示。还有一个很奇怪的现象是数据读取进来后有些数字会被处理成字符串类型,如'1'这样的数据。这些都需要我们提前处理一下。

df = pd.read_csv('./dataset/breast-cancer-wisconsin.data')
# 处理问号
df.replace('?', -99999, inplace=True)
# id字段不应该当成一个统计特征字段,因此去除该列的内容
df.drop(['id'], 1, inplace=True)
# 源数据有部分数据是字符串,如'1',这对我们的模型有影响,所以整理一下类型
# 用列表存放数据
full_data = df.astype(float).values.tolist()
random.shuffle(full_data) # 洗乱数据

接下来生成训练数据集和统计数据集,代码如下:

# 生成训练数据集和统计数据集
test_size = 0.2
train_set = {2:[], 4:[]} # 训练集,占80%
test_set = {2:[], 4:[]} # 统计集,占20%
train_data = full_data[:-int(test_size*len(full_data))]
test_data = full_data[-int(test_size*len(full_data)):]
for i in train_data:
    train_set[i[-1]].append(i[:-1])
for i in test_data:
    test_set[i[-1]].append(i[:-1])

最后,利用上述KNN函数统计测试数据的准确性。

correct = 0
total = 0
for group in test_set:
    for data in test_set[group]:
        vote = k_nearest_neighbors(train_set, data, k=5)
        if group == vote:
            correct += 1
        total += 1
# 打印结果
print('correct: ', correct)
print('total: ', total)
print('Accuracy: ', correct/total)

完整代码请查看github链接

sklearn的K近邻算法

同样需要先处理一下数据并生成符合sklearn的输入格式的数据集。

from sklearn import model_selection
# 读取乳癌统计数据
df = pd.read_csv('./dataset/breast-cancer-wisconsin.data')
# 处理问号
df.replace('?', -99999, inplace=True)
# 因为ID字段与分类无关,所以去除他先,稍后我们看一下它的影响
df.drop(['id'], 1, inplace=True)
df = df.astype(float)

# 生成数据集
X = np.array(df.drop(['class'], 1))
y = np.array(df['class'])
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.2)

然后生成KNN模型对象,用数据训练模型,评估模型准确性。

from sklearn import neighbors
# 构建模型与训练
clf = neighbors.KNeighborsClassifier()
clf.fit(X_train, y_train)

# 计算精确度
accuracy = clf.score(X_test, y_test)
print('Accuracy: ', accuracy)

# 预测我们自己构造的数据属于哪个类型
example_measures = np.array([[4,2,1,1,1,2,3,2,1],[2,3,4,4,1,2,3,4,1]])
prediction = clf.predict(example_measures)
print('Predict resuct: ', prediction)

完整代码请查看github链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容