赛题详情:
一、赛事背景
讯飞开放平台针对不同行业、不同场景提供相应的AI能力和解决方案,赋能开发者的产品和应用,帮助开发者通过AI解决相关实际问题,实现让产品能听会说、能看会认、能理解会思考。
用户新增预测是分析用户使用场景以及预测用户增长情况的关键步骤,有助于进行后续产品和应用的迭代升级。
二、赛事任务
本次大赛提供了讯飞开放平台海量的应用数据作为训练样本,参赛选手需要基于提供的样本构建模型,预测用户的新增情况。
三、评审规则
1.数据说明
赛题数据由约62万条训练集、20万条测试集数据组成,共包含13个字段。其中uuid为样本唯一标识,eid为访问行为ID,udmap为行为属性,其中的key1到key9表示不同的行为属性,如项目名、项目id等相关字段,common_ts为应用访问记录发生时间(毫秒时间戳),其余字段x1至x8为用户相关的属性,为匿名处理字段。target字段为预测目标,即是否为新增用户。
2.评估指标
本次竞赛的评价标准采用f1_score,分数越高,效果越好。评估代码参考:
知识点学习
lightgbm
LightGBM(Light Gradient Boosting Machine)是一种基于梯度提升框架的机器学习算法。它由微软开发,以其高效性和高性能而闻名,相比其他梯度提升库更受青睐。
当涉及到机器学习算法中的梯度提升框架时,LightGBM是一种备受欢迎的选择。以下是关于LightGBM的更详细解释:
- 梯度提升框架: LightGBM属于一种梯度提升框架,这意味着它是一种集成学习方法,通过多个弱学习器的组合来构建一个强大的预测模型。它逐步迭代地训练一系列的决策树模型,并通过将每个新的树模型的预测结果与真实值之间的残差进行学习,来不断改进模型的表现。
- 回归和分类问题: LightGBM适用于回归和分类问题。对于回归问题,它通过拟合残差来逐步逼近目标值。对于分类问题,它使用指定的损失函数来优化模型。
- 基于树的学习算法: LightGBM使用基于树的学习算法来构建模型。它采用了一种叶子生长策略,称为叶子生长算法。与传统的层级生长算法不同,LightGBM通过选择具有最大损失下降的叶子节点来生长树,从而减少了树的深度,提高了模型的效率。
- 特征选择和绑定: LightGBM实现了基于梯度的单边采样(GOSS)技术,用于进行特征选择。它根据特征的梯度来选择具有重要性的特征样本,从而减少了内存使用和训练时间。此外,LightGBM还支持独立特征绑定,可以将一组具有排他性的特征作为一个组合特征进行处理,从而提高模型的效率。
- 并行和GPU学习: LightGBM支持并行学习和GPU加速。它可以利用多核处理器和GPU来并行处理数据和模型训练,从而显著提高了训练速度。
- 高性能和内存效率: LightGBM以其高性能和内存效率而闻名。通过使用GOSS技术、叶子生长策略和并行学习,LightGBM在大规模数据集和特征空间中表现出色。它可以处理数百万个样本和数千个特征,并提供准确且快速的预测。
F1分数
F1分数是一种常用的综合评估指标,主要用于衡量分类模型的性能。它结合了模型的准确率(Precision)和召回率(Recall),能够更全面地评估模型的分类能力。
F1分数的计算方式:
- 首先,计算模型的准确率(Precision),即正确预测为正例的样本数(True Positives)除以所有预测为正例的样本数(True Positives + False Positives)。准确率表示了模型在预测为正例的样本中有多少是真正的正例。
- 然后,计算模型的召回率(Recall),即正确预测为正例的样本数(True Positives)除以真实正例的样本数(True Positives + False Negatives)。召回率表示了模型正常识别正例的能力。
- 最后,使用准确率和召回率的调和平均数来计算F1分数,公式为:2 * (Precision * Recall) / (Precision + Recall)。F1分数衡量了模型准确性和召回能力的平衡情况,数值越高表示模型性能越好。
F1分数的取值范围在0到1之间,其中1表示最佳性能,0表示最差性能。当模型的准确率和召回率都很高时,F1分数会接近1。然而,如果准确率和召回率存在较大差异,F1分数将较低,这说明模型在正负类之间的平衡性较差。
F1分数在二分类问题中特别有用,特别是当正负样本之间存在不平衡情况时。当数据集中正负样本比例差异较大时,仅使用准确率作为评估指标可能会导致误导。通过使用F1分数,可以更好地判断模型在少数类别上的性能,并避免过度关注准确率或召回率的问题。
F1分数的含义和应用:
-
准确率(Precision):准确率是指模型预测为正例的样本中,真正是正例的比例。准确率度量了模型正确预测为正例的能力,即预测的阳性样本中有多少是真正的阳性样本。较高的准确率表示模型在预测正例上具有较少的误差。
-
召回率(Recall):召回率也被称为灵敏度(Sensitivity)或真正例率(True Positive Rate),它是指模型正确预测为正例的样本数占真实正例样本总数的比例。召回率衡量了模型识别真正例的能力,即能够正确找出多少真实阳性样本。较高的召回率表示模型对于正例的识别能力较强。
-
F1分数:F1分数是准确率和召回率的调和平均值,可以综合考虑模型在准确率和召回率之间的平衡性。F1分数的计算公式为2 * (Precision * Recall) / (Precision + Recall)。F1分数的取值范围在0到1之间,值越接近1表示模型性能越好。
- 当准确率和召回率相等时,F1分数达到最大值1,表示模型在阳性和阴性样本的分类上表现出较好的平衡。
- 当准确率和召回率有较大差距时,F1分数较低,这意味着模型在正例和反例的分类上存在不平衡,性能较差。
-
处理不平衡数据集:在某些情况下,数据集中的正例和反例之间可能存在显著的不平衡,即一个类别的样本数量明显多于另一个类别。此时,仅使用准确率作为评估指标可能会导致误导,因为模型可能会倾向于将所有样本都预测为多数类别,从而获得较高的准确率。F1分数对于处理不平衡数据集非常有用,因为它将同时考虑正例和反例的预测能力。
-
阈值选择:在计算F1分数时,通常需要将连续的预测概率或分数转换为二进制分类结果。这需要选择一个阈值,将概率或分数大于阈值的样本划分为正例,小于阈值的划分为反例。阈值的选择将影响准确率、召回率和F1分数的计算结果。
- 如果更关注准确识别正例,可以选择较高的阈值,从而减少误分类的反例,提高准确率但可能降低召回率。
- 如果更关注捕捉所有正例,可以选择较低的阈值,从而增加将真实正例识别出来的能力,提高召回率但可能降低准确率。
- 在某些情况下,可能需要根据具体需求进行阈值的调整,以取得最佳的准确率和召回率平衡。
交叉验证
交叉验证是一种用于评估机器学习模型性能的技术。它将数据集分成若干个子集,其中一个子集被保留作为验证集,其余的子集用于训练模型。然后,使用验证集来评估模型的性能指标,例如准确度、精确度或 F1 分数。
交叉验证的目的是通过多次重复随机划分数据集来减小模型性能评估的偏差。常用的交叉验证方法有 k 折交叉验证和留一法交叉验证。在 k 折交叉验证中,数据集被分成 k 个子集,然后每个子集依次作为验证集,其余的 k-1 个子集作为训练集。最后,将 k 次验证结果的平均值用作模型的性能评估。
交叉验证可以帮助选择最佳的模型超参数、比较不同模型的性能或检测模型的过拟合情况。它是一个常用且有效的评估机器学习模型的方法。
再通过运行Baseline中的交叉验证模块后,得出了以下的结果:
# 训练并验证SGDClassifier
precision recall f1-score support
0 0.863 0.976 0.916 533155
1 0.254 0.050 0.084 87201
accuracy 0.846 620356
macro avg 0.558 0.513 0.500 620356
weighted avg 0.777 0.846 0.799 620356
# 训练并验证DecisionTreeClassifier
precision recall f1-score support
0 0.934 0.940 0.937 533155
1 0.618 0.593 0.605 87201
accuracy 0.891 620356
macro avg 0.776 0.767 0.771 620356
weighted avg 0.889 0.891 0.890 620356
# 训练并验证MultinomialNB
precision recall f1-score support
0 0.893 0.736 0.807 533155
1 0.221 0.458 0.298 87201
accuracy 0.697 620356
macro avg 0.557 0.597 0.552 620356
weighted avg 0.798 0.697 0.735 620356
# 训练并验证RandomForestClassifier
precision recall f1-score support
0 0.921 0.955 0.938 533155
1 0.645 0.501 0.564 87201
accuracy 0.891 620356
macro avg 0.783 0.728 0.751 620356
weighted avg 0.882 0.891 0.885 620356
可以看出训练集没有欠拟合的问题,而且估计的f1_score 相对准确,其中RandomForestClassifier模型的表现最好
知识点补充:
classification_report()函数:python在机器学习中常用的输出模型评估报告的方法。
classification_report( y_true, y_pred, labels=None, target_names=None, sample_weight=None, digits=2, output_dict=False, zero_division=“warn” )
| 参数 | 描述 |
|---|---|
| y_true | 真实值 ,一维数组形式(也可以是列表元组之类的) |
| y_pred | 预测值,一维数组形式(也可以是列表元组之类的) |
| labels | 标签索引列表,可选参数,数组形式 |
| target_names | 与标签匹配的名称,可选参数,数组形式 |
| sample_weight | 样本权重,数组形式 |
| digits | 格式化输出浮点值的位数。默认为2。当“output_dict”为“True”时,这将被忽略,并且返回的值不会四舍五入。 |
| output_dict | 是否输出字典。默认为False,如果为True则输出结果形式为字典。 |
| zero_division | 设置存在零除法时返回的值。默认为warn。如果设置为“warn”,这相当于0,但也会引发警告。 |
- precisoin即准确率,也称查准率。 预测结果是该标签的样例中,实际是该标签的所占比。
- recall是召回率 ,也称查全率, 预测结果是该标签的样例中,实际是该标签的所占比。
- f1-score简称F1
可视化分析
下面进行可视化分析,代码如下:
import seaborn as sns
#读取训练集
train_data = pd.read_csv('test_data.csv')#读取训练集
# 相关性热力图
sns.heatmap(train_data.corr().abs(), cmap='YlOrRd')
# key9_mean分组下标签均值
sns.barplot(x='key9_mean', y='target', data=train_data)
# 其中key9mean可以随意更换为其他变量
特征工程
代码块:
import pandas as pd
import numpy as np
from sklearn.metrics import precision_score,recall_score,f1_score
from sklearn.datasets import make_classification
from imblearn.over_sampling import RandomOverSampler,SMOTE
from collections import Counter
from sklearn.model_selection import learning_curve
train_data['eid_freq'] = train_data['eid'].map(train_data['eid'].value_counts())
test_data['eid_freq'] = test_data['eid'].map(train_data['eid'].value_counts())
train_data['eid_mean'] = train_data['eid'].map(train_data.groupby('eid')['target'].mean())
test_data['eid_mean'] = test_data['eid'].map(train_data.groupby('eid')['target'].mean())
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
def hours_feature(x):
if x>=5 and x<=16:
return 1
else:
return 0
train_data['hour_feature']=train_data['common_ts_hour'].apply(hours_feature)
test_data['hour_feature']=test_data['common_ts_hour'].apply(hours_feature)
train_data['common_ts_day'] = train_data['common_ts'].dt.day
test_data['common_ts_day'] = test_data['common_ts'].dt.day
'''
def day_feature(x):#新增
if x==6:
return 1
elif x==7:
return 0.2
else:
return 0
train_data['day_feature']=train_data['common_ts_day'].apply(day_feature)
test_data['day_feature']=train_data['common_ts_day'].apply(day_feature)
'''
train_data['hour_freq']=train_data['common_ts_hour'].map(train_data['common_ts_hour'].value_counts())
test_data['hour_freq']=test_data['common_ts_hour'].map(test_data['common_ts_hour'].value_counts())
train_data['hour_mean']=train_data['common_ts_hour'].map(train_data.groupby('common_ts_hour')['target'].mean())
test_data['hour_mean']=test_data['common_ts_hour'].map(train_data.groupby('common_ts_hour')['target'].mean())
train_data.to_csv("changed.csv",index=None)
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import classification_report
from sklearn.tree import DecisionTreeClassifier
pred = cross_val_predict(
DecisionTreeClassifier(),
train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
train_data['target']
)
print(classification_report(train_data['target'], pred, digits=3))
clf = DecisionTreeClassifier()
clf.fit(
train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1),
train_data['target']
)
pred=clf.predict(train_data.drop(['udmap', 'common_ts', 'uuid', 'target'], axis=1))
precision=precision_score(train_data["target"],pred)
recall=recall_score(train_data["target"],pred)
f1_score=f1_score(train_data["target"],pred)
print(precision)
print(recall)
print(f1_score)
result_df = pd.DataFrame({
'uuid': test_data['uuid'],
'target': clf.predict(test_data.drop(['udmap', 'common_ts', 'uuid'], axis=1))
})
result_df.to_csv('submit.csv', index=None)
在添加特征时发现,x3与x4有NAN值,需要进行数据预处理,这里我使用众数进行填充。 加入了额外的四个特征分别为:hour_feature、day_feature、hour_freq和hour_mean,添加后模型有略微提升,且在尝试中发现common_ts_day特征与x4,x8在加入时会导致评分下降。
最终在使用随机数森林模型后跑出了0.7的成绩。