前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python:需求预估

Python:需求预估

作者头像
sladesal
发布2018-08-27 11:21:11
4950
发布2018-08-27 11:21:11
举报
文章被收录于专栏:机器学习之旅机器学习之旅

之前写了一篇以基于elastic的需求预估的文章,只不过用的是R语言开发的,最近在学python,就仿照逻辑写了一篇python的,主要修改点如下:

  • 用决策树替换了elastic算法
  • 用分层抽样替换了组合抽样

需要看详细理论及思考过程参考链接:商品需求预估

python code如下:

代码语言:javascript
复制
# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
import random as rd
from sklearn import tree

# 读取数据
data_orgin = pd.read_table("C:/Users/17031877/Desktop/supermarket_second_hair_washing_train.txt")
data_deal_1 = data_orgin.drop(['aimed_date', 'member_id', 'age', 'gender', 'diff_rgst'], axis=1)

这边是常规的数据读取,删除了不必要的列


代码语言:javascript
复制
#因变量单列
label = data_deal_1['label']

# 用户分量级
value00 = ['max_date_diff', 'aimed_max_date_diff']
data00 = data_deal_1[value00]

value01 = ['max_pay', 'per_pay', 'six_month_max_pay', 'six_month_per_pay', 'three_month_max_pay', 'three_month_per_pay',
           'one_month_max_pay', 'one_month_per_pay', 'fifteen_day_max_pay', 'fifteen_day_per_pay', 'aimed_max_pay',
           'aimed_per_pay', 'aimed_six_month_max_pay', 'aimed_six_month_per_pay', 'aimed_three_month_max_pay',
           'aimed_three_month_per_pay', 'aimed_one_month_max_pay', 'aimed_one_month_per_pay',
           'aimed_fifteen_day_max_pay', 'aimed_fifteen_day_per_pay', 'qty_drtn_seven', 'qty_drtn_fourteen']
data01 = data_deal_1[value01]

value02 = ['cnt_time', 'six_month_cnt_time', 'three_month_cnt_time', 'one_month_cnt_time', 'fifteen_day_cnt_time',
           'aimed_cnt_time', 'aimed_six_month_cnt_time', 'aimed_three_month_cnt_time', 'aimed_one_month_cnt_time',
           'aimed_fifteen_day_cnt_time', 'pv_times_seven', 'pv_times_fourteen', 'search_times_seven',
           'search_times_fourteen', 'clc_times_seven', 'clc_times_fourteen', 'cart2_times_seven',
           'cart2_times_fourteen', 'cart1_times_seven', 'cart1_times_fourteen', 'unpay_times_seven',
           'unpay_times_fourteen']
data02 = data_deal_1[value02]

value03 = ['pv_visit_last_period', 'search_last_period', 'clc_last_period', 'cart2_last_period', 'cart1_last_period',
           'unpay_last_period']
data03 = data_deal_1[value03]

因为不同量级的数据之后做异常点处理的时候截断位置不同,所有需要分割数据处理


代码语言:javascript
复制
def test_function_one(x, l):
    k = x.dropna(how='any')
    y = k.quantile(l)
    z = k.max()
    x[x > y] = y
    x = x.fillna(value=z)
    return x
for i in range(len(data00.columns)):
    data00.iloc[:, i] = test_function_one(data00.iloc[:, i], 0.98)

def test_function_two(x, l):
    k = x.dropna(how='any')
    y = k.quantile(l)
    z = 0
    x[x > y] = y
    x = x.fillna(value=z)
    return x
for i in range(len(data01.columns)):
    data01.iloc[:, i] = test_function_two(data01.iloc[:, i], 0.95)
for i in range(len(data02.columns)):
    data02.iloc[:, i] = test_function_two(data02.iloc[:, i], 0.99)

def test_function_three(x):
    z = 14
    x[x > z] = z
    x = x.fillna(value=z)
    return x
for i in range(len(data03.columns)):
    data03.iloc[:, i] = test_function_three(data03.iloc[:, i])
# 数据合并
data_train = pd.concat([label, data00, data01, data02, data03], axis=1)

根据数据量的不同做数据分割,跑上面写完的code函数就可以


代码语言:javascript
复制
#数量级对比
zero_case = data_train[data_train['label'] == 0]['label'].count()
print '负样本数:%d' % zero_case
one_case = data_train[data_train['label'] == 1]['label'].count()
print '正样本数: %d' % (one_case)

