震惊
邻居女神小美到了要出嫁的年纪,天天相亲遇见奇葩,所以小美准备拜托她的青梅竹马兼男闺蜜的单身男程序员
你!!!!!
帮她写个程序,提前筛选一下相亲对象
你:???????
震惊
某程序员竟然用k近邻【(K-NearestNeighbor),俗称KNN,数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它最接近的K个邻近值来代表。近邻算法就是将数据集合中每一个记录进行分类的方法】给女神找相亲对象!
开局先将优略,如不符合您的要求,可以提前结束阅读,避免浪费您的时间。
优势:
- 理论逻辑简单,容易理解,方便实现。
- 可以用来分类也可用来回归
- 对稀有事物分类有奇效
- 可用于数值型或离散型数据
不足:
- 时空复杂度过高,运算量大,不适合大数据操作
- 存在样本不平衡问题
- 算法的可理解性差,无法给出数据的内在含义
算法的理论讲解
k-近邻(KNN):
给定已知标签类别的训练数据集,输入没有标签的测试集,在训练集中找到于测试集最邻近的k个实例,如果这k个实例中的多数属于类别A,则测试集也属于列别A。
我们使用离Y最近的k个点来决定Y属于哪一类
如图,我们已有类别红点和蓝点,判断图中心的绿点属于哪一类
if k=3; because: blue=1 and red = 2 and 2>1 therefore:green = red
elif k = 5; because: blue=3 and red = 3 and 3>2 therefore:green = blue
ou~~
懂是懂了,但是距离如何衡量呢?
A:
距离度量。在二维平面上计算两个点之间的距离。
∣
A
B
∣
=
(
x
1
−
x
2
)
2
+
(
y
1
−
y
2
)
2
|AB|\ =\ \sqrt{\left( x_{_1}-x_2 \right) ^2+\left( y_1-y_2 \right) ^2}
∣AB∣ = (x1−x2)2+(y1−y2)2
当扩展到多个点时,再往后延续z,q,w,p等就可以了。
举例
import pandas as pd
data = {'电影名称':['无问西东','后来的我们','前任三','红海行动','唐人街探案','战狼2'],
'打斗镜头':[1,5,12,108,112,115],
'接吻镜头':[101,89,97,5,9,8],
'电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']
}
data = pd.DataFrame(data)
data
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 | |
---|---|---|---|---|
0 | 无问西东 | 1 | 101 | 爱情片 |
1 | 后来的我们 | 5 | 89 | 爱情片 |
2 | 前任三 | 12 | 97 | 爱情片 |
3 | 红海行动 | 108 | 5 | 动作片 |
4 | 唐人街探案 | 112 | 9 | 动作片 |
5 | 战狼2 | 115 | 8 | 动作片 |
ok
接下来输入一条数据
['巴啦啦小魔仙全身边',24,67]
让你写程序判定一下,这是属于爱情片还是属于动作片
#首先计算“小魔仙”到其他各个点之间的距离
xian_movie = [24,67]
xian_movie = list((((data.iloc[:,1:3]-xian_movie)**2).sum(1))**0.5)
xian_movie
[41.048751503547585,
29.068883707497267,
32.31098884280702,
104.4030650891055,
105.39449701004318,
108.45275469069469]
可以看到,我们的"小魔仙"到其它点的距离
之后选取距离最小的k个点,这里我们将k设为4
sorted_data = pd.DataFrame({'movie':xian_movie,'labels':(data.iloc[:6,3])})
sorted_data = sorted_data.sort_values(by = 'movie')[:4]
sorted_data
movie | labels | |
---|---|---|
1 | 29.068884 | 爱情片 |
2 | 32.310989 | 爱情片 |
0 | 41.048752 | 爱情片 |
3 | 104.403065 | 动作片 |
统计出top k,之后我们计算top k 中每个类别出现的次数, 最后选择最高频率的类别作为我们的预测结果
freq = sorted_data.loc[:,'labels'].value_counts()
freq
爱情片 3
动作片 1
Name: labels, dtype: int64
print('巴啦啦小魔仙全身变属于 {} '.format(freq.index[0]))
巴啦啦小魔仙全身变属于 爱情片
however“巴啦啦小魔仙”真的属于爱情片麽?这里面存在很多很多的问题,需要诸位的努力,加油!!!!!!
生活不易,猫猫叹气.
实例
背景介绍:
小美到了要出嫁的年纪,但是并不是每个人都让她喜欢,而有些人又明显不是她的菜。所以小美准备拜托她的青梅竹马兼男闺蜜的单身程序员小白帮她写个程序提前筛选一番。
小白筛选规则如下:
根据
- 每年的飞行里程数
- 玩游戏、视频所占的时间比
- 每周消费的冰淇凌公升数
小白将相亲对象分为
- didntLike--------很不喜欢的人
- smallDoses-------不喜欢的人
- largeDoses-------有点不喜欢的人
import pandas as pd
data = pd.read_table('./data/data45246/datingTestSet.txt',header=None)
print(data.shape)
data.head()
(1000, 4)
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 40920 | 8.326976 | 0.953952 | largeDoses |
1 | 14488 | 7.153469 | 1.673904 | smallDoses |
2 | 26052 | 1.441871 | 0.805124 | didntLike |
3 | 75136 | 13.147394 | 0.428964 | didntLike |
4 | 38344 | 1.669788 | 0.134296 | didntLike |
import matplotlib as mpl
import matplotlib.pyplot as plot
Colors = []
for i in range(data.shape[0]):
m = data.iloc[i,-1]
if m == 'didntLike':
Colors.append('black')
elif m == 'smallDoses':
Colors.append('orange')
elif m == 'largeDoses':
Colors.append('red')
plot.rcParams['font.sans-serif'] = ['Simhei']
pl = plot.figure(figsize = (12,8))
fig1 = pl.add_subplot(221)
plot.scatter(data.iloc[:,1],data.iloc[:,2],marker='.',c = Colors)
plot.xlabel('玩游戏视频所占时间比')
plot.ylabel('每周消费冰淇淋公升数')
fig2 = pl.add_subplot(222)
plot.scatter(data.iloc[:,0],data.iloc[:,1],marker = '.',c = Colors)
plot.xlabel('plane')
plot.ylabel('game & video')
fig3 = pl.add_subplot(223)
plot.scatter(data.iloc[:,0],data.iloc[:,2],marker = '.',c = Colors)
plot.xlabel('plane ')
plot.ylabel('icecream')
plot.show()
第三张图还不是特别的明显,但是看到第二张图我又有想法了,请把你的想法打在回复上。
但是,在本篇文章中,我们只用来观察数据。
我们在上述观察数据的时候发现,飞行里程都是以“万”为单位,但是每周消费的冰淇凌数却很难超过1,
那么造成的影响便是,我们分类的准确性几乎全部取决于较大数值的飞行里程,而较小数值的冰淇凌消费数很难有话语权,
So
我们需要进行”归一化“处理,使得三个特征所占的权重相同。
归一化处理的方式有很多:Sigmod归一化,Z-Score归一化,而我们这里 使用的是最简单的"0-1归一化"。
0-1归一化公式 = (x-min)/(max-min)
def minmax(dataset):
min_d = dataset.min()
max_d = dataset.max()
normdataset = (dataset-min_d)/(max_d-min_d)
return normdataset
data_t = pd.concat([minmax(data.iloc[:,:3]),data.iloc[:,3]],axis=1)
data_t.head()
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0.448325 | 0.398051 | 0.562334 | largeDoses |
1 | 0.158733 | 0.341955 | 0.987244 | smallDoses |
2 | 0.285429 | 0.068925 | 0.474496 | didntLike |
3 | 0.823201 | 0.628480 | 0.252489 | didntLike |
4 | 0.420102 | 0.079820 | 0.078578 | didntLike |
到了划分训练集和测试集的时候了
def randSplit(data,rate = 0.8):
n = data.shape[0]
m = int(n*rate)
train = data.iloc[:m,:]
test = data.iloc[m:,:]
test.index = range(test.shape[0])
return train,test
train,test = randSplit(data_t)
print(train.head())
test.head()
0 1 2 3
0 0.448325 0.398051 0.562334 largeDoses
1 0.158733 0.341955 0.987244 smallDoses
2 0.285429 0.068925 0.474496 didntLike
3 0.823201 0.628480 0.252489 didntLike
4 0.420102 0.079820 0.078578 didntLike
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0.565951 | 0.080003 | 0.431779 | didntLike |
1 | 0.033197 | 0.225597 | 0.412308 | smallDoses |
2 | 0.391080 | 0.492596 | 0.929750 | largeDoses |
3 | 0.016840 | 0.099760 | 0.707143 | smallDoses |
4 | 0.099515 | 0.302984 | 0.667006 | smallDoses |
分类器的构建
def data_classing(trian,test,k):
n = train.shape[1]-1
m = test.shape[0]
result = []
for i in range(m):
dist = list((((train.iloc[:,:n]-test.iloc[i,:n])**2).sum(1))**0.5)
dist1 = pd.DataFrame({'dist':dist,'labels':(train.iloc[:,n])})
dr = dist1.sort_values(by = 'dist')[:k]
re = dr.loc[:,'labels'].value_counts()
result.append(re.index[0])
result = pd.Series(result)
test['predict'] = result
acc = (test.iloc[:,-1]==test.iloc[:,-2]).mean()
print('模型的准确率为{}'.format(acc))
return test
train,test = randSplit(data_t)
print(train.head())
test.head()
data_classing(train,test,5)
0 1 2 3
0 0.448325 0.398051 0.562334 largeDoses
1 0.158733 0.341955 0.987244 smallDoses
2 0.285429 0.068925 0.474496 didntLike
3 0.823201 0.628480 0.252489 didntLike
4 0.420102 0.079820 0.078578 didntLike
模型的准确率为0.945
0 | 1 | 2 | 3 | predict | |
---|---|---|---|---|---|
0 | 0.565951 | 0.080003 | 0.431779 | didntLike | didntLike |
1 | 0.033197 | 0.225597 | 0.412308 | smallDoses | smallDoses |
2 | 0.391080 | 0.492596 | 0.929750 | largeDoses | largeDoses |
3 | 0.016840 | 0.099760 | 0.707143 | smallDoses | smallDoses |
4 | 0.099515 | 0.302984 | 0.667006 | smallDoses | smallDoses |
5 | 0.523090 | 0.394607 | 0.418764 | largeDoses | largeDoses |
6 | 0.781962 | 0.768050 | 0.574250 | didntLike | didntLike |
7 | 0.416114 | 0.082374 | 0.182566 | didntLike | didntLike |
8 | 0.464376 | 0.180935 | 0.516860 | didntLike | didntLike |
9 | 0.248562 | 0.122258 | 0.072347 | didntLike | smallDoses |
10 | 0.432899 | 0.470962 | 0.645680 | largeDoses | largeDoses |
11 | 0.130214 | 0.175873 | 0.918369 | smallDoses | smallDoses |
12 | 0.054167 | 0.467973 | 0.502735 | smallDoses | smallDoses |
13 | 0.802318 | 0.715080 | 0.310177 | didntLike | didntLike |
14 | 0.192664 | 0.534536 | 0.759757 | largeDoses | largeDoses |
15 | 0.753092 | 0.359884 | 0.977555 | didntLike | didntLike |
16 | 0.151392 | 0.251146 | 0.812960 | smallDoses | smallDoses |
17 | 0.346893 | 0.666691 | 0.841321 | largeDoses | largeDoses |
18 | 0.949744 | 0.743678 | 0.843311 | didntLike | didntLike |
19 | 0.473459 | 0.596747 | 0.405673 | largeDoses | largeDoses |
20 | 0.263944 | 0.110773 | 0.832161 | didntLike | didntLike |
21 | 0.575680 | 0.481359 | 0.451476 | largeDoses | largeDoses |
22 | 0.677758 | 0.276884 | 0.952764 | didntLike | didntLike |
23 | 0.524832 | 0.197828 | 0.280246 | didntLike | didntLike |
24 | 0.407459 | 0.618065 | 0.178960 | largeDoses | largeDoses |
25 | 0.065879 | 0.448304 | 0.180738 | smallDoses | smallDoses |
26 | 0.298259 | 0.399695 | 0.969125 | largeDoses | largeDoses |
27 | 0.756270 | 0.379525 | 0.781348 | didntLike | didntLike |
28 | 0.861613 | 0.513180 | 0.415869 | didntLike | didntLike |
29 | 0.331467 | 0.554163 | 0.168224 | largeDoses | largeDoses |
... | ... | ... | ... | ... | ... |
170 | 0.588465 | 0.580790 | 0.819148 | largeDoses | largeDoses |
171 | 0.705258 | 0.437379 | 0.515681 | didntLike | didntLike |
172 | 0.101772 | 0.462088 | 0.808077 | smallDoses | largeDoses |
173 | 0.664085 | 0.173051 | 0.169156 | didntLike | didntLike |
174 | 0.200914 | 0.250428 | 0.739211 | smallDoses | smallDoses |
175 | 0.250293 | 0.703453 | 0.886825 | largeDoses | largeDoses |
176 | 0.818161 | 0.690544 | 0.714136 | didntLike | didntLike |
177 | 0.374076 | 0.650571 | 0.214290 | largeDoses | largeDoses |
178 | 0.155062 | 0.150176 | 0.249725 | smallDoses | smallDoses |
179 | 0.102188 | 0.000000 | 0.070700 | smallDoses | smallDoses |
180 | 0.208068 | 0.021738 | 0.609152 | smallDoses | smallDoses |
181 | 0.100720 | 0.024394 | 0.008994 | smallDoses | smallDoses |
182 | 0.025035 | 0.184718 | 0.363083 | smallDoses | smallDoses |
183 | 0.104007 | 0.321426 | 0.331622 | smallDoses | smallDoses |
184 | 0.025977 | 0.205043 | 0.006732 | smallDoses | smallDoses |
185 | 0.152981 | 0.000000 | 0.847443 | smallDoses | smallDoses |
186 | 0.025188 | 0.178477 | 0.411431 | smallDoses | smallDoses |
187 | 0.057651 | 0.095729 | 0.813893 | smallDoses | smallDoses |
188 | 0.051045 | 0.119632 | 0.108045 | smallDoses | smallDoses |
189 | 0.192631 | 0.305083 | 0.516670 | smallDoses | smallDoses |
190 | 0.304033 | 0.408557 | 0.075279 | largeDoses | largeDoses |
191 | 0.108115 | 0.128827 | 0.254764 | smallDoses | smallDoses |
192 | 0.200859 | 0.188880 | 0.196029 | smallDoses | smallDoses |
193 | 0.041414 | 0.471152 | 0.193598 | smallDoses | smallDoses |
194 | 0.199292 | 0.098902 | 0.253058 | smallDoses | smallDoses |
195 | 0.122106 | 0.163037 | 0.372224 | smallDoses | smallDoses |
196 | 0.754287 | 0.476818 | 0.394621 | didntLike | didntLike |
197 | 0.291159 | 0.509103 | 0.510795 | largeDoses | largeDoses |
198 | 0.527111 | 0.436655 | 0.429005 | largeDoses | largeDoses |
199 | 0.479408 | 0.376809 | 0.785718 | largeDoses | largeDoses |
200 rows × 5 columns
哇
准确率达到了0.945!这么强的麽?
骗你的啦,这是百里挑一的数据集,特别适合CNN,好了,快去试试你的数据集能不能和CNN契合吧!!!!
桥爹妈的
别忘了不要白嫖!