《歌手》决赛排名预测之技术篇

上一篇文章预测了《歌手》排名和候选“歌王”,大多数人是看个热闹而看不到门道,也许你们认为我们是凭空胡诌,而这一篇干货满满的文章,我们从技术角度出发,用详实的数据和详尽的方法来说话,给大家展示一下复杂的预测过程,这可不是随随便便的忽悠——

定义问题

首先,明确我们要解决的问题是什么?是预测——准确来说是用机器学习的方法进行预测。预测什么呢?歌王,还是歌手决赛排名?其实都可以。预测歌王的话,标签就会二值化,可以使用逻辑回归等模型;预测排名的话,标签就会连续化,可以使用回归模型(当然也可以把标签当成离散数据,再使用分类模型预测)。为了更丰富,我们将问题定义为用机器学习算法预测歌手决赛排名。

数据准备

1、数据获取

“巧妇难为无米之炊。”数据准备是跑模型的前提。那么,要获取什么数据?换句话说,要如何设计歌手的特征维度?我认为夺冠几率与歌手的国籍(地域)、资历每期比赛的排名相关。最后,我们打算根据以下特征获取数据:


特征

备注

Name

歌手名

Season

第几季

isTeam

个人or团队

isStart

首发or补位or踢馆or逆战or挑战

Gender

男or女or混合

Location

歌手国籍(地域)

Age

歌手资历(参赛年份- 出道年份)

Ranking_per_game

每期比赛排名(共12个特征)

Ranking

决赛排名(标签)

那么,如何获取这些数据呢?网上并没有数据源可以直接下载或抓取。我决定采取手动抓取数据的技术,将数据整理储存到一张csv表格里面。

下图是部分数据截图:

《歌手》决赛排名预测之技术篇插图


2、数据预处理

1)缺失值处理

原始数据中存在很多缺失值,因为绝大部分歌手不是每期都参加。如何处理这些缺失值呢?总不能把包含缺失值的数据都删了,这样就一条不剩了,我决定用一个不会跟排名撞到的数字13代替缺失值。

2)离散值处理

数据当中,如性别、地域这些离散型特征数据是无法直接丢进模型里面跑的。我们需要先把它们编码成数字。我们使用sklearn里面的preprocessing模块的

LabelEncoder:

from sklearn import preprocessing as pre

le = pre.LabelEncoder()

data_encode[‘gender’] = le.fit_transform(data_origin[‘gender’])   

以上代码是将性别数据编码的例子。

经过数据预处理,理论上可以套模型了。我迫不及待地套了几个模型,发现效果都很烂。(我用前三季作为训练数据,第四季作为预测数据。)这迫使我不得不进入到特征工程的环节。


特征工程


坊间流传一句话:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。可见特征工程的重要性!

1、特征生成

我猜测前面将每一期的排名作为一个特征的做法欠妥。一来是因为这些都是“平行特征”,携带的信息量不大;二来是因为这样做存在大量缺失值,很难处理。为了解决这个问题,我决定生成一组新的特征来描述这12期的排名情况。它们分别是:


特征

备注

Mean

排名平均值

Std

排名标准差

Count

常规赛参加期数

Median

排名中位数

Mad

平均绝对离差

Var

方差

Min

最好排名

Max

最差排名

1_count

问鼎第一的次数

下图是特征替换后的部分数据截图:(几乎解决缺失值问题。剩下的标签缺失值还是用13代替。)

《歌手》决赛排名预测之技术篇插图1

2、特征相关性分析

下面,我们计算了两两变量(特征)之间的相关系数矩阵,来全面分析特征之间的关系

《歌手》决赛排名预测之技术篇插图2

先看特征1(决赛排名)这列。相关系数绝对值大于0.5的特征如下:

8:平均值,10:参加期数,11:中位数,14:最高排名,15:最低排名,16:第一次数

其中排名平均值和中位数更是超过0.7。可见平均值真是一个神指标。而懂点数学的人都知道,中位数在很多情况下其实接近于平均数。查找平均值和中位数的相关系数,发现高达0.935。

参加期数的系数是-0.547,意味着在场上待越久,决赛排名越靠前。有点像歌手定位这个特征。

最高/低排名表示了歌手水平的上/下限,这个与中位数(表示“中限”)一样,都是与决赛排名呈正相关。

3、特征选择

那么,我们就选择这些高相关系数的特征进行模型的训练就行了吗?不是的。我们看看平均值与其他特征的相关性,发现刚刚分析的几个特征不但与决赛排名(标签)相关性高,而且与平均值的相关性也很高!这些叫做冗余特征,对训练模型益处不大。

问题来了,那要如何找到特征的最佳搭配呢?这个问题让人来想是难的,只能靠猜;但是让计算机来“想”,却很简单,因为计算机可以把所有特征搭配的可能都试一遍,看看哪个效果最好,也就是所谓的“暴力法”。

from sklearn.feature_selection import RFE

clf = RandomForestRegressor(n_estimators=50, max_depth=14)

selector = RFE(clf, 1, step=1)

selector = selector.fit(data_encode.ix[:,3:], data_encode.ix[:,1])

print selector.ranking_


以上代码是使用随机森林算法时的遍历特征选择,最后输出特征重要程度的排序。例如你想取k个特征,那么排序中top k个特征搭配会是效果最佳的。注意,不同算法的特征排名不一样。

Step 1: 模型训练

数据准备好了,特征工程也做了,可以训练模型了。我先后尝试了线性回归、决策树、SVM、朴素贝叶斯和随机森林五个模型。最后选择了随机森林。这里我主要介绍使用随机森林建模的过程。

Step 2: 初探随机森林

在尝试了一系列常用模型都不满意后,我将希望寄托在随机森林上。周志华教授在他著名的西瓜书上说:“随机森林简单、容易实现、计算开销小,令人惊奇的是,它在很多现实任务中展现出强大的性能,被誉为‘代表集成学习技术水平的方法’。

随机森林真的跟决策树有关系!它的精髓在于“多样性”。随机森林先随机抽取原数据集(从数据和特征两个方面),生成很多子数据集。然后用子数据集训练出很多个决策树,再用每个决策树预测结果,最后取结果的众数作为最终结果!

《歌手》决赛排名预测之技术篇插图3

(因为随机森林是取所有预测结果的平均数,所以预测排名是小数。)

这个结果还不错,冠军预测对了,前三对了两位。但还是不太理想,实际第二的张信哲被预测成第四,实际第四的老狼被预测成第七。

Step 3:分层随机森林

根据我对《歌手》这个节目的理解,前三名的名次比较重要,后面的排名不太要紧,例如第四季直接用年度六强来取代4~6名。所以我想到一个分层预测模型:

1、把歌手的标签从排名变成等级,先预测出第一等(前三),和第二等(后四or后五)。

2、  再用回排名标签分别预测具体的排名。

看看效果如何:

《歌手》决赛排名预测之技术篇插图4

哇塞!虽然张信哲的预测排名是2.06,可以说是第二等,但是不要紧,他是排在第三位,就是他会被分到前三这一等!这样一来,分层模型已经成功了一半!再看看第二轮预测:

“上层预测”:

《歌手》决赛排名预测之技术篇插图5

“下层预测”:

《歌手》决赛排名预测之技术篇插图6

前三全部预测准确!!!


预测

最后,我们使用分层随机森林模型对第五季歌手决赛排名进行预测:

“上层预测”:

《歌手》决赛排名预测之技术篇插图7

“下层预测”:                                                                              

《歌手》决赛排名预测之技术篇插图8


(更多有趣分析详见头条姐妹篇文章,谢谢大家

点赞