2019 CCF 乘用车细分市场销量预测 - 分析

前言

自己也学了别人分享的比赛心得,也总结了自己的比赛心得,主要是了解更全面的看这个比赛问题,首先比赛提供了60个车型在22个省份,从2016年1月至2017年12月的销量。参赛队伍需要预测接下来4个月(2018年1月至2018年4月)的汽车销量,额外提供了搜索数据、新闻及评论数据。这个数据是做额外的分析作用的。

思路

大体思路就是提取特征,利用前n个月数据预测本月数据。

  • 依次来得到4个月的预测数据,例如先预测1月份数据,再利用1月份数据得到2月份特征,用来预测2月的销量,这样误差就传递到后面的月份去了。
  • 另一种思想就是直接预测这4个月的数据,但是这样的话就存在一个问题,提取特征时会利用前n个月数据,预测4月份销量时,1、2、3月份都没有车型销量数据,那么4月的特征就会失准,一种解决方法就是将销量平移,或者加权重来平移销量,还有一种就是相隔提取特征,每次提取距离当前月n个月之前的历史数据,从中来构建特征,这样就不会数据失准,也是一个思路。
  • 第三种方案,上述两种方案都没有利用搜索数据、新闻等数据来做特征,这些数据其实是很用的,但是同样存在问题就是这些数据只有历史数据,1、2、3、4月份是未来数据,没有搜索数据、新闻数据,也就无法利用这些额外数据来得到2、3、4月份的特征,同样可以数据平移、加权重等方式来获取一个大概数据。
  • 在第3中方案下,也可以训练模型分别预测搜索数据、新闻数据,然后这样相互做特征,所以一共3个模型,分别预测销量、搜索量、新闻数量,不过误差太大了,互相传递,有点蛋疼,不敢说效果好,是一个比较好的思路。

提取特征

对省份进行加权,这里根据一线、二线、三线等来区分,一线城市给的权重高一些,毕竟大城市汽车销量就高,也跟人口、收入相关。

# 省份 词典
dicProvince = {'北京':5,'上海':5,'广东':5,'浙江':5,'江苏':5,
'河北':4,'重庆':4,'四川':4,'湖北':4,'辽宁':4,'湖南':4,'福建':4,
'安徽':3,'河南':3,'山东':3,'江西':3,'陕西':3,'云南':3,'广西':3,'黑龙江':3,'内蒙古':3,'山西':3}

对车型做权重,可以根据销量大小来做权重区分,销量好的车型权重大

#  按照 总销量 来 确定 大小顺序的
dicBodyType ={"Hatchback":1,"MVP":2,"SUV":3,"Sedan":4}

1、数据平移,获取前n个月的销量数据作为本月特征

'''
    历史平移特征:start, end+1 坐标来表示平移几个月的数据
    '''
    df = df_.copy()
    for i in range(start, end+1):
        // group 是列名,该列数据是多个特征量化后组装在一起的数字,
        // 其中最后2位表示月份,+ 1 表示 月份加1,也就是下个月
        df['{}_{}'.format(col,i)] = df[group] + i
        // 以新得到的下个月的数据作为index,col 作为value,
        df_last = df[~df[col].isnull()].set_index('{}_{}'.format(col,i))
        //  通过map 方法来获取 月份的 value
        df['shift_{}_{}_{}'.format(col,group,i)] = df[group].map(df_last[col])
        del df['{}_{}'.format(col,i)]
    
    return df, add_feat

2、相邻数据的平均值、总值、最小月份与最大月份的销量差值、最小月份与最大月份的比值
这里相邻,是当前月份的历史月份相邻数据的特征,比如:当前是7月,计算6月、5月数据的平均值、总值等等特征,看代码主要:‘shift_{}{}{}’.format(col,‘adcode_model_mt’,i+j) 表示当前月份的前 (i+j)个月特征,这是平移历史特征方法中得到的特征

// space 表示 相邻的月份,space =2,表示最近2个月,但是是以 i 为基础,
//  i =2,表示获取2+0=2、2+1=3、2+2=4 的数据,这是当前月份的前2、3、4月份数据,有点绕,我也是看了半天
 //   start:距离当前月份的第前start个月的数据
//    end:距离当前月份的第前end个月的数据

    for i in range(start, end+1):   
        df['adjoin_{}_{}_{}_{}_{}_sum'.format(col,group,i,i+space,space)] = 0
   
//    'shift_{}_{}_{}'.format(col,'adcode_model_mt',i+j)    表示当前月份的前 (i+j)个月特征,这是平移历史特征方法中得到的特征

        # 求和
        for j in range(0, space+1):
            df['adjoin_{}_{}_{}_{}_{}_sum'.format(col,group,i,i+space,space)]   = df['adjoin_{}_{}_{}_{}_{}_sum'.format(col,group,i,i+space,space)] +  df['shift_{}_{}_{}'.format(col,'adcode_model_mt',i+j)]
            
        # 均值
        df['adjoin_{}_{}_{}_{}_{}_mean'.format(col,group,i,i+space,space)]  = df['adjoin_{}_{}_{}_{}_{}_sum'.format(col,group,i,i+space,space)].values/(space+1)
        # 首尾差值
        df['adjoin_{}_{}_{}_{}_{}_diff'.format(col,group,i,i+space,space)]  = df['shift_{}_{}_{}'.format(col,'adcode_model_mt',i)].values - df['shift_{}_{}_{}'.format(col,'adcode_model_mt',i+space)]
        # 首尾比例
        df['adjoin_{}_{}_{}_{}_{}_ratio'.format(col,group,i,i+space,space)] = df['shift_{}_{}_{}'.format(col,'adcode_model_mt',i)].values /  df['shift_{}_{}_{}'.format(col,'adcode_model_mt',i+space)]

    return df

