商品数据运营化(二)

案例:基于集成算法GBDT和RandomForest的投票组合模型的异常检测

part 1 导入库

import numpy as np
import pandas as pd
from imblearn.over_sampling import SMOTE #过抽样处理库SMOTE
from sklearn.ensemble import VotingClassifier,GradientBoostingClassifier,RandomForestClassifier #集成分类库和投票方法库
from sklearn.model_selection import StratifiedKFold,cross_val_score #交叉检验算法
from sklearn.preprocessing import OrdinalEncoder #字符串转数值

part 2函数模块

定义了一个基于日期和时间派生出更多特征的函数

def datetime_exp(data):
    date_set = [pd.datetime.strptime(dates,'%Y-%m-%d') for dates in data['order_date']] #将data中的order_date列转换为特定日期格式
    data['weekday_data'] = [data.weekday() for data in date_set]
    data['daysinmonth_data'] = [data.day for data in date_set]
    data['month_data'] = [data.month for data in date_set]

    time_set = [pd.datetime.strptime(times, '%H:%M:%S') for times in data['order_time']] #将data中的order_time列转换为特定日期格式
    data['second_data'] = [data.second for data in time_set]
    data['minute_data'] = [data.minute for data in time_set]
    data['hour_data'] = [data.hour for data in time_set]
    return data.drop(['order_date','order_time'],axis=1)

part 3 读取数据

raw_data = pd.read_table('abnormal_orders.txt',delimiter=',')

part 4 数据审查

#查看基本状态
print('{:*^60}'.format('Data overview:'))
print(raw_data.tail(2))
print('{:*^60}'.format('Data dtypes:'))
print(raw_data.dtypes)
print('{:*^60}'.format('Data DESC:'))
print(raw_data.describe().round(2).T)

 结果:

***********************Data overview:***********************
          order_id  order_date order_time       cat attribution      pro_id  \
134188  4285770012  2013-09-19   23:55:06      家居日用          GO  1000335947   
134189  4285770056  2013-05-20   23:58:59  生活电器厨卫电器          GO  1000009280   

       pro_brand  total_money  total_quantity order_source pay_type  \
134188       炊大师         79.0               1           抢购     合并支付   
134189        海尔        799.0               1           抢购     合并支付   

           user_id city  abnormal_label  
134188      shukun  东莞市               0  
134189  544975322_  海口市               0  
************************Data dtypes:************************
order_id            int64
order_date         object
order_time         object
cat                object
attribution        object
pro_id              int64
pro_brand          object
total_money       float64
total_quantity      int64
order_source       object
pay_type           object
user_id            object
city               object
abnormal_label      int64
dtype: object
*************************Data DESC:*************************
                   count          mean           std           min  \
order_id        134190.0  4.214285e+09  1.510533e+08  3.000316e+09   
pro_id          134190.0  3.404167e+09  3.287444e+09  1.000000e+09   
total_money     134189.0  6.601100e+02  2.901210e+03  5.000000e-01   
total_quantity  134190.0  1.200000e+00  3.230000e+00  1.000000e+00   
abnormal_label  134190.0  2.100000e-01  4.100000e-01  0.000000e+00   

                         25%           50%           75%           max  
order_id        4.203350e+09  4.276630e+09  4.281996e+09  4.285770e+09  
pro_id          1.000321e+09  1.000369e+09  8.001623e+09  8.002352e+09  
total_money     2.900000e+01  9.840000e+01  3.720000e+02  7.660000e+05  
total_quantity  1.000000e+00  1.000000e+00  1.000000e+00  1.000000e+03  
abnormal_label  0.000000e+00  0.000000e+00  0.000000e+00  1.000000e+00  

Data overview:

每个字段都已经被正确识别。数据里有散列特殊字段:order_id、pro_id和user_id。Order_id在所有记录中都是唯一值,没有实际意义,之后会去掉。pro_id和user_id作为商品和用户的唯一识别标志,可以有一定的参考价值,后续不会去掉。

Data DESC:

total_money和total_quantity存在极大值,由于案例是针对异常值检测,所以不处理。

#缺失值审查:
na_cols = raw_data.isnull().any(axis=0)
print('{:*^60}'.format('NA Cols:'))
print(na_cols[na_cols]==True)
print('Total number of NA lines is: {0}'.format(raw_data.isnull().any(axis=1).sum()))

