K-近邻算法预测电影类型

K-近邻算法预测电影类型

k-近邻算法是一种比较简单,但是在一些方面又有很多作用的算法,比较常用的就是推荐入住位置,或者推荐入住酒店等等。

K-近邻算法的原理:就是根据特征值,计算出离自己最近的那个分类,自己也属于那个类别,K-近邻是一种分类的算法模型。

K-近邻算法的公式:(a1-b1)2 + (a2-b2)2 + (a3-b3)2 A(a1,a2,a3) B (b1,b2,b3)
A代表了已知的数据,B代表未知的数据,得出的结果就是未知的数据与已知的距离,也称为欧式距离

获取数据

在机器学习中数据是非常重要的,是取决你的模型是否能够成功的建立起来的重要因素。在这里我的数据是自己在豆瓣上面爬取出来的,如果不懂的爬虫的朋友可以自行百度,或者向我拿数据也是可以的。

| 在这里插入图片描述
这些就是数据,有演员、导演、票房等等。

处理数据

在机器学习中,机器只会识别数字,不能识别字符,所以我们要把这些数据都转换为数字,首先是转换票房,因为这里的票房是有亿、万这些字眼的,所以我们把他转化为数字。

mobie_box_list = []
for i in all_data["mobie_box"]:
    if "亿" in i:
        mobie_box_list.append(float(re.match(r"\d.*\d+",i).group()) * 100000000)
    if "万" in i:
        mobie_box_list.append(float(re.match(r"\d.*\d+", i).group()) * 10000)
all_data["mobie_box"] = mobie_box_list
all_data["mobie_box"] = all_data["mobie_box"].astype("int")

因为这里的每部电影的电影类型都不止一个,所以我们只提取一个类型来预测比较好。

all_data["type"] = [ "".join(i[1:2]) if len(i) > 1 else "".join(i[:1]) for i in all_data["type"].str.split("、")]
print(all_data["type"])

这里有些电影的导演不止一个人,所以我们要把导演给分隔出来,就是有些电影有两个导演,那我们就把导演给分隔出来,然后复制电影信息,然后把分隔出来的导演放进去。

all_data=all_data.drop('director', axis=1).join(all_data['director'].str.split(' / ', expand=True).stack().reset_index(level=1, drop=True).rename('director'))

对地区进行分类处理

n = 0
dict_10 = {}
country_list = list(set(all_data["country"].tolist()))
for z in country_list:
    dict_10[z] = n
    n +=1
print(dict_10)
all_data["country"] = all_data["country"].map(dict_10)

因为暂时没想到比较好的办法来处理演员数据,所以在模型建立的时候,把演员从特征值中删除掉。

数据处理源代码

'''
K-近邻预测电影类型
creat on July 21,2019
@Author 小明
'''
'''
1、处理数据
2、特征工程
3、数据集划分
4、建立模型
5、调整模型
'''
import pandas as pd
from matplotlib.pylab import date2num
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.feature_extraction import DictVectorizer
from sklearn.preprocessing import FunctionTransformer
import datetime
import re
pd.set_option("display.max_columns",1000)
pd.set_option("display.width",500)
pd.set_option("display.max_colwidth",10000)

#处理数据
data_1 = pd.read_csv("I:/crack/DATA/movie_datadouban.csv")
data_1.index.name = "id"
data_2 = pd.read_csv("I:/crack/DATA/movie_datadouban_2.csv")
data_3 = pd.read_csv("I:/crack/DATA/movie_datadouban_3.csv")
data = pd.merge(data_3,data_2,how="outer")
all_data = pd.merge(data,data_1,how="outer")

data_4 = pd.read_csv("I:/crack/DATA/movie_data2009.csv")
data_5 = pd.read_csv("I:/crack/DATA/movie_data2010.csv")
data_6 = pd.read_csv("I:/crack/DATA/movie_data2011.csv")
data_7 = pd.read_csv("I:/crack/DATA/movie_data2012.csv")
data_8 = pd.read_csv("I:/crack/DATA/movie_data2013.csv")
data_9 = pd.read_csv("I:/crack/DATA/movie_data2014.csv")
data_10 = pd.read_csv("I:/crack/DATA/movie_data2015.csv")
data_11 = pd.read_csv("I:/crack/DATA/movie_data2016.csv")
data_12 = pd.read_csv("I:/crack/DATA/movie_data2017.csv")
data_13 = pd.read_csv("I:/crack/DATA/movie_data2018.csv")
d_1 = pd.merge(data_4,data_5,how="outer")
d_2 = pd.merge(d_1,data_6,how="outer")
d_3 = pd.merge(d_2,data_7,how="outer")
d_4 = pd.merge(d_1,data_8,how="outer")
d_5 = pd.merge(data_9,data_10,how="outer")
d_6 = pd.merge(data_11,data_12,how="outer")
d_7 = pd.merge(d_4,d_5,how="outer")
d_8 = pd.merge(d_7,d_6,how="outer")
d_9 = pd.merge(d_8,data_13,how="outer")
all_d = d_9.loc[:,["title","mobie_box","history_rank"]]
all_data = pd.merge(all_data,all_d,on=["title","title"])
pd.DataFrame.to_csv(all_data,"I:/crack/DATA/all_movies.csv",encoding="utf_8_sig")