负样本数:292936
正样本数: 3973
Backend TkAgg is interactive backend. Turning interactive mode on.

实际看下来,正负样本的差异的确还是很大,这个其实做多了就有经验,常规的来看,潜在的浏览、搜索到最后的成单,普遍自然转化不到1%,也正是这么低的转化,才需要一些算法来做信息抓去。


代码语言:javascript
复制
def case_sample(x, y, z):
    diff_case = pd.DataFrame(x[y]).drop_duplicates([y])
    result = []
    result = pd.DataFrame(result)
    for i in range(len(diff_case)):
        k = np.array(diff_case)[i]
        data_set = x[x[y] == k[0]]
        nrow_nb = data_set.iloc[:, 0].count()
        data_set.index = range(nrow_nb)
        index_id = rd.sample(range(nrow_nb), int(nrow_nb * z))
        result = pd.concat([result, data_set.iloc[index_id, :]], axis=0)
    return result


zero_case = data_train[data_train['label'] == 0]
one_case = data_train[data_train['label'] == 1]
# 开始分层抽样
new_zero_case = case_sample(zero_case, 'unpay_last_period', 0.1)
# 新数量级对比
new_zero_case_count = new_zero_case[new_zero_case['label'] == 0]['label'].count()
# 数据集合并
new_data_train = pd.concat([new_zero_case, one_case], axis=0)

case_sample是一个简单的分层抽样的小函数,x是数据集,y是分层变量,z是抽样占比;新的样本new_data_train中正负样本比例在1:10左右,这边的样本比是我自己设置的,不一定是最合理的;且此处也不一定要求一定用分层抽样,只是我用来练练手的;推荐还是遵从奥卡姆原理,在未知的情况下,尽可能简单的解决问题,比如组合抽样就是很不错的方法。


代码语言:javascript
复制
#函数设置
clf = tree.DecisionTreeRegressor(criterion='mse', max_features='log2', random_state=1)

#函数拟合
y = new_data_train['label']
x = new_data_train.drop('label', 1)
clf.fit(x, y)

#数据预测
y_predict = clf.predict(x)

# 结果对比
y.index = range(len(y))
combined_date = pd.concat([y, pd.DataFrame(y_predict)], axis=1)
combined_date.columns = ['actual', 'predict']

这边稍微讲解一下,我认为的sklearnDecisionTreeRegressor中比较终于的参数设置,criterion这边为模型优化的标准,常规的有msemae,建议在数据量差异不大的时候多考虑msemax_features是每次训练用的特征个数,综合特征量级考虑,一般有log2sqrt,尽可能是抽取比例在70%;max_depth刚开始可以默认,第一类模型出来后,可在结果附近迭代,寻找out of bag最小的error下的值;另外,我没有发现有weight设置,可能是我不熟悉,但是如果sklearn这边不提供weight的化,我们在做数据预处理的时候一定要平衡数据,不然当数据集过偏的时候最后的结果会以“牺牲”少类的判断正确率去完善整体正确率。


代码语言:javascript
复制
# case 1
x = []
y = []
for i in range(1, 10):
    test_data = combined_date
    i = i / float(10)
    for j in range(combined_date['actual'].count()):
        if test_data.iloc[j, 1] > i:
            test_data.iloc[j, 1] = 1
        else:
            continue
    z = test_data[test_data['actual'] == test_data['predict']]['actual'].count() / float(test_data['actual'].count())
    x.append(i)
    y.append(z)

这边写了检查函数,检查了分别0.1~1,以0.1为间隔的情况下的分割点,每个分割点下预测正确的数量/所有统计的样本数,也就是下面的accuracy.


代码语言:javascript
复制
# case 2
test_data = combined_date
aimed_data = test_data[test_data['predict']>0]
k1=aimed_data[aimed_data['actual']==1]['predict'].count()
k2=float(aimed_data['predict'].count())

print '所有预测可能下单用户中真实下单用户数:%d' %(k1)
print '所有预测可能下单用户数:%d' %(k2)

因为这边需要对用户营销,所以更关系topN的转化率,需要看一下实际正样本被覆盖了多数,以上即为code,这边的效果值为98.7%,还是比较高的,但是应该是过拟合了,所有一般不建议单纯使用决策树模型


所有的python code到这里就结束了,后续我做项目的同时会同时更新R及python两种code的思考,和大家讨论分享学习,谢谢。

参考文献:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.07.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档