k-近邻算法
算法介绍
-
定义: 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一类别,则该样本也属于这个类别。
-
计算距离公式:欧式距离 (两点之间距离)
-
需要做标准化处理,防止某一类特征值权重过大
-
Sklearn API
- sklearn.neighbors.KNeighborsClassifier
- n 的取值会影响最终结果
算法实例 (Facebook Check in)
解决思路
-
分类:
- 特征值: x,y 坐标, 定位准确性, 年,日,时,周
- 目标值: 入住位置的id
-
处理: 0<x<10 0<y<10
- 由于数据量大,节省时间,x,y 缩小
- 时间戳进行(年,月,日,周,时分秒), 当做新特征
- 少于指定签到人数的位置删除
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import pandas as pd
def knncls():
"""
K-近邻预测用户签到位置
:return: None
"""
# 读取数据
data = pd.read_csv('./train.csv')
# print(data.head(10))
# 处理数据
# 1.缩小数据
data = data.query('x >1.0 & x < 1.25 & y > 2.5 & y < 2.75')
# 2. 处理时间数据
time_value = pd.to_datetime(data['time'], unit='s')
# print(time_value)
# 3. 构造一些特征, 把日期格式转换为字典格式
time_value = pd.DatetimeIndex(time_value)
data['day'] = time_value.day
data['weekday'] = time_value.weekday
data['hour'] = time_value.hour
# 4.把时间戳特征删除
data = data.drop(['time'],axis=1)
# print(data)
# 5.把签到数量少于n个的目标位置删除
place_count = data.groupby('place_id').count() # 统计place_id次数,变成行索引
tf = place_count[place_count.row_id > 3].reset_index() # row_id 具体次数,reset_index 把place_id生成新的一列
data = data[data['place_id'].isin(tf.place_id)] # 筛选place_id
# print(data)
# 6.取出数据中的特征值和目标值
y = data['place_id']
x = data.drop(['place_id', 'row_id'], axis=1) # 去掉row_id 可以增加精度
# 7.分割训练集和测试集
x_train, x_test, y_train, y_text = train_test_split(x, y, test_size=0.25)
# 8.特征工程(标准化)
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 进行算法流程 fit, predict, score #超参数
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(x_train, y_train)
# 得出预测结果
y_predict = knn.predict(x_test)
print('预测的目标签到位置为:', y_predict)
# 得出准确率
print('预测的准确率为:', knn.score(x_test, y_text))
return None
if __name__ == '__main__':
knncls()
总结
问题
-
k值取多大,有什么影响?
- k值取很小:容易受异常点影响
- k值取很大:容易受K值数量(类别)波动
-
性能问题
优缺点
-
优点: 简单,易于理解实现,无需估计参数,无需训练
-
缺点:
- 懒惰算法,对测试样本分类时的计算量打,内存开销大
- 必须指定K值,k值选择不当则分类精度不能保证
-
使用场景:小数据(几千~几万),基本不常用