赛题
比赛来源:https://www.datafountain.cn/competitions/311/details/data-evaluation
感谢大佬开源:
TOP2方案: 用户套餐个性化匹配TOP2
本博客只是单纯的对TOP方案进行整理学习。
要求
此题利用已有的用户属性(如个人基本信息、用户画像信息等)、终端属性(如终端品牌等)、业务属性、消费习惯及偏好匹配用户最合适的套餐。
数据说明
字段 | 中文名 | 数据类型 | 说明 |
---|---|---|---|
USERID | 用户ID | VARCHAR2(50) | 用户编码,标识用户的唯一字段 |
current_type | 套餐 | VARCHAR2(500) | / |
service_type | 套餐类型 | VARCHAR2(10) | 0:23G融合,1:2I2C,2:2G,3:3G,4:4G |
is_mix_service | 是否固移融合套餐 | VARCHAR2(10) | 1.是 0.否 |
online_time | 在网时长 | VARCHAR2(50) | / |
1_total_fee | 当月总出账金额_月 | NUMBER | 单位:元 |
2_total_fee | 当月前1月总出账金额_月 | NUMBER | 单位:元 |
3_total_fee | 当月前2月总出账金额_月 | NUMBER 单位:元 | |
4_total_fee | 当月前3月总出账金额_月 | NUMBER | 单位:元 |
month_traffic | 当月累计-流量 | NUMBER | 单位:MB |
many_over_bill | 连续超套 | VARCHAR2(500) | 1-是,0-否 |
contract_type | 合约类型 | VARCHAR2(500) | ZBG_DIM.DIM_CBSS_ACTIVITY_TYPE |
contract_time | 合约时长 | VARCHAR2(500) | / |
is_promise_low_consume | 是否承诺低消用户 | VARCHAR2(500) | 1.是 0.否 |
net_service | 网络口径用户 | VARCHAR2(500) | 20AAAAAA-2G |
pay_times | 交费次数 | NUMBER | 单位:次 |
pay_num | 交费金额 | NUMBER | 单位:元 |
last_month_traffic | 上月结转流量 | NUMBER | 单位:MB |
local_trafffic_month | 月累计-本地数据流量 | NUMBER | 单位:MB |
local_caller_time | 本地语音主叫通话时长 | NUMBER | 单位:分钟 |
service1_caller_time | 套外主叫通话时长 | NUMBER | 单位:分钟 |
service2_caller_time | Service2_caller_time | NUMBER | 单位:分钟 |
gender | 性别 | varchar2(100) | 01.男 02女 |
age | 年龄 | varchar2(100) | / |
complaint_level | 投诉重要性 | VARCHAR2(1000) | 1:普通,2:重要,3:重大 |
former_complaint_num | 交费金历史投诉总量 | NUMBER | 单位:次 |
former_complaint_fee | 历史执行补救费用交费金额 | NUMBER | 单位:分 |
数据探索
TOP2解决方案
导入必要的库:
import pandas as pd
import numpy as np
from gensim.corpora import WikiCorpus
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import multiprocessing
亮点1-利用word2vec
围绕以下数据进行词嵌入
1_total_fee | 当月总出账金额_月 | NUMBER | 单位:元 |
---|---|---|---|
2_total_fee | 当月前1月总出账金额_月 | NUMBER | 单位:元 |
3_total_fee | 当月前2月总出账金额_月 | NUMBER 单位:元 | |
4_total_fee | 当月前3月总出账金额_月 | NUMBER | 单位:元 |
读取并合并数据:
path = '../raw_data/'
save_path = '../gen_data/'
train_1 = pd.read_csv(path+'train_1.csv') # 初赛数据
train_2 = pd.read_csv(path+'train_2.csv') # 复赛数据
test = pd.read_csv(path+'test_2.csv') # 复赛测试集
data = pd.concat([train_1,train_2,test]).reset_index(drop=True).sample(frac=1,random_state=2010).fillna(0)
data = data.replace('\\N',999)
将每个用户的四个月出账金额组成一个句子:
sentence = []
for line in list(data[['1_total_fee','2_total_fee','3_total_fee','4_total_fee']].values):
# [str(n) for n in line] 这样更快
sentence.append([str(float(l)) for idx, l in enumerate(line)])
sentence是个二维数组,结果如下:
训练词向量模型:
print('training')
model = Word2Vec(sentence,size=L, window=2, min_count=1, workers=multiprocessing.cpu_count(),iter=10)
print('outputing')
利用已经训练好的模型,将每个词(数据)保存起来:
for fea in ['1_total_fee', '2_total_fee', '3_total_fee', '4_total_fee']:
# 利用set将 data['1_total_fee'].values 数据去重,逐个输入模型,算出相应的词向量(10维)
values = set(data['1_total_fee'].values)
w2v = []
for i in values:
a = [i]
# 利用append将多个元素加入list
a.extend(model[str(float(i))])
w2v.append(a)
out_df = pd.DataFrame(w2v)
# 添加列名
name = [fea]
for i in range(L):
name.append(name[0] + 'W' + str(i))
out_df.columns = name
# 保存结果,后期通过merge利用此结果
out_df.to_csv(save_path + fea + '.csv', index=False)
亮点2-预测概率作为新的特征
将上述的词向量merge带训练数据中:
w2v_features = []
for col in ['1_total_fee', '2_total_fee', '3_total_fee', '4_total_fee']:
df =pd.read_csv(save_path+'/'+col+'.csv')
df.drop_duplicates([col], inplace=True)
feat_name = list(df) # 获取列名
feat_name.remove(col) # 移除列名中的 1_total_fee
w2v_features += feat_name
data = pd.merge(data, df, on=col, how='left')
TOP2中的业务特征,本文只对计数特征进行总结
# 计算特征具体取值出现的个数
count_feature_list = []
def feature_count(data, features=[]):
if len(set(features)) != len(features):
print('equal feature !!!!')
return data
new_feature = 'count'
for i in features:
new_feature += '_' + i.replace('add_', '')
try:
del data[new_feature]
except:
pass
temp = data.groupby(features).size().reset_index().rename(columns={0: new_feature})
# print(temp)
data = data.merge(temp, 'left', on=features)
count_feature_list.append(new_feature)
return data
计算以下特征以及组合特征的计数特征
data = feature_count(data, ['1_total_fee'])
data = feature_count(data, ['2_total_fee'])
data = feature_count(data, ['3_total_fee'])
data = feature_count(data, ['4_total_fee'])
data = feature_count(data, ['former_complaint_fee'])
data = feature_count(data, ['pay_num'])
data = feature_count(data, ['contract_time'])
data = feature_count(data, ['last_month_traffic'])
data = feature_count(data, ['online_time'])
for i in ['service_type', 'contract_type']:
data = feature_count(data, [i, '1_total_fee'])
data = feature_count(data, [i, '2_total_fee'])
data = feature_count(data, [i, '3_total_fee'])
data = feature_count(data, [i, '4_total_fee'])
data = feature_count(data, [i, 'former_complaint_fee'])
data = feature_count(data, [i, 'pay_num'])
data = feature_count(data, [i, 'contract_time'])
data = feature_count(data, [i, 'last_month_traffic'])
data = feature_count(data, [i, 'online_time'])
将业务特征和词向量特征输入到Lightgbm模型,进行训练。
lgb_model = lgb.LGBMClassifier(
n_estimators=10,
boosting_type="gbdt",
objective='multiclass',
silent=False,
random_state=2018, n_jobs=-1
)
lgb_model.fit(train_x, train_y.values,eval_set=[(train_x.iloc[:1000, :],train_y.values[:1000])], categorical_feature=cate_feature,verbose=1)
print(lgb_model.best_score_)
预测时,采用predict_proba进行预测。
train_proba = lgb_model.predict_proba(test_x[feature])
test_proba = lgb_model.predict_proba(data[data.label == 0][feature])
print(len(train_proba), len(test_proba))
print(train_proba)
预测结果是11个类别的概率:
将每条数据的预测概率作为新的特征加入到Lightgbm模型中。
亮点3 - 不同的数据用不同的模型预测
观察发现套餐类型数据分布如下:
其中 0:23G融合,1:2I2C,2:2G,3:3G,4:4G
真实场景中只有1,3,4三类。因此将3、4类归为1类:
data.loc[data['service_type'] == 3, 'service_type'] = 4
此时service_type只有两类:1和4。针对这两类分别训练模型。
模型一:取出service_type==1的数据进行训练预测。
模型一:取出service_type==4的数据进行训练预测。