用户偏好类结构化数据分析题参赛总结


前言

  参加了某运营商举办的系列比赛连续获奖,比赛登录公司内部账号,可直接操作内部真实业务数据(脱敏后),在真实生产环境中建模。作为外行,这是我第一次知道机器学习在真实生产中是怎么应用的,这里把参赛的技术要点总结一下。

一、任务简介

  任务是根据运营商提供的用户数据来分析用户偏好。数据id为手机号码(脱敏,看不到真实号码),主要数据包括每id的消费记录、通话记录、上网记录、APP使用记录、手机配置、用户属性(职业、收入、家庭等)、GPS轨迹等等。需要分析的偏好比如是否近期更换手机,是否近期安装ETC等等。

二、数据处理

1.使用Hadoop、spark抽取相关数据到本地
2.使用HiveSQL把有用字段提取后合并成一个以id为索引的大表
我习惯用pandas处理数据,它非常灵活高效,所以先用HiveSQL把数据全装到一个大表再传给建模平台用pandas处理,注意平台自动把竖杠"|"作为分隔符,所以HiveSQL提取字段时需要把每字段每记录中包含“|”的字符去掉,否则会造成串列。
3.使用pandas读取大表,通过可视化、统计等方法检验每字段的数据类型、异常值情况、分布规律等
4.滤掉高相关、重复、仅有单一值、伪id(即和Id一一对应且为字符)字段
5.填充缺失值。
根据各字段含义可按照平均值、众数、前月份值、新字符等填充。
6.字符类字段编码
字符类不便于后续特征工程处理,所以要编码,使用sklearn.preprocessing.LabelEncoder编码

三、特征工程

  特征工程的原则是:全面撒网、重点捕捞。就是说开始要尽量多做特征,批量创建多种特征,然后再对特征进行筛选,保留有用的特征。

1.尽量多做特征

第一类:id对应类特征,每id一条记录的字段类都可以直接作为特征
第二类:按id分组统计类,有的字段每id会有多条记录,例如通话时长。可以按照id分组后,统计次数、总和、最大最小值、均值、方差等
第三类:时序类字段的统计特征,例如各月的消费金额,可求取时序序列的最大最小值、均值、方差、偏度、峰度等
第四类:热线访问类,根据样本标签分离出阳性标签集和阴性标签集,可以统计出某些字段阳性标签对应的热线类别,例如app登录记录在安装ETC用户中排行前几的app被认为是热线app,然后再统计每id访问热线的次数、时长等指标作为特征。热线的定义除了根据阳性标签外,还可以根据阳性阴性比等其他指标定义。
第五类:根据场景和语义构造符合人类思维的特殊特征。这种特征往往比较有效。

2.特征筛选

  在构造特征时应根据原始字段名、构造方法等制定一个规范的命名规则,这样便于筛选的时候进行批量选择。筛选的主要方法就是根据验证集上的评价指标得分情况筛选,应该编制一个自动筛选代码,充分发挥算力优势,让电脑日夜不停的跑,自己去睡觉就行了。特征筛选完成后,还应再回到数据处理的代码部分,把那些被筛掉的特征相关的处理环节全部删除,这样可以大大加快数据处理的速度,毕竟模型建立以后工程上以后是要长期反复使用的,速度也是很重要的一个指标。

3.根据特征重要性排序获得启发,构造更多特征

  做特征和筛选特征是一个循环往复的过程,筛选的特征可以根据树模型的特征重要性排序功能得到贡献最大的一些特征,然后受这些特征启发,类比联想构造更多特征。

四、模型训练及预测

  我一般使用lightgbm建模,它速度快,用起来很爽。建模过程比较简单,这部分代码模板如下,要点是五折交叉融合,f1指标跟踪早停:

import numpy as np
from sklearn.metrics import f1_score
from sklearn.externals import joblib
import lightgbm as lgb
import time
t0=time.time()

def feval_spec(preds, traindata):
	eval_score = f1_score(traindata.get_label(), np.round(preds))
	return 'f1_score:', eval_score, True

params = {
	'boosting_type': 'gbdt',
	'learning_rate': 0.1,
	'num_leaves': 32,
	'objective': 'binary',
	'metric': 'feval_spec',
	'is_unbalance': 'true',
	'nthread': -1,
	'verbose': -1,
}
feats=[col for col in data_feats.columns if col not in ['user_id','flag']]
skf = StratifiedKFold(n_splits=5,random_state=2020, shuffle=True)
yy_val, vval_label, = [],[]
for fold,(train_index,val_index) in enumerate(skf.split(range(len(data_feats)),data_feats.flag)):
	print('fold:',fold)
	val = data_feats.iloc[val_index]
	train = data_feats.iloc[train_index]
	trainData = lgb.Dataset(train[feats], label=train['flag'])
	valData = lgb.Dataset(val[feats], label=val['flag'])
	model = lgb.train(params, train_set=trainData, num_boost_round=10000,
					  valid_sets=[valData],
					  early_stopping_rounds=100,
					  feval=feval_spec,
					  verbose_eval=1000)
	y_val = model.predict(val[feats])
	yy_val.append(y_val)
	vval_label.append(val.flag.values)
	joblib.dump(model,'Model_fold%d.pkl'%fold)
yy_val = np.concatenate(yy_val)
yy_val = np.round(yy_val)
vval_label = np.concatenate(vval_label)
print(confusion_matrix(vval_label, yy_val))
print(f1_score(vval_label, yy_val))
####推理部分:
preds=[]
for fold in range(5):
	model = joblib.load('Model_fold%d.pkl'%fold)
	pred = model.predict(data_feats[feats])
	preds.append(pred)
p_value = np.array(preds).mean(axis=0)
pred = np.round(p_value).astype('int')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值