#转换票房数据
mobie_box_list = []
for i in all_data["mobie_box"]:
    if "亿" in i:
        mobie_box_list.append(float(re.match(r"\d.*\d+",i).group()) * 100000000)
    if "万" in i:
        mobie_box_list.append(float(re.match(r"\d.*\d+", i).group()) * 10000)
all_data["mobie_box"] = mobie_box_list
all_data["mobie_box"] = all_data["mobie_box"].astype("int")

#截取电影类型
all_data["type"] = [ "".join(i[1:2]) if len(i) > 1 else "".join(i[:1]) for i in all_data["type"].str.split("、")]
print(all_data["type"])


#把导演分开出来
all_data=all_data.drop('director', axis=1).join(all_data['director'].str.split(' / ', expand=True).stack().reset_index(level=1, drop=True).rename('director'))
print(all_data)

#把演员转换成列表形式
# all_data = all_data.drop('actor', axis=1).join(all_data['actor'].str.split(' / ', expand=True).stack().reset_index(level=1, drop=True).rename('actor'))
# print(all_data)

#时间戳处理
# time = pd.DatetimeIndex(all_data["release_time"])
# all_data["year"] = time.year
# all_data["month"] = time.month
# all_data["day"] = time.day
# all_data = all_data.drop(["release_time"],axis = 1)
# all_data = all_data.drop(["actor"],axis = 1)
all_data["release_time"] = pd.to_datetime(all_data["release_time"])
all_data["release_time"] = date2num(all_data["release_time"])
all_data["release_time"] = all_data["release_time"].astype("int")

#特征工程
vector = DictVectorizer(sparse=False)
director_list = []
# for z in all_data["director"]:
#     dict = {}
#     dict["director"] = z
#     director_list.append(dict)
# director = vector.fit_transform(director_list)
# all_data["director"] = director

#将地区进行分类
n = 0
dict_10 = {}
country_list = list(set(all_data["country"].tolist()))
for z in country_list:
    dict_10[z] = n
    n +=1
print(dict_10)
all_data["country"] = all_data["country"].map(dict_10)

#对电影类型进行分类处理
# j = 0
# dict_9 = {}
# country_list = list(set(all_data["type"].tolist()))
# for z in country_list:
#     dict_9[z] = j
#     j +=1
# print(dict_9)
# all_data["type"] = all_data["type"].map(dict_9)

d = 0
dict_8 = {}
country_list = list(set(all_data["director"].tolist()))
for z in country_list:
    dict_8[z] = d
    d +=1
print(dict_8)
all_data["director"] = all_data["director"].map(dict_8)
pd.DataFrame.to_csv(all_data,"I:/crack/DATA/K-movie.csv",encoding="utf_8_sig")

模型建立

模型建立的步骤
1、读取数据
2、划分特征值和目标值
3、标准化处理
4、划分数据集
5、建立模型
6、模型评估

读取数据和划分特征值和目标值

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA

data = pd.read_csv("I:crack/DATA/K-movie.csv")

#划分数据集
target = data["type"]
featrue = data.loc[:,["comment_number","country","play_time","release_time","score","mobie_box","history_rank","director"]]

标准化处理

因为防止某一特征值的数据对目标值的影响过大,所以要进行标准化处理

st = StandardScaler()
featrue = st.fit_transform(featrue)

划分测试集和训练集

train_x,test_x,train_y,test_y = train_test_split(featrue,target,test_size=0.25)

train_x就是训练集的特征值
test_x就是测试集的特征值
train_y就是训练集的目标值
test_y就是测试集的目标值

test_size就是代表测试集占的比例

建立模型

kn = KNeighborsClassifier(n_neighbors=6,algorithm="auto")
kn.fit(train_x,train_y)

predict_y = kn.predict(test_x)

score = kn.score(test_x,test_y)

print(score)

n_neighbors代表提取分数最下的几个来预测,algorithm是用来对数据结构进行调优的,默认都是auto的

运行得出来的结果

在这里插入图片描述
得出来的准确率只有0.365,而且每次运行的准确率都是不一样的,那是因为每次测试集和训练集都是随机分隔的,所以结果不一样。

交叉验证

上面得出准确率这么低,难道这个项目就失败了吗?模型就失败了吗?不一定,因为还有一个K值的调优,只有我们把K值调到最优才能看到模型的准确率

交叉验证的原理:交叉验证就是先把训练集分为n等份,然后提取一部分当做验证集,然后对验证集进行预测,每次预测的结果都保留下来,然后把这些结果进行取平均值,因为有些模型是需要传递超参数的,比如K-近邻算法的K值,然后把每个可能的K-值放进去一一验证,就会得出最好的超参数的值,
网格搜索:网格搜索就是,有一些模型的超参数不知一个,然后网格搜索就会把这些参数都一一验证,得出最好的超参数