**************************NA Cols:**************************
cat            True
pro_brand      True
total_money    True
city           True
dtype: bool
Total number of NA lines is: 1429

按列查看缺失值

na_cols[na_cols]==True 过滤出包含缺失值为True的列

通过结果分析,总的缺失记录为1429,占总体样本量的1%左右可以考虑直接丢弃。

#类样本均衡审查
print('{:*^60}'.format('Labesl samples cpunt:'))
print(raw_data.iloc[:,-1].value_counts())

*******************Labesl samples cpunt:********************
0    105733
1     28457
Name: abnormal_label, dtype: int64

 负样本的比例只有正样本的20%左右,需要做样本均衡处理。

part 5 数据预处理

直接使用dropna方法丢弃缺失值

#Nan处理:
drop_na_set = raw_data.dropna()

#丢弃订单ID列:
drop_na_set = drop_na_set.drop(['order_id'],axis = 1)

字符串转数值

convert_cols = ['cat', 'attribution', 'pro_id', 'pro_brand', 'order_source', 'pay_type','user_id', 'city']  # 定义要转换的列
enc = OrdinalEncoder()
drop_na_set[convert_cols]=enc.fit_transform(drop_na_set[convert_cols])

分割测试机和训练集

num = int(0.7*data_final.shape[0])
X_raw, y_raw = data_final.drop(['abnormal_label'],axis=1), data_final['abnormal_label']  
X_train,X_test = X_raw.iloc[:num,:],X_raw.iloc[num:,:]
y_train,y_test = y_raw.iloc[:num],y_raw.iloc[num:]

样本均衡

model_smote = SMOTE()
x_smote_resampled,y_smote_resampled = model_smote.fit_resample(x_train,y_train)

使用SMOTE方法对不均衡样本进行处理,先建立模型,然后使用fit_sample方法做训练后的抽样处理。

part 6 模型训练

#交叉检验:
model_rf = RandomForestClassifier(max_features=0.8,random_state=0)
model_gdbc = GradientBoostingClassifier(max_features=0.8,random_state=0)
estimators = [('randomforest',model_rf),('gradientboosting',model_gdbc)] #建立组合评估器列表
model_vot = VotingClassifier(estimators=estimators,voting='soft',weights=[0.9,1.2],n_jobs=1) #建立组合评估模型
cv = StratifiedKFold(5) #交叉检验方法
cv_score = cross_val_score(model_gdbc,x_smote_resampled,y_smote_resampled,cv=cv) #交叉检验
print('{:*^60}'.format('Cross val scores:'),'\n',cv_score)
print('Mean score is: %.2f' % cv_score.mean())

*********************Cross val scores:********************** 
 [0.52150039 0.81140029 0.89191384 0.79624115 0.75687382]
Mean score is: 0.76

#训练模型:
model_vot.fit(x_smote_resampled,y_smote_resampled)

从交叉检验结果看,5词交叉检验除第一次结果较差外,其他检验效果都不错,整体得分达到0.76。

part 7 新数据集做预测

#读取数据
x_new = pd.read_csv('new_abnormal_orders.csv')
#丢掉order_id列
x_new_drop = x_new.drop(['order_id'],axis=1)
#字符串转数值
x_new_drop[convert_cols] = enc.transform(x_new_drop[convert_cols])
#日期特征拓展
x_new_final = datetime_exp(x_new_drop)
#预测结果
predict_label = model_vot.predict(x_new_final)
predict_proba = model_vot.predict_proba(x_new_final)
predict_np = np.hstack((predict_label.reshape(-1,1),predict_proba))
predict_pd = pd.DataFrame(predict_np,columns=['label','proba_0','proba_1'])
#输出
print('{:*^60}'.format('Predicted Labesls:'),'\n',predict_pd)

*********************Predicted Labesls:********************* 
    label   proba_0   proba_1
0    1.0  0.383849  0.616151
1    0.0  0.745019  0.254981
2    0.0  0.990146  0.009854
3    0.0  0.989648  0.010352
4    0.0  0.990495  0.009505
5    0.0  0.768635  0.231365
6    0.0  0.823290  0.176710

总结

在该案例中,76%的准确值是一个中等结果。由于我们没有优化参数,所以准确度不是特别高。

需要注意的是:字符串转整数型分类,应用的前提是训练集中被转换的唯一值域必须是固定的。还需注意预测的新数据集中是否存在NA值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值