这个特征大概是这个意思,

  • 当前月份是10月,i =2,space=2
  • 取 8月、7月、6月的数据作为相邻数据

3、连续N月的统计值,总值、最大值、最小值、平均值、标准偏差、最大值与最小值之差
上面那个相邻特征可能会与当前月份有间隔,比如上文举例说得到当前月份前2、3、4月的历史数据做特征,那么连续N月则会强调根据离当前月份的连续 N月 数据的特征。看代码主要注意:‘shift_{}{}{}’.format(col,‘adcode_model_mt’,i+j) 表示当前月份的前 (i+j)个月特征,这是平移历史特征方法中得到的特征。

  '''
    连续N月的统计值
    start:距离当前月份的第前start个月的数据
    end:距离当前月份的第前end个月的数据
    '''
    df = df_.copy()
    add_feat = []
    li = []
    for i in range(start,end+1):
        li.append('shift_{}_{}_{}'.format(col,'adcode_model_mt',i))

    // 多列数据求和、平均值、最大值、最小值等计算,得到一列数据
    df['series_{}_{}_{}_{}_sum'.format( col,group,start,end)] = df[li].apply(get_sum, axis=1)
    df['series_{}_{}_{}_{}_mean'.format(col,group,start,end)] = df[li].apply(get_mean, axis=1)
    df['series_{}_{}_{}_{}_min'.format( col,group,start,end)] = df[li].apply(get_min, axis=1)
    df['series_{}_{}_{}_{}_max'.format( col,group,start,end)] = df[li].apply(get_max, axis=1)
    df['series_{}_{}_{}_{}_std'.format( col,group,start,end)] = df[li].apply(get_std, axis=1)
    df['series_{}_{}_{}_{}_ptp'.format( col,group,start,end)] = df[li].apply(get_ptp, axis=1)

    return df

通过列表指定方法来获取:
df[li].apply(get_std, axis=1)  // 标准偏差
df[li].apply(get_ptp, axis=1) // 最大值与最小值之差

  举例子来分析一下:取连续的前n个月的销量数据做特征,当前月份是10月,n=3,start = 2,end=5,可以取8、7、6、5月这4个月数据用来分析。

  问题来了,为什么要这么做?取的都不是当前月份的相邻历史数据、连续历史数据来做特征,其实是考虑到了测试集,因为测试集要求预测1月-4月的数据,预测的是连续的数据,所以可以取当前月份的前4个月之前的数据做特征,比如预测7月-10月的销量数据,当前月份是10月,用6月及之前的历史数据做特征,这样就不会因为9、8、7月无销量数据而造成特征数据有问题。 所以可以指定 start =4,这样保持对当前当月的间隔月份。

  上面是基本的特征,可以根据省份-车型-月份(adcode + model + regMonth )、车型-月份、省份-月份等来组合特征,这样就可以得到一些关系特征数据,这里要注意adcode + model + regMonth 可以唯一指定一行记录,作为主键的功能,所以用车型-月份、省份-月份 就需要做sum操作,把数据累计起来才是该特征正确的数据。
  当然这样不仅仅是对销量,也可以对新闻热度,新闻评论等方面做判断,因为取当前月份前4个月的数据。

异常数据的处理

似乎提高分数一个必做的事情就是解决异常数据,异常数据如何处理具体要做数据分析,把数据分布弄出来看看,这个方面讲解以后补充,本比赛的可视化链接

算法模型

  • lgb
model = lgb.LGBMRegressor(
                                num_leaves=2**5-1, reg_alpha=0.25, reg_lambda=0.25, objective='mse',
                                max_depth=-1, learning_rate=0.05, min_child_samples=5, random_state=2019,
                                n_estimators=2000, subsample=0.9, colsample_bytree=0.7,
                                )
        model.fit(train_x, train_y, 
              eval_set=[(train_x, train_y),(valid_x, valid_y)], 
              categorical_feature=cate_feat, 
              early_stopping_rounds=100, verbose=100)  

  • xgb
model = xgb.XGBRegressor(
                                max_depth=5 , learning_rate=0.05, n_estimators=2000, 
                                objective='reg:gamma', tree_method = 'hist',subsample=0.9, 
                                colsample_bytree=0.7, min_child_samples=5,eval_metric = 'rmse' 
                                )
        model.fit(train_x, train_y, 
              eval_set=[(train_x, train_y),(valid_x, valid_y)], 
              early_stopping_rounds=100, verbose=100) 

模型融合

可以采取多模型融合的方式来提高分数,这里只是比较多,也不讲解了。

参考博客

2019CCF-BDCI-乘用车细分市场销量预测方案(Top1%)

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值