注意:交叉验证也可以得出测试集的预测值,和预测结果

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV

data = pd.read_csv("I:crack/DATA/K-movie.csv")

#划分数据集
target = data["type"]
featrue = data.loc[:,["comment_number","country","play_time","score","mobie_box","history_rank","director"]]
print(target)

#标准化
st = StandardScaler()
featrue = st.fit_transform(featrue)

#划分数据集
train_x,test_x,train_y,test_y = train_test_split(featrue,target,test_size=0.25)

#特征工程标准化
sta = StandardScaler()
train_x = sta.fit_transform(train_x)
test_x = sta.fit_transform(test_x)

#建立模型
kn = KNeighborsClassifier()
# kn.fit(train_x,train_y)
#
# predict_y = kn.predict(test_x)
#
# score = kn.score(test_x,test_y)
# print(score)

#建立交叉验证的对象
gri = GridSearchCV(kn,param_grid={"n_neighbors":[1,2,3,4,5,6,7,8,9],"algorithm":["auto","ball_tree","kd_tree"]},cv=10)

#这里把全部数据都当做训练集,因为数据量不多
gri.fit(featrue,target)

#打印测试集的准确率,这个值是所有结果中最好的结果,就是每个参数10次运行结果的最好结果
print(gri.score(test_x,test_y))

#打印最好的验证结果,就是最好的准确率平均值
print(gri.best_score_)

#打印最好的参数
print(gri.best_estimator_)

# 打印每个参数的每次预测的结果
print(gri.cv_results_)

打印最好结果的平均值
在这里插入图片描述

打印最好的参数值
KNeighborsClassifier(algorithm=‘auto’, leaf_size=30, metric=‘minkowski’,
metric_params=None, n_jobs=None, n_neighbors=3, p=2,
weights=‘uniform’)

召回率和精准率和F1值

上面看到最好的平均值结果才0.31,难道这个模型就彻底没救了吗?也不是,我可以来看来每个分类的召回率和精准率和F1值

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.decomposition import PCA

data = pd.read_csv("I:crack/DATA/K-movie.csv")

#划分数据集
target = data["type"]
featrue = data.loc[:,["comment_number","country","play_time","score","mobie_box","history_rank","director"]]


#标准化
st = StandardScaler()
featrue = st.fit_transform(featrue)

#划分数据集
train_x,test_x,train_y,test_y = train_test_split(featrue,target,test_size=0.25)

#特征工程标准化
sta = StandardScaler()
train_x = sta.fit_transform(train_x)
test_x = sta.fit_transform(test_x)

#建立模型
kn = KNeighborsClassifier(n_neighbors=5,algorithm="auto")
kn.fit(train_x,train_y)

predict_y = kn.predict(test_x)

score = kn.score(test_x,test_y)

class_data = list(set(test_y.tolist()))
print(class_data)
all_class = list(set(target.tolist()))
#传递的参数,y_true传递的是测试集的目标值,y_pred传递的是预测结果,target_names传递的是测试集的目标值的分类数据,labels传递的是分类索引的索引列表,也就是说target_names上面显示的名称都是从labels里面得来的。
print(classification_report(y_true=test_y,y_pred=predict_y,target_names=class_data,labels=class_data))

#返回的结果就是精确值、召回率、F1值、和每个类别在测试集中的真实数量

动作 0.24 0.36 0.29 11
歌舞 0.00 0.00 0.00 2
灾难 0.00 0.00 0.00 1
爱情 0.50 0.14 0.22 7
悬疑 0.00 0.00 0.00 5
喜剧 0.67 0.33 0.44 6
犯罪 0.00 0.00 0.00 3
同性 0.00 0.00 0.00 1
科幻 0.29 0.25 0.27 8
动画 0.50 0.92 0.65 12
剧情 0.29 0.50 0.36 4
音乐 0.00 0.00 0.00 1
西部 0.00 0.00 0.00 1
武侠 0.00 0.00 0.00 1
传记 0.17 0.25 0.20 4
奇幻 0.00 0.00 0.00 4
冒险 0.17 1.00 0.29 1
家庭 0.00 0.00 0.00 4
惊悚 0.00 0.00 0.00 4

这里可以看到这个模型对动画和冒险者这两个分类还是效果的,所以也证明了这个模型也不是一文不值的。

总结

这个模型的准确率这么低,不外乎几个原因:

1、数据量太小,不足以用来预测和分析
2、数据的价值太低,预测的结果不理想
3、数据处理的方法太差,没能发挥数据的价值,就像演员数据不能发挥作用
4、特征工程的处理方法不好,所以导致模型结果不理想。

我相信只要解决掉上面的问题,模型的准确率也会大大提高的。

有什么不懂的地方可以加我的QQ 1693490575 问我,或者有什么好的建议或者模型方法,也欢迎跟我探讨一下。

发布了28 篇原创文章 · 获赞 14 · 访问量 6786

猜你喜欢

转载自blog.csdn.net/weixin_42304193/article/details/97309989
今日推荐