精华内容
下载资源
问答
  • 这里需要强调的是“大量数据”和“有意义的潜在规律”,这两个特征将数据挖掘与传统的独立分散的数据分析及简单的数据库查询、报表应用区分开来。 数据挖掘应用在近年来迅速发展,其基础是关系型数据库系统应用的...
    1 数据挖掘简介
     
    数据挖掘业界权威michael berry和gordon linoff的论述,数据挖掘是利用自动或半自动手段揭示大量数据中有意义的潜在规律的处理过程。这里需要强调的是“大量数据”和“有意义的潜在规律”,这两个特征将数据挖掘与传统的独立分散的数据分析及简单的数据库查询、报表应用区分开来。
     
    数据挖掘应用在近年来迅速发展,其基础是关系型数据库系统应用的逐步普及和成熟,以数据库形态存在的业务数据大量积累,为数据挖掘中的“大量数据”和“自动或半自动手段”提供了可能;其驱动力是业务需求的发展,尤其是数据库应用系统上线后给业务需求带来的正反馈作用;其核心是产品化的数据挖掘产品和实施咨询服务。
     
    2 数据挖掘项目形态
     
    2.1基于数据仓库的数据挖掘

    在很多项目中,数据挖掘是整合数据平台特别是数据仓库的延伸应用。通常,大型项目中,在数据仓库中为特定主题的数据挖掘建立数据集市,使得数据可以通过比较系统的形式定期加载更新,作为较为稳定的数据挖掘数据源;经过数据挖掘得到的数据规律,以计分预测或者与营销系统整合等形式发布到企业中,并经过一定的收效评估和阶段回顾,得出项目阶段性结论[1]。这种类型的项目,数据挖掘和数据仓库紧密结合,取用统一数据,有利于数据挖掘过程在企业的重用和固化,建立稳定的应用模式;但是数据挖掘的过程在较大程度上受到数据仓库建设的制约,见效的周期可能会较长,短期的投资见效比不理想,而且项目有很可能因数据仓库方面的问题而非数据挖掘的问题导致失败。

    2.2先导型数据挖掘

    数据挖掘项目也可以独立于数据仓库存在。在挖掘的主题已经明确而相应的数据仓库还未建立,或者是项目有较强的预研性的情况下,数据挖掘项目可以直接进入主题,取用运营系统的原始数据,建立针对具体数据挖掘用途的专用数据区,不考虑太多的重用批量加载环节,尽快地开始挖掘过程,并将结果与业务迅速沟通。这样做的好处是便于企业更直接地体验数据挖掘的效益,尤其是业务管理部门可以很快得到来自数据规律的直接决策支持信息,数据挖掘受数据仓库建设过程的制约较少,见效周期短,短期的投资见效比比较好。但是比较难形成较为稳定的应用模式,同时由于数据源及转换处理往往独立于企业数据仓库建设,部分工作可能会在以后的数据集市过程中重复开始,甚至出现数据的不一致性,如果存在过多的这种彼此独立的项目,将造成局部“信息孤岛”现象[2]。

    在我们实施的数据挖掘案例中,将以上两种模式有机地结合在一起,先利用一个或几个主题的独立数据挖掘项目的开展,为企业数据仓库提供面向数据挖掘的数据需求,同时,这些独立项目中的数据准备环节充分考虑数据仓库的思路。这样,在数据仓库建设中,可以得到更多的来自数据挖掘的设计要求和参考经验,有效地建立数据仓库和数据挖掘整体系统。

    3 数据挖掘项目的架构

    3.1数据挖掘方法论简介

    数据挖掘的架构是建立在成熟、合理的方法论基础上的。主要有semma方法论和crisp-dm方法论。semma方法论以抽样(sample)、探索(explore)、修改(modify)、建模(model)、评估(assess)为核心环节,强调数据挖掘过程是这5个环节的有机循环。crisp-dm是跨行业数据挖掘标准流程(cross-industry standard process for data mining)的缩写,强调以业务理解(business understanding)、数据理解(data understanding)、数据准备(data preparation)、建模(modeling)、评价(evaluation)、发布(deployment)为核心环节,将数据挖掘目标和商务目标有机地联系在一起[3]。

    在实际应用中,我们将上述两种方法有机地结合起来,crisp-dm强调高层的商务目的实现过程,semma强调具体的数据挖掘技术实现过程。

    3.2主要环节

    综合我们实际进行的数据挖掘,数据挖掘项目可以分为以下几个主要环节,如图1所示。
     
    500)this.style.width=500;" border="0" style="font-family: -apple-system, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft Yahei", sans-serif; -webkit-font-smoothing: antialiased; margin: 0px 0px 15px; padding: 0px; border: none; max-width: 100%; font-size: 16px; word-break: break-all; width: 485px; height: 270px; cursor: pointer;">
    a) 定义业务问题

    这个环节的任务包括:评估数据挖掘过程的成本和商务收益间是否平衡,识别分析目标的焦点范围,收集相关的业务规则,确定数据源的可用性和验证行业专家的观点。

    b) 转换数据格式使之适应数据挖掘的要求

    这是技术性最强的环节,包括了数据准备和数据挖掘建模。主要流程如图2。
     
    500)this.style.width=500;" border="0" style="font-family: -apple-system, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft Yahei", sans-serif; -webkit-font-smoothing: antialiased; margin: 0px 0px 15px; padding: 0px; border: none; max-width: 100%; font-size: 16px; word-break: break-all; cursor: pointer;">
    确定并获取数据

    首先,要根据已经明确的业务问题,定义需要被预测或研究的目标因素。然后,确认数据中包含在历史上已经发生的目标因素的结果值,例如,预测客户流失,历史数据中需要包含客户是否发生流失的信息。同时数据中还应该包含与目标因素可能相关的各类信息,在了解数据源的过程中,还应该明确数据的更新加载方式,这样才能够形成不断使用最近数据,预测未来目标的循环应用模式。
     
    验证,探索,清洗数据

    需要确定数据的来源是否可靠。考察数据项是自动衍生还是手工录入,是否存在缺失现象,取值是否符合规定,是否合理,数值分布是否可以解释,等等。

    转置数据,形成合适的颗粒度

    数据挖掘需要的数据往往是一个事件一行,一行中包含所有的相关属性。例如,客户价值分析中,以客户号为核心,将客户的各种指标在时间上的快照聚集到一行上。这种形式,需要对原始数据进行相应的转置操作,例如,将多个属性行对应一个一个客户的结构转置成一个客户行多个属性列的格式。

    增加衍生变量

    很多情形下,原始的数据列和目标因素之间不易找到明显的相关性,需要增加一些衍生变量,以辅助分析。例如,在客户使用量这个指标的基础上,增加客户的用量的三个月平均变动率,等等。
     
    准备建模用的数据
    这个环节需要考虑分析的时间段和时间颗粒度(周,月,季等),建模用的数据必须匹配相应的时间要求,数据中时间的发生必须在相应的时间段内。同时,可能需要对小概率事件进行过抽样(oversampling)以适应建模技术。在很多情形下,还可能对数据做剖分(partition),将历史数据分为训练(train)、验证(validate)、测试(test)三个部分,以便取得较好的预测效果,避免过拟合(overfitting)现象[4]。这些操作,将使数据更加适合数据挖掘的建模工作。
     
    选择合适建模技术,训练模型

    这个环节,就是狭义上的“数据挖掘”,实质上是挖掘建模的具体技术过程。我们采用semma方法论逐步找到合适的建模技术,训练数据,最终找到规律和模式[5]。
     
    检验模型的效果

    在模型检验中,会使用历史数据中部分已有结果,以测试数据的形式与模型预测结果对比,客观地考察预测准确性。在真正的预测期间,只能等到未来的数据结果变成现实后,才能对预测结果作出对比,因此,需要有一个模型在市场环境中的试投放的时期,来检验模型真实效果。

    c) 对分析结果进行理解和应用

    利用数据挖掘的最终结果和中间结果,可以深入了解企业数据的分布特征和存在的问题,进行一次性的专题分析或是周期性分析预测,还可以建立实时评分系统如客户信用评分系统等,也可以为企业数据系统的改进提供重要的依据。

    d) 评估模型的收效

    将模型的结果和投入成本与真实的业务收效相比,最终对数据挖掘过程作出综合评价。

    4 小结
     
    数据挖掘项目在目前,特别是在国内,还处于边界条件尚未明确界分的阶段,并不是很成熟。但是数据挖掘项目的特质之一就是动态性,这种动态性是由它与企业业务的密切结合决定的,它对于业务的辅助作用的力度和直接程度超过了传统的业务支撑系统、mis系统,也超过了数据仓库应用中的报表查询系统;企业对于决策信息的需求,在数据挖掘项目中,找到了前所未有的载体,因此,数据挖掘应用拥有更加广阔深远的前景。随着数据挖掘中某些应用的进一步成熟,数据挖掘将在各大行业中逐步形成有层次的产业链。

    所以,不断地跟踪最新的数据挖掘知识和项目实施方法论,不断地通过数据挖掘项目实践来创造业务效益,应该作为国内信息技术领域在今后一个时期的焦点命题。本文挂靠中国民航飞行学院科研基金,项目名称是“设备虚拟网”,基金编号是j2004-23。

    参考文献

    [1] michael j.a. berry and gordon s. linoff . mastering data mining. john wiley & s isbn 0-471-33123-6,copyright 2000.

    [2] y. vassiliou, maurizio lenzerini, panos vassiliadis. fundamentals of data warehouses november 2002 publisher. springer verlag; 2nd edition (january 17, 2003).

    [3](加)jiawei han micheline kamber. 数据挖掘概念与技术. 机械工业出版社,2001年.

    [4] 萨师煊. 数据库系统概论. 高等教育出版社,2004年.

    [5] 郭崇慧. 数据挖掘教程. 清华大学出版社,2005年.
    展开全文
  • 客户流失及用户画像分析

    千次阅读 2021-01-15 01:38:13
    1 项目背景 在今天产品高度同质化的阶段,市场竞争不断加剧,企业与企业之间的竞争,主要集中在对客户的争夺上。“用户就是上帝”促使众多企业不惜...挖掘出影响用户流失的关键因素,预测客户的转化效果以及用K-means

    1 项目背景

    在今天产品高度同质化的阶段,市场竞争不断加剧,企业与企业之间的竞争,主要集中在对客户的争夺上。“用户就是上帝”促使众多企业不惜代价去争夺尽可能多的新客户。但是,在企业不惜代价发展新用户的过程中,往往会忽视老用户的流失情况,结果就导致出现新用户在源源不断的增加,辛苦找来的老用户却在悄无声息的流失的窘状。
    如何处理客户流失的问题,成为一个非常重要的课题。那么,我们如何从数据汇总挖掘出有价值的信息,来防止客户流失呢?

    2 项目目标

    挖掘出影响用户流失的关键因素,预测客户的转化效果以及用K-means对用户进行画像,
    并针对不同的用户类别,提出可行的营销建议

    3 数据理解

    1.数据概况

    训练集userlostprob_train.txt 共689946条记录,测试集userlostprob_test.txt 共435076条记录,测试集不提供目标变量label,需自行预测。为保护客户隐私,不提供uid等信息。此外,数据经过了脱敏,和实际商品的订单量、浏览量、转化率等有一些差距,但是不会影响这个问题的可解性。

    数据集包含51列变量信息,除去id列和目标变量label外,还有49列变量。

    2.数据指标分析

    观察数据集,并进行指标梳理。除去id和label外,数据指标可以分为三类,一类是订单相关的指标,如入住日期、订单数、取消率等,共10个指标;一类是与客户行为相关的指标,如星级偏好、用户偏好价格等。共17个指标;还有一类是与酒店相关的指标,如酒店评分均值、酒店评分人数、平均价格等,共22个指标。
    在这里插入图片描述

    4 数据处理

    4.1 导入数据

    #导入基础包
    %matplotlib inline
    import pandas as pd
    import numpy as np
    import seaborn as sns
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
    plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
    
    #读取数据
    df = pd.read_csv('./data/userlostprob_train.txt',sep='\t')
    df.head(2)
    

    4.2 查看数据信息

    df.info()
    

    在这里插入图片描述

    4.3 衍生变量

    添加新列:提前预订 = 入住时间-访问时间
    入住时间和访问时间数据格式为’object,需转换成日期型格式

    # 转为日期型格式
    df['arrival']=pd.to_datetime(df['arrival'])
    df['d']=pd.to_datetime(df['d'])
    # 相减得到“提前预定天数”列
    df['day_advanced']=(df['arrival']-df['d']).dt.days
    # 删除原有列
    df=df.drop(['d','arrival'],axis=1)
    

    4.4 异常值处理

    # 查看数值型数据描述统计信息
    df.describe()
    

    通过描述统计观察发现,delta_price1、delta_price2、lowestprice、customer_value_profit、ctrip_profits这几个变量最小值为负值,需要对其处理。同时,结合四分位和极值,发现有极大或极小的异常值,如decisionhabit_user、historyvisit_avghotelnum等,较多字段都存在异常值,对所有字段一并进行处理。

    for col in ['delta_price1','delta_price2','lowestprice']:
        df.loc[df[col]<0,col]=df[col].median()  # 填充中位数
    for col in ['customer_value_profit','ctrip_profits']:
        df.loc[df[col]<0,col]=0  # 填充0
    #极值处理
    for i in df.columns:
        df.loc[df[i]<np.percentile(df[i],1),i]=np.percentile(df[i],1)
        df.loc[df[i]>np.percentile(df[i],99),i]=np.percentile(df[i],99)
    

    4.5 缺失值处理

    #查看各列缺失情况,并统计
    df_count = df.count()
    na_count = len(df) - df_count
    na_rate = na_count/len(df)
    #按values正序排列,不放倒序是为了后边的图形展示排列
    a = na_rate.sort_values(ascending=True) 
    a1 = pd.DataFrame(a)
    
    #绘图查看缺失情况   
    #用来正常展示中文标签
    plt.rcParams['font.sans-serif']=['SimHei']
    x = df.shape[1]
    fig = plt.figure(figsize=(8,12)) #图形大小
    plt.barh(range(x),a1[0],color='steelblue',alpha=1) 
    plt.tick_params(axis='both',labelsize=14)
    plt.xlabel('数据缺失占比') #添加轴标签
    columns1 = a1.index.values.tolist() #列名称
    plt.yticks(range(x),columns1)
    plt.xlim([0,1]) #设置X轴的刻度范围
    for x,y in enumerate(a1[0]):
        plt.text(y,x,'%.3f' %y,va='bottom')
    plt.show()
    

    在这里插入图片描述
    缺失值删除
    特征值中只有iforderpv_24h、sid、h、day_advanced这四个是不存在缺失的,其他的44个特征都是存在缺失值的,并且大部分的缺失值都挺多的,因此需要对缺失值进行处理

    利用dropna(thresh=n)过滤方式,删除行列缺失值大于80%的数据。

    # 删除缺失值比例大于80%的行和列
    print('删除空值前数据维度是:{}'.format(df.shape))
    df.dropna(axis=0,thresh=df.shape[1]*0.2,inplace=True)  
    df.dropna(axis=1,thresh=df.shape[0]*0.2,inplace=True)
    print('删除空值后数据维度是:{}'.format(df.shape))
    
    '''
    删除空值前数据维度是:(689945, 50)
    删除空值后数据维度是:(689870, 49)
    '''
    

    缺失值补充
    趋于正态分布的字段,使用均值填充:businessrate_pre2、cancelrate_pre、businessrate_pre;
    偏态分布的字段,使用中位数填充.。

    df.hist(figsize=(20,20))
    plt.savefig('hist.png')
    

    在这里插入图片描述
    通过上图看出’businessrate_pre’,‘businessrate_pre2’,‘cancelrate_pre’,'customereval_pre2 '这些字段大体服从正态分布,可以用均值填充;其余字段大都呈右偏态分布,右偏分布就不可以用均值填充了,因为会受到极值的影响,但中位数不太受异常值或者极值的影响,使用中位数填充比较合适。

    filter_mean=['businessrate_pre','businessrate_pre2','cancelrate_pre','customereval_pre2 ']
    for i in df.columns:
        if i in filter_mean:
            df[i].fillna(df[i].mean(),inplace=True)
        else:
            df[i].fillna(df[i].median(),inplace=True)
    

    4.6 极值处理

    通过上面数据描述分析,数据集中还存在极值,过大或者过小的值会对模型分析造成影响,这里通过截断填充的方式,分别对极小值和极大值进行处理。
    盖帽法:某连续变量6西格玛之外的记录用正负3西格玛值替代,一般正负3西格玛包含99%的数据,所以默认凡小于百分之一分位数和大于百分之九十九分位数的值用百分之一分位数和百分之九十九分位数代替,俗称盖帽法

    # 盖帽法
    for i in df.columns:
    	#小于1%分位数的用1%分位数填充
        df.loc[df[i]<np.percentile(df[i],1),i]=np.percentile(df[i],1)   
        # 大于99%分位数的用99%分位数填充
        df.loc[df[i]>np.percentile(df[i],99),i]=np.percentile(df[i],99) 
    

    5 特征工程

    5.1 相关性分析

    观察整个数据集可以大体分为两个类别:用户信息和酒店信息。
    用户信息,即主体是用户,如consuming_capacity (消费能力指数)、price_sensitive(价格敏感指数)、starprefer(星级偏好)等,这些变量主要描述的是用户信息;
    酒店信息,即主体是酒店,如hotelcr (当前酒店历史cr),commentnums (当前酒店点评数)、novoters (当前酒店评分人数)等,这些变量主要描述的酒店信息。

    用户特征的相关性分析

    # 用户特征提取
    user_features=['visitnum_oneyear','starprefer','sid','price_sensitive','ordernum_oneyear','ordercanncelednum','ordercanceledprecent','lastpvgap',
                   'lasthtlordergap','landhalfhours','iforderpv_24h','historyvisit_totalordernum','historyvisit_avghotelnum','h',
                   'delta_price2','delta_price1','decisionhabit_user','customer_value_profit','ctrip_profits','cr','consuming_capacity','avgprice']
    #生成用户特征的相关性矩阵
    user_corr=df[user_features].corr()
    
    #绘制用户特征的相关性矩阵热度图
    fig,ax = plt.subplots(figsize=(18, 12))
    sns.heatmap(user_corr, 
                xticklabels=True,
                yticklabels=True, 
                square=False, linewidths=.5, 
                annot=True, cmap="YlGnBu")
    plt.savefig('./用户特征的相关性分析.jpg',dpi=400, bbox_inches='tight')
    plt.show() 
    

    在这里插入图片描述
    从热图中看出:

    • ordernum_oneyear和historyvisit_totalordernum的相关性高达0.93,两者都是表示用户1年内订单数,特征选取时可以只选择其一,这里选择ordernum_oneyear作为用户年订单数的特征;
    • delta_price1和delta_price2的相关性达到了0.91,前者表示用户偏好价格-24小时浏览最多酒店价格,后者表示用户偏好价格-24小时浏览酒店平均价格,一定程度上说明浏览最多的酒店价格影响着平均价格,可以理解为众数和平均数的关系,这里选择PCA提取一个主成分表示用户价格偏好;
    • decisionhabit_user和historyvisit_avghotelnum相关性达到了0.89,前者表示用户决策习惯,后者表示近3个月用户历史日均访问酒店数,说明用户的决策习惯可能是基于用户近3个月的日均访问数判定的,这里选择用PCA提取一个主成分表示用户近期的日均访问量;
    • customer_value_profit和ctrip_profits这两个特征之间相关性达到了0.85,前者表示用户近一年的价值,后者也表示用户价值,细分区别在于衡量的时间长度不同,这里也选择PCA提取一个主成分表示用户价值。

    酒店信息特征的相关性分析

    # 酒店信息特征的相关性分析
    hotel_features=['hotelcr','hoteluv','commentnums','novoters','cancelrate','lowestprice','cr_pre','uv_pre','uv_pre2','businessrate_pre',
                    'businessrate_pre2','customereval_pre2','commentnums_pre','commentnums_pre2','cancelrate_pre','novoters_pre','novoters_pre2',
                    'deltaprice_pre2_t1','lowestprice_pre','lowestprice_pre2','firstorder_bu','historyvisit_visit_detailpagenum']
    #生成酒店特征的相关性矩阵
    user_corr1 = df[user_features].corr()
    
    #绘制用户特征的相关性矩阵热度图
    fig,ax = plt.subplots(figsize=(18, 12))
    sns.heatmap(user_corr1, 
                xticklabels=True,
                yticklabels=True, 
                square=False, linewidths=.5, 
                annot=True, cmap="YlGnBu")
    plt.savefig('./酒店信息特征的相关性分析.jpg',dpi=400, bbox_inches='tight')
    plt.show() 
    

    在这里插入图片描述

    5.2 特征降维

    在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程

    • 主成分分析
      相关性大于80%的变量进行降维
    # 用户价值
    c_value=['customer_value_profit','ctrip_profits']   
    # 用户消费水平
    consume_level=['avgprice','consuming_capacity']   
    # 用户偏好价格
    price_prefer=['delta_price1','delta_price2']     
    # 酒店热度
    hotel_hot=['commentnums','novoters']   
    # 24小时内浏览次数最多的酒店热度
    hotel_hot_pre=['commentnums_pre','novoters_pre']   
    # 24小时内浏览酒店的平均热度
    hotel_hot_pre2=['commentnums_pre2','novoters_pre2']                 
    
    from sklearn.decomposition import PCA
    pca=PCA(n_components=1)
    df['c_value']=pca.fit_transform(df[c_value])
    df['consume_level']=pca.fit_transform(df[consume_level])
    df['price_prefer']=pca.fit_transform(df[price_prefer])
    df['hotel_hot']=pca.fit_transform(df[hotel_hot])
    df['hotel_hot_pre']=pca.fit_transform(df[hotel_hot_pre])
    df['hotel_hot_pre2']=pca.fit_transform(df[hotel_hot_pre2])
    
    df.drop(c_value,axis=1,inplace=True)
    df.drop(consume_level,axis=1,inplace=True)
    df.drop(price_prefer,axis=1,inplace=True)
    df.drop(hotel_hot,axis=1,inplace=True)
    df.drop(hotel_hot_pre,axis=1,inplace=True)
    df.drop(hotel_hot_pre2,axis=1,inplace=True)
    df.drop('historyvisit_totalordernum',axis=1,inplace=True)  ###把重复的一列删了
    print('PCA降维后数据维度是:{}'.format(df.shape))
    
    '''
    PCA降维后数据维度是:(689870, 42)
    '''
    

    5.3 特征预处理

    • 标准化处理
      数据标准化的目的是:处理不同规模和量纲的数据,使其缩放到相同的数据区间和范围
    # 数据标准化
    from sklearn.preprocessing import StandardScaler
    
    y = df['label']
    x = df.drop('label',axis=1)
    scaler = StandardScaler()
    
    X= scaler.fit_transform(x)
    

    6 建模预测

    from sklearn.model_selection import train_test_split, GridSearchCV
    
    X_train,X_test,y_train,y_test = train_test_split(X,y,test_size= 0.2,random_state=420)
    

    6.1 逻辑回归模型

    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import classification_report
    from sklearn import metrics
    
     # 实例化一个LR模型
    lr = LogisticRegression()    
     # 训练模型
    lr.fit(X_train,y_train) 
     # 预测1类的概率
    y_prob = lr.predict_proba(X_test)[:,1]     
     # 模型对测试集的预测结果
    y_pred = lr.predict(X_test)      
     # 获取真阳率、伪阳率、阈值
    fpr_lr,tpr_lr,threshold_lr = metrics.roc_curve(y_test,y_prob)   
    # AUC得分
    auc_lr = metrics.auc(fpr_lr,tpr_lr)  
     # 模型准确率
    score_lr = metrics.accuracy_score(y_test,y_pred)                
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_lr,auc_lr))
    print('============================================================')
    print(classification_report(y_test,y_pred,labels=None,target_names=None,sample_weight=None, digits=2))
    

    在这里插入图片描述

    6.2 朴素贝叶斯

    from sklearn.naive_bayes import GaussianNB
    
    gnb = GaussianNB()                                                # 实例化一个LR模型
    gnb.fit(X_train,y_train)                                          # 训练模型
    y_prob = gnb.predict_proba(X_test)[:,1]                           # 预测1类的概率
    y_pred = gnb.predict(X_test)                                      # 模型对测试集的预测结果
    fpr_gnb,tpr_gnb,threshold_gnb = metrics.roc_curve(y_test,y_prob)  # 获取真阳率、伪阳率、阈值
    auc_gnb = metrics.auc(fpr_gnb,tpr_gnb)                            # AUC得分
    score_gnb = metrics.accuracy_score(y_test,y_pred)                 # 模型准确率
    
    
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_gnb,auc_gnb))
    print('============================================================')
    print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
    

    在这里插入图片描述

    6.3 支持向量机

    from sklearn.svm import SVC
    
    svc = SVC(kernel='rbf',C=1,max_iter=100).fit(X_train,y_train)
    y_prob = svc.decision_function(X_test)                              # 决策边界距离
    y_pred = svc.predict(X_test)                                        # 模型对测试集的预测结果
    fpr_svc,tpr_svc,threshold_svc = metrics.roc_curve(y_test,y_prob)    # 获取真阳率、伪阳率、阈值
    auc_svc = metrics.auc(fpr_svc,tpr_svc)                              # 模型准确率
    score_svc = metrics.accuracy_score(y_test,y_pred)
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_svc,auc_svc))
    print('============================================================')
    print(classification_report(y_test, y_pred, labels=None, target_names=None, sample_weight=None, digits=2))
    

    在这里插入图片描述

    6.4 决策树

    from sklearn import tree
    
    dtc = tree.DecisionTreeClassifier()                              # 建立决策树模型
    dtc.fit(X_train,y_train)                                         # 训练模型
    y_prob = dtc.predict_proba(X_test)[:,1]                          # 预测1类的概率
    y_pred = dtc.predict(X_test)                                     # 模型对测试集的预测结果 
    fpr_dtc,tpr_dtc,threshod_dtc= metrics.roc_curve(y_test,y_prob)   # 获取真阳率、伪阳率、阈值
    score_dtc = metrics.accuracy_score(y_test,y_pred)                
    auc_dtc = metrics.auc(fpr_dtc,tpr_dtc) 
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_dtc,auc_dtc))
    print('============================================================')
    print(classification_report(y_test,y_pred,labels=None,target_names=None,sample_weight=None, digits=2))
    

    在这里插入图片描述

    6.5 随机森林

    from sklearn.ensemble import RandomForestClassifier
    
    rfc = RandomForestClassifier()                                     # 建立随机森林分类器
    rfc.fit(X_train,y_train)                                           # 训练随机森林模型
    y_prob = rfc.predict_proba(X_test)[:,1]                            # 预测1类的概率
    y_pred=rfc.predict(X_test)                                         # 模型对测试集的预测结果
    fpr_rfc,tpr_rfc,threshold_rfc = metrics.roc_curve(y_test,y_prob)   # 获取真阳率、伪阳率、阈值  
    auc_rfc = metrics.auc(fpr_rfc,tpr_rfc)                             # AUC得分
    score_rfc = metrics.accuracy_score(y_test,y_pred)                  # 模型准确率
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_rfc,auc_rfc))
    print('============================================================')
    print(classification_report(y_test,y_pred,labels=None,target_names=None,sample_weight=None, digits=2))
    

    在这里插入图片描述

    6.6 XGBoost

    import xgboost as xgb
    
    # 读入训练数据集和测试集
    dtrain=xgb.DMatrix(X_train,y_train)
    dtest=xgb.DMatrix(X_test)
    
    # 设置xgboost建模参数
    params={'booster':'gbtree','objective': 'binary:logistic','eval_metric': 'auc',
        'max_depth':8,'gamma':0,'lambda':2,'subsample':0.7,'colsample_bytree':0.8,
        'min_child_weight':3,'eta': 0.2,'nthread':8,'silent':1}
    
    # 训练模型
    watchlist = [(dtrain,'train')]
    bst=xgb.train(params,dtrain,num_boost_round=500,evals=watchlist)
    
    # 输入预测为正类的概率值
    y_prob=bst.predict(dtest)
    
    # 设置阈值为0.5,得到测试集的预测结果
    y_pred = (y_prob >= 0.5)*1
    
    # 获取真阳率、伪阳率、阈值
    fpr_xgb,tpr_xgb,threshold_xgb = metrics.roc_curve(y_test,y_prob)   
    auc_xgb = metrics.auc(fpr_xgb,tpr_xgb)    # AUC得分
    score_xgb = metrics.accuracy_score(y_test,y_pred)    # 模型准确率
    print('模型准确率为:{0},AUC得分为:{1}'.format(score_xgb,auc_xgb))
    print('============================================================')
    print(classification_report(y_test,y_pred,labels=None,target_names=None,sample_weight=None, digits=2))
    

    6.7 模型比较

    plt.style.use('bmh')
    plt.figure(figsize=(13,10))
    
    plt.plot(fpr_lr,tpr_lr,label='lr: {0:.3f}'.format(score_lr))            # 逻辑回归
    plt.plot(fpr_gnb,tpr_gnb,label='gnb:{0:.3f}'.format(score_gnb))         # 朴素贝叶斯
    plt.plot(fpr_svc,tpr_svc,label='svc:{0:.3f}'.format(score_svc))         # 支持向量机
    plt.plot(fpr_dtc,tpr_dtc,label='dtc:{0:.3f}'.format(score_dtc))         # 决策树
    plt.plot(fpr_rfc,tpr_rfc,label='rfc:{0:.3f}'.format(score_rfc))         # 随机森林
    plt.plot(fpr_rfc,tpr_rfc,label='xgb:{0:.3f}'.format(score_xgb))         # XGBoost
    
    plt.legend(loc='lower right',prop={'size':25})
    plt.xlabel('伪阳率')
    plt.ylabel('真阳率')
    plt.title('ROC carve')
    plt.savefig('./模型比较图.jpg',dpi=400, bbox_inches='tight')
    plt.show()
    

    在这里插入图片描述

    7 K-means用户画像

    7.1 RFM分析

    RFM模型是衡量客户价值和客户创利能力的重要工具和手段,其有三个指标:最近一次消费时间间隔(Recency),消费频率(Frequency),消费金额(Monetary)。本数据集中三个指标并不都是直接给出,需要进行分析提取。

    Recency:选用lasthtlordergap(距离上次下单时长)此字段。
    Frequency:选用ordernum_oneyear(用户年订单数)此字段。
    Monetary:选用avgprice(平均价格),consuming_capacity(消费能力指数)这两个字段作为消费金额指标,合并为consume_level。

    #字段重名
    rfm = df[['lasthtlordergap','ordernum_oneyear','consume_level']]  
    rfm.rename(columns={'lasthtlordergap':'recency','ordernum_oneyear':'frequency','consume_level':'monetary'},inplace=True)
    
    #利用MinMaxScaler进行归一化处理
    from sklearn.preprocessing import MinMaxScaler
    scaler = MinMaxScaler()
    scaler.fit(rfm)
    rfm = pd.DataFrame(scaler.transform(rfm),columns=['recency','frequency','monetary'])
    
    #分箱
    rfm['R']=pd.qcut(rfm["recency"], 2)
    rfm['F']=pd.qcut(rfm["frequency"], 2)
    rfm['M']=pd.qcut(rfm["monetary"], 2)
    
    # 根据分箱情况进行编码,二分类可以直接用标签编码方式
    from sklearn.preprocessing import LabelEncoder
    rfm['R']=LabelEncoder().fit(rfm['R']).transform(rfm['R'])  
    rfm['F']=LabelEncoder().fit(rfm['F']).transform(rfm['F'])
    rfm['M']=LabelEncoder().fit(rfm['M']).transform(rfm['M'])
    
    #定义RFM模型,需要特别注意的是,R值代表距离上次消费时间间隔,值越小客户价值越高,与F和M值正好相反。
    def get_label(r,f,m):
        if (r==0)&(f==1)&(m==1):
            return '高价值客户'
        if (r==1)&(f==1)&(m==1):
            return '重点保持客户'
        if((r==0)&(f==0)&(m==1)):
            return '重点发展客户'
        if (r==1)&(f==0)&(m==1):
            return '重点挽留客户'
        if (r==0)&(f==1)&(m==0):
            return '一般价值客户'
        if (r==1)&(f==1)&(m==0):
            return '一般保持客户'
        if (r==0)&(f==0)&(m==0):
            return '一般发展客户'
        if (r==1)&(f==0)&(m==0):
            return '潜在客户'
    
    def RFM_convert(df):
        df['Label of Customer']=df.apply(lambda x:get_label(x['R'],x['F'],x['M']),axis=1)
        
        df['R']=np.where(df['R']==0,'高','低')
        df['F']=np.where(df['F']==1,'高','低')
        df['M']=np.where(df['M']==1,'高','低')
        
        return df[['R','F','M','Label of Customer']]
    
    rfm1=RFM_convert(rfm)
    rfm1.head(10)
    

    在这里插入图片描述

    value_counts=rfm1["Label of Customer"].value_counts().values
    labels=rfm1["Label of Customer"].value_counts().index
    explode=[0.1,0.1,0.1,0,0,0,0,0]
    color=['deepskyblue','steelblue','lightskyblue','aliceblue','skyblue','cadetblue','cornflowerblue','dodgerblue']
    plt.figure(figsize=(10, 7))
    
    plt.pie(x=value_counts,labels=labels,autopct='%.2f%%',explode=explode,colors=color,wedgeprops={'linewidth':0.5,'edgecolor':'black'},
    textprops={'fontsize':12,'color':'black'})
    plt.legend(labels,bbox_to_anchor=(1, 1), loc='best', borderaxespad=0.7)
    plt.title('客户类别细分情况')
    plt.show()
    

    在这里插入图片描述

    7.2 构建用户画像

    重要性特征
    由于携程数据集的特征较多,我们可以通过XGBoost的plot_importance来辨别哪些是重要性特征,其原理是F score方差分析法。

    # 导入plot_importance
    from xgboost import plot_importance
    
    # 画柱状图
    fig, ax = plt.subplots(figsize=(15, 15))
    plot_importance(bst, height=0.5, ax=ax, max_num_features=40, color='chocolate')
    plt.savefig('./重要性特征图.jpg', dpi=400, bbox_inches='tight')
    plt.show()
    

    在这里插入图片描述
    从上图可以看到,较为重要的特征为:24小时内是否访问订单填写页(24小时内是否访问订单填写页)、近3个月用户历史日均访问酒店数(historyvisit_avghotelnum)、当前酒店转换率(hotelcr)、当前酒店历史订单取消率(ordercanceledprecent)、星级偏好(starprefer)、用户历史取消率(cancelrate)、 7天内访问酒店详情页数(historyvisit_visit_detailpagenum)、价格敏感指数(price_sensitive)、当前酒店访客量(hoteluv)、浏览最多的酒店商务属性(businessrate_pre)。

    聚类分析
    K-Means算法是一种基于划分的无监督聚类算法,它以 k 为参数,把 n 个数据对象分成 k 个簇,使簇内具有较高的相似度,而簇间的相似度较低。

    # 选取刻画用户的重要指标
    user_feature =  ['decisionhabit_user','ordercanncelednum','ordercanceledprecent',
                    'consume_level','starprefer','lasthtlordergap','lastpvgap',
                    'h','sid','c_value','landhalfhours','price_sensitive',
                    'price_prefer','day_advanced','historyvisit_avghotelnum',
                    'ordernum_oneyear']
    user_attributes = df[user_feature]
    
    # 数据标准化
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    scaler.fit(user_attributes)
    user_attributes = scaler.transform(user_attributes)
    
    #K-Means聚类
    from sklearn.cluster import KMeans
    
    Kmeans = KMeans(n_clusters=3,random_state=13)                                     # 建立KMean模型
    Kmeans.fit(user_attributes)                                                     # 训练模型
    k_char = Kmeans.cluster_centers_                                                  # 得到每个分类的质心
    personas = pd.DataFrame(k_char.T,index=user_feature,columns=['0类','1类','2类'])  # 用户画像表
    personas
    

    在这里插入图片描述

    #绘制热力图
    fig,ax = plt.subplots(figsize=(5, 10))
    sns.heatmap(personas, xticklabels=True,
                yticklabels=True, square=False,
                linewidths=.5, annot=True, cmap="YlGnBu")
                plt.tick_params(axis='both',labelsize=14)
    plt.show() 
    

    在这里插入图片描述
    其中,2类用户的lasthtlordergap(代表RFM模型中的Recency)为0.048非常小(R越小代表客户价值越高),ordernum_oneyear(代表RFM模型中的Frequency)为1.1比较高,consume_level(代表RFM模型中的Monetary)为1.3也几乎是最高的。很明显,2类客户为我们的“高价值客户”;而0类中几乎都是白格子,无论是客户价值还是消费水平值都是最低的,很明显,这一类我们将其归为“低价值客户”;剩下的1类我们将其称为“中等群体”

    plt.figure(figsize=(9,9))
    
    class_k = list(Kmeans.labels_) # 每个类别的用户个数
    percent = [class_k.count(1)/len(user_attributes),
               class_k.count(0)/len(user_attributes),
               class_k.count(2)/len(user_attributes)] # 每个类别用户个数占比
    
    fig, ax = plt.subplots(figsize=(10, 10))
    colors = ['chocolate', 'sandybrown', 'peachpuff']
    types = ['中等群体', '低价值用户', '高价值用户']
    ax.pie(percent, radius=1, autopct='%.2f%%', pctdistance=0.75,
           colors=colors, labels=types)
    ax.pie([1], radius=0.6, colors='w')
    plt.savefig('./用户画像.jpg', dpi=400, bbox_inches='tight')
    plt.show()
    

    在这里插入图片描述

    7.3 用户画像分析

    从三类客户的占比图得知,中等价值用户占所有用户人数的6.65%,可结合该群体流失情况分析流失客户因素,进行该群体市场的开拓。

    低价值用户是潜在客户群体,占比最高,占总用户人数的76.65%,可对该部分用户实施一些营销策略,进而刺激消费。

    高价值用户,能给我们带来较优的收益,可对这类群体实施个性化营销策略。

    展开全文
  • VMware Workstation的关键特性之一就是不需要额外购买计算机,用户就能够创建并使用虚拟机。这给测试及开发团队带来了灵活性,通过使用虚拟环境而不是增加物理硬件,不再需要维护或打补丁,有助于减轻IT的负担。 ...

    VMware Workstation的关键特性之一就是不需要额外购买计算机,用户就能够创建并使用虚拟机。这给测试及开发团队带来了灵活性,通过使用虚拟环境而不是增加物理硬件,不再需要维护或打补丁,有助于减轻IT的负担。 VMware Workstation安装在主机操作系统上,并被看作一个应用程序。Workstation然后将虚拟计算资源映射到计算机的物理资源——CPU、内存、存储以及I/O——而且能够分配这些虚拟资源,创建完整的封装虚拟机。

    由于主机操作系统将Workstation视作一个应用,修改虚拟机时不需要修改计算机的引导分区或者重启系统。可以选择虚拟机并在主机操作系统间无缝切换。 为完成……

    我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

    我原创,你原创,我们的内容世界才会更加精彩!

    【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

    微信公众号

    TechTarget

    官方微博

    TechTarget中国

    电子邮件地址不会被公开。 必填项已用*标注

    评论

    敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

    姓名 *

    电子邮件 *

    站点

    Save my name, email, and website in this browser for the next time I comment.

    VMware Workstation的关键特性之一就是不需要额外购买计算机,用户就能够创建并使用虚拟机。这给测试及开发团队带来了灵活性,通过使用虚拟环境而不是增加物理硬件,不再需要维护或打补丁,有助于减轻IT的负担。

    VMware Workstation安装在主机操作系统上,并被看作一个应用程序。Workstation然后将虚拟计算资源映射到计算机的物理资源——CPU、内存、存储以及I/O——而且能够分配这些虚拟资源,创建完整的封装虚拟机。由于主机操作系统将Workstation视作一个应用,修改虚拟机时不需要修改计算机的引导分区或者重启系统。可以选择虚拟机并在主机操作系统间无缝切换。

    为完成配置过程,需要给新虚拟机准备特定的操作系统镜像。例如,如果你在创建Window Server虚拟机,启动新虚拟机然后将Windows Server安装CD或镜像放在手边。新虚拟机启动时,正常情况下将会开始安装客户操作系统。当你计划使用安装了同一个操作系统的多个虚拟机时,请记住针对特定的客户操作系统可能需要额外购买许可。

    网络设置同样很灵活。如果DHCP服务器可用,Workstation能够给每台虚拟机分配一个新的IP地址。如果DHCP服务器不可用,Workstation允许多台虚拟机共享主机的IP地址。如果有多台虚拟机运行在计算机上,Workstation能够支持隔离的虚拟网络,允许虚拟机与主机通信,但不与局域网交换数据。

    有必要指出Workstation仅能映射并分配现有的计算资源给虚拟机,无法创建新计算资源。分配给虚拟机的资源被从计算机总的可用资源中排除出去了。主机系统必须有足够多的可用资源运行主机操作系统、在主机上打开的应用、虚拟机客户操作系统以及虚拟机客户应用程序—如果启动了多个虚拟机的话,可能有多个客户操作系统以及应用。

    虚拟机配置过高将占用过多的资源,配置过低虚拟机低性能可能达不到要求—或者根本无法运行。也有可能虚拟机配置没有问题,但主机系统没有足够多的资源运行特定应用。小心分配新资源并在必要时升级主机计算机。关闭虚拟机能够释放虚拟资源为主机上的其他虚拟机所用。

    展开全文
  •   数据预处理与特征工程包括Data PreProcessing(数据预处理)、Feature Extraction(特征提取)、Feature Selection(特征选择)和Feature construction(特征构造)等步骤 1.数据预处理   数据预处理又包括...

    引言

      数据预处理与特征工程包括Data PreProcessing(数据预处理)、Feature Extraction(特征提取)、Feature Selection(特征选择)和Feature construction(特征构造)等步骤

    1.数据预处理

      数据预处理又包括数据清洗与特征预处理两步

    1.1 数据清洗

      数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值等

    1.1.1 异常值处理

      异常值是否需要处理需要视具体情况而定,因为有些异常值可能蕴含着有用的信息。

    1. 简单统计量分析
      在进行异常值分析时,可以先对变量做一个描述性统计,进而查看哪些数据是不合理的。最常用的统计量是最大值和最小值,用来判断这个变量的取值是否超出了合理范围。如客户年龄的最大值为199岁,则判断该变量的取值存在异常。

    2. 通过箱线图分析删除异常值;
      箱型图提供了识别异常值的一个标准:异常值通常被定义为小于 Q L − 1.5 I Q R Q_L-1.5IQR QL1.5IQR或大于 Q U + 1.5 I Q R Q_U+1.5IQR QU+1.5IQR的值。 Q L Q_L QL称为下四分位数,表示全部观察值中有四分之一的数据取值比它小; Q U Q_U QU称为上四分位数,表示全部观察值中有四分之一的数据取值比它大;IQR称为四分位数间距,是上四分位数 Q U Q_U QU与下四分位数 Q L Q_L QL之差,其间包含了全部观察值的一半。这里的1.5可以根据问题的不同进行改变。

      箱型图依据实际数据绘制,对数据没有任何限制性要求,如服从某种特定的分布形式,它只是真实直观地表现数据分布的本来面貌;另一方面,箱型图判断异常值的标准以四分位数和四分位距为基础,四分位数具有一定的鲁棒性:多达25%的数据可以变得任意远而不会严重扰动四分位数,所以异常值不能对这个标准施加影响。由此可见,箱型图识别异常值的结果比较客观,在识别异常值方面有一定的优越性

      import numpy as np
      import pandas as pd
      import matplotlib.pyplot as plt
      import seaborn as sns
      
      
      def box_plot_outliers(data_ser, box_scale):
          """
          利用箱线图去除异常值
          :param data_ser: 接收 pandas.Series 数据格式
          :param box_scale: 箱线图尺度,
          :return:
          """
          iqr = box_scale*(data_ser.quantile(0.75) - data_ser.quantile(0.25))
          # Q_L - 1.5IQR为下界
          val_low = data_ser.quantile(0.25) - iqr
          # Q_U + 1.5IQR为上界
          val_up = data_ser.quantile(0.75) + iqr
          rule_low = (data_ser < val_low)
          rule_up = (data_ser > val_up)
          return (rule_low, rule_up), (val_low, val_up)
      
      def outliers_proc(data, col_name, scale=1.5):
          """
          用于清洗异常值,默认用 box_plot(scale=1.5)进行清洗
          :param data: 接收 pandas 数据格式
          :param col_name: pandas 列名
          :param scale: 尺度
          :return:
          """
          # 复制数据
          data_n = data.copy()
          # 针对哪一个特征清洗异常值
          data_series = data_n[col_name]
          # 返回异常值索引(bool格式)与上下边界
          rule, value = box_plot_outliers(data_series, box_scale=scale)
          # 得到异常值得索引
          # |会先转化成二进制,然后相同位数的数字有1则为1,否则为0
          index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
          print("Delete number is: {}".format(len(index)))
      
          # 删除异常值
          data_n = data_n.drop(index)
          # 重置索引
          data_n.reset_index(drop=True, inplace=True)
          print("Now column number is: {}".format(data_n.shape[0]))
          # 统计低于下界的异常值
          index_low = np.arange(data_series.shape[0])[rule[0]]
          outliers = data_series.iloc[index_low]
          print("Description of data less than the lower bound is:")
          print(pd.Series(outliers).describe())
      
          # 统计高于上界的异常值
          index_up = np.arange(data_series.shape[0])[rule[1]]
          outliers = data_series.iloc[index_up]
          print("Description of data larger than the upper bound is:")
          print(pd.Series(outliers).describe())
      
          # 查看删除异常值前后图形的区别
          fig, ax = plt.subplots(1, 2, figsize=(10, 7))
          sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
          sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
          return data_n
      
    3. 通过 3 σ 3σ 3σ原则删除异常值

      如果数据服从正态分布,在 3 σ 3σ 3σ原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值。在正态分布的假设下,距离平均值 3 σ 3σ 3σ之外的值出现的概率为P(x-u |> 3 σ 3σ 3σ)≤0.003,属于极个别的小概率事件。
      如果数据不服从正态分布,也可以用远离平均值的标准差倍数来描述。

    4. 长尾截断;

      长尾截断主要也是分布不符合正态分布,而是类似于“长尾”。例如房价中,低价占大部分,豪宅属于小部分。应对这种数据分布,一般可以通过神奇的log化处理转化类近似正态分布或者使用Box-Cox转换将数据转换为正态。数据预处理—5.box-cox变换及python实现

    5. 将异常值视为缺失值,利用缺失处理方法进行处理

    1.1.2 缺失值处理

      缺失值处理的方法可分为3种:删除记录、数据插补和不处理

    1. 不处理(针对类似 XGBoost 等树模型);
    2. 删除(缺失数据太多);
    3. 插值补全,包括均值/中位数/众数/使用固定值/最近邻插补/回归方法/插值法(拉格朗日插值法、牛顿插值法)等;
      前面几种方面使用pandas中的fillna函数可以轻松实现
      插值法数据预处理—7.数据插补之拉格朗日插值法、牛顿差值法及python实现
      回归方法:对带有缺失值的变量,根据已有数据和其有关的其他变量(因变量)的数据建立拟合模型来预测缺失的属性值。6.4 随机森林实战这里面使用了随机森林来预测年龄中的缺失值作为填充
    4. 分箱,缺失值一个箱;
      见后面

    1.2 特征预处理

    1.2.1 数值型特征无量纲化

      数值型特征无量纲化是为了消除样本不同属性具有不同量级(大小)时的影响,不仅提高精度,而且提高迭代精度

    1. 标准化(转换为标准正态分布);

      from sklearn.preprocessing import MinMaxScaler,StandardScaler
      # 标准化
      scaler = StandardScaler()
      result = scaler.fit_transform(data)  # 将data标准化
      
      scaler.inverse_transform(result)  # 将标准化结果逆转
      

      优点:
      标准化最大的优点就是简单,容易计算,Z-Score能够应用于数值型的数据,并且不受数据量级(数据多少)的影响,因为它本身的作用就是消除量级给分析带来的不便。
      缺点:

      • 估算Z-Score需要总体的平均值与方差,但是这一值在真实的分析与挖掘中很难得到,大多数情况下是用样本的均值与标准差替代。

      • Z-Score对于数据的分布有一定的要求,正态分布是最有利于Z-Score计算的。

      • Z-Score消除了数据具有的实际意义,属性A的Z-Score与属性B的Z-Score与他们各自的分数不再有关系,因此Z-Score的结果只能用于比较数据间的结果,数据的真实意义还需要还原原值。

      • 在存在异常值时无法保证平衡的特征尺度。

    2. 归一化(转换到 [0,1] 区间);

      from sklearn.preprocessing import MinMaxScaler,StandardScaler
      # 归一化
      scaler = MinMaxScaler()
      result = scaler.fit_transform(data)  # 将data归一化
      
      scaler.inverse_transform(result) # 将归一化结果逆转
      

      缺点:

      • 这种方法有一个缺陷就是当有新数据加入时,可能导致max和min的变化,需要重新定义。

      • MinMaxScaler对异常值的存在非常敏感。

    3. MaxAbs归一化
      定义:单独地缩放和转换每个特征,使得训练集中的每个特征的最大绝对值将为1.0,将属性缩放到[-1,1]。它不会移动/居中数据,因此不会破坏任何稀疏性。
      在这里插入图片描述

      from sklearn.preprocessing import MaxAbsScaler
      maxAbsScaler = MaxAbsScaler().fit(X_train) 
      maxAbsScaler.transform(X_train)
      

      缺点:

      1. 这种方法有一个缺陷就是当有新数据加入时,可能导致max和min的变化,需要重新定义;
      2. 对异常值的存在非常敏感
    4. 正态分布化(Normalization)
      定义:正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1)。Normalization主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。
      在这里插入图片描述
      适用情形:如果要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。该方法是文本分类和聚类分析中经常使用的向量空间模型(Vector Space Model)的基础。

      from sklearn.preprocessing import Normalizer
      #正态归一化,返回值为正态归一化后的数据 
      normalizer = Normalizer(norm='l2').fit(X_train) 
      normalizer.transform(X_train)
      
    5. 针对幂律分布,可以采用公式: l o g 1 + x 1 + m e d i a n log\frac{1+x}{1+median} log1+median1+x

    1.2.2 连续数值型特征分箱

      一些数据挖掘算法,特别是某些分类算法,如ID3算法、Apriori算法等,要求数据是分类属性形式。这样,常常需要将连续属性变换成分类属性,即连续属性离散化。
      连续属性离散化的优势:

    • 离散后稀疏向量内积乘法运算速度更快,计算结果也方便存储,容易扩展;
    • 离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大的干扰;
    • LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,能够提升模型的表达能力,加大拟合;
    • 离散后特征可以进行特征交叉,提升表达能力,由 M+N 个变量编程 M*N 个变量,进一步引入非线形,提升了表达能力;
    • 特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化

      连续属性离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。所以,连续属性离散化涉及两个子任务:确定分类数以及如何将连续属性值映射到这些分类值。特征分箱可分为无监督分箱与有监督分箱方法。

    1.2.2.1 无监督分箱法
    1. 自定义分箱
      定义:自定义分箱,是根据业务经验或者常识等自行设定划分的区间,然后将原始数据归类到各个区间中。

    2. 等距分箱
      将属性的值域分成具有相同宽度的区间,区间的个数由数据本身的特点决定或者用户指定。等距分箱只考虑区间宽度相同,每个区间里面的实例数量可能不等。

      	import pandas as pd
      import numpy as np
      
      df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                         [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]], columns=['age', 'Y'])
      k = 4
      # 等宽离散化,各个类别依次命名为0,1,2,3
      df['age_bin'] = pd.cut(df['age'], k)
      df['age_bin_label'] = pd.cut(df['age'], k, labels=range(k))
      print(df)
      
         age  Y          age_bin age_bin_label
      0   22  1  (12.947, 26.25]             0
      1   13  1  (12.947, 26.25]             0
      2   33  1    (26.25, 39.5]             1
      3   52  0    (39.5, 52.75]             2
      4   16  0  (12.947, 26.25]             0
      5   42  1    (39.5, 52.75]             2
      6   53  1    (52.75, 66.0]             3
      7   39  1    (26.25, 39.5]             1
      8   26  0  (12.947, 26.25]             0
      9   66  0    (52.75, 66.0]             3
      

      缺点:一方面需要人为规定划分的区间个数,另一方面,它对离群点比较敏感,倾向于不均匀地把属性值分布到各个区间。有些区间包含许多数据,而另外一些区间的数据极少,这样会严重损坏建立的决策模型。

    3. 等频分箱;
      将相同数量的记录放进每个区间。

      import pandas as pd
      import numpy as np
      
      df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                         [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]], columns=['age', 'Y'])
      k = 5
      # 等频离散化,各个类别依次命名为0,1,2,3,4
      df['age_bin'] = pd.qcut(df['age'], k)
      df['age_bin_label'] = pd.qcut(df['age'], k, labels=range(k))
      print(df)
      
         age  Y         age_bin age_bin_label
      0   22  1    (20.8, 30.2]             1
      1   13  1  (12.999, 20.8]             0
      2   33  1    (30.2, 40.2]             2
      3   52  0    (40.2, 52.2]             3
      4   16  0  (12.999, 20.8]             0
      5   42  1    (40.2, 52.2]             3
      6   53  1    (52.2, 66.0]             4
      7   39  1    (30.2, 40.2]             2
      8   26  0    (20.8, 30.2]             1
      9   66  0    (52.2, 66.0]             4
      

      缺点:
      等频法虽然避免了等距分箱问题的产生,却可能将相同的数据值分到不同的区间,以满足每个区间中固定的数据个数。

    4. 基于聚类分箱
      定义:基于k均值聚类的分箱方法,k均值聚类法将观测值聚为k类,但在聚类过程中需要保证分箱的有序性,第一个分箱中所有观测值都要小于第二个分箱中的观测值,第二个分箱中所有观测值都要小于第三个分箱中的观测值,以此类推。
      聚类分箱具体步骤:

      1. 对预处理后的数据进行归一化处理。
      2. 将归一化处理过的数据,应用k-means聚类算法,划分为多个区间:采用等距法设定k-means聚类算法的初始中心,得到聚类中心。
      3. 在得到聚类中心后将相邻的聚类中心的中点作为分类的划分点,将各个对象加入到距离最近的类中,从而将数据划分为多个区间。
      4. 重新计算每个聚类中心,然后重新划分数据,直到每个聚类中心不再变化,得到最终的聚类结果。
      import pandas as pd
      import numpy as np
      from sklearn.cluster import KMeans
      
      k = 4
      df = pd.DataFrame([[22, 1], [13, 1], [33, 1],
                         [52, 0], [16, 0], [42, 1], [53, 1], [39, 1], [26, 0], [66, 0]],
                        columns=['age', 'Y'])
      # k为聚成几类
      kmodel = KMeans(n_clusters=k)
      # 训练模型
      kmodel.fit(df['age'].values.reshape(len(df), 1))
      # 求聚类中心
      c = pd.DataFrame(kmodel.cluster_centers_,columns=['聚类中心'])
      # 排序  
      c = c.sort_values(by='聚类中心')
      # 用滑动窗口求均值的方法求相邻两项求中点,作为边界点
      w = c.rolling(window=2).mean().iloc[1:]
      # 把首末边界点加上
      w = [0] + list(w['聚类中心'].values) +[df['age'].max()]
      #
      df['age_bins'] = pd.cut(df['age'], w)
      df['age_bins_label'] = pd.cut(df['age'], w, labels=range(k))
      print(df)
      
         age  Y         age_bins age_bins_label
      0   22  1    (0.0, 28.625]              0
      1   13  1    (0.0, 28.625]              0
      2   33  1  (28.625, 45.25]              1
      3   52  0   (45.25, 59.25]              2
      4   16  0    (0.0, 28.625]              0
      5   42  1  (28.625, 45.25]              1
      6   53  1   (45.25, 59.25]              2
      7   39  1  (28.625, 45.25]              1
      8   26  0    (0.0, 28.625]              0
      9   66  0    (59.25, 66.0]              3
      
    5. 二值化分箱
      定义:二值化可以将数值型(numerical)的特征进行阀值化得到boolean型数据。这对于下游的概率估计来说可能很有用(比如:数据分布为Bernoulli分布时)。定量特征二值化的核心在于设定一个阈值,大于阈值的赋值为1,小于等于阈值的赋值为0。

      from sklearn.preprocessing import Binarizer  
      # Binarizer函数也可以设定一个阈值,结果数据值大于阈值的为1,小于阈值的为0 
      binarizer = Binarizer(threshold=0.0).fit(X_train) 
      binarizer.transform(X_train)
      
    1.2.2.2 有监督分箱法
    1. 卡方分箱
      定义:自底向上的(即基于合并的)数据离散化方法。它依赖于卡方检验:具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。
      基本思想:对于精确的离散化,相对类频率在一个区间内应当完全一致。因此,如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并,否则,它们应当保持分开(组内的差别很小,组间的差别很大)。而低卡方值表明它们具有相似的类分布
      卡方分箱的具体步骤:
      在这里插入图片描述
      在这里插入图片描述
      连续变量的卡方分箱,返回分箱点,下面是在申请评分卡中,进行卡方分箱的函数
      def AssignGroup(x, bin):
          """
          将超过100个的属性值调整到100个
          :param x: 属性值
          :param bin: 99个分割点
          :return: 调整后的值
          """
          N = len(bin)
          if x <= min(bin):
              return min(bin)
          elif x > max(bin):
              return 10e10
          else:
              for i in range(N - 1):
                  if bin[i] < x <= bin[i + 1]:
                      return bin[i + 1]
       def Chi2(df, total_col, bad_col, overallRate):
          '''
          # 计算卡方值
          :param df: the dataset containing the total count and bad count
          :param total_col: total count of each value in the variable
          :param bad_col: bad count of each value in the variable
          :param overallRate: the overall bad rate of the training set—逾期率
          :return: the chi-square value
          '''
          df2 = df.copy()
          df2['expected'] = df[total_col].apply(lambda x: x * overallRate)
          combined = zip(df2['expected'], df2[bad_col])
          chi = [(i[0] - i[1]) ** 2 / i[0] for i in combined]
          chi2 = sum(chi)
          return chi2
      
      def ChiMerge_MaxInterval(df, col, target, max_interval=5):
          '''
          通过指定最大分箱数,使用卡方值拆分连续变量
          :param df: the dataframe containing splitted column, and target column with 1-0
          :param col: splitted column
          :param target: target column with 1-0
          :param max_interval: 最大分箱数
          :return: 返回分箱点
          '''
          colLevels = sorted(list(set(df[col])))
          N_distinct = len(colLevels)
          if N_distinct <= max_interval:
              print("The number of original levels for {} is less than or equal to max intervals".format(col))
              return colLevels[:-1]
          else:
              # 如果属性过多,则时间代价较大,不妨取100个属性进行分箱
              if N_distinct > 100:
                  ind_x = [int(i / 100.0 * N_distinct) for i in range(1, 100)]
                  split_x = [colLevels[i] for i in ind_x]
                  # 超过100个属性值调整为100个
                  df['temp'] = df[col].map(lambda x: AssignGroup(x, split_x))
              else:
                  df['temp'] = df[col]
              # Step 1: group the dataset by col and work out the total count & bad count in each level of the raw column
              # 按col对数据集进行分组,并计算出total count & bad count
              total = df.groupby(['temp'])[target].count()
              total = pd.DataFrame({'total': total})
              bad = df.groupby(['temp'])[target].sum()
              bad = pd.DataFrame({'bad': bad})
              regroup = total.merge(bad, left_index=True, right_index=True, how='left')
              regroup.reset_index(level=0, inplace=True)
              N = sum(regroup['total'])
              B = sum(regroup['bad'])
              # the overall bad rate will be used in calculating expected bad count
              # 计算总的逾期率
              overallRate = B * 1.0 / N
              # initially, each single attribute forms a single interval
              # since we always combined the neighbours of intervals, we need to sort the attributes
              colLevels = sorted(list(set(df['temp'])))
              groupIntervals = [[i] for i in colLevels]
              groupNum = len(groupIntervals)
              # 终止条件:在迭代的每个步骤中,间隔数等于预先指定的阈值(最大分箱数),我们计算每个属性的卡方值
              while (len(groupIntervals) > max_interval):
                  chisqList = []
                  for interval in groupIntervals:
                      df2 = regroup.loc[regroup['temp'].isin(interval)]
                      chisq = Chi2(df2, 'total', 'bad', overallRate)
                      chisqList.append(chisq)
                  # 找到最小卡方值的位置,并将该卡方值与左右两侧相邻的较小的卡方值合并
                  min_position = chisqList.index(min(chisqList))
                  if min_position == 0:
                      combinedPosition = 1
                  elif min_position == groupNum - 1:
                      combinedPosition = min_position - 1
                  else:
                      if chisqList[min_position - 1] <= chisqList[min_position + 1]:
                          combinedPosition = min_position - 1
                      else:
                          combinedPosition = min_position + 1
                  groupIntervals[min_position] = groupIntervals[min_position] + groupIntervals[combinedPosition]
                  # after combining two intervals, we need to remove one of them
                  groupIntervals.remove(groupIntervals[combinedPosition])
                  groupNum = len(groupIntervals)
              groupIntervals = [sorted(i) for i in groupIntervals]
              # 取最大的点
              cutOffPoints = [i[-1] for i in groupIntervals[:-1]]
              del df['temp']
              return cutOffPoints
      
      或者参考这个创建卡方分箱脚本
    2. Best-KS 分箱(类似利用基尼指数进行二分类);
      在这里插入图片描述
      下面是KS值计算公式介绍:
      在这里插入图片描述
    def calc_ks(count, idx):
        """
        计算各分组的KS值
        :param count: DataFrame 待分箱变量各取值的正负样本数
        :param group: list 单个分组信息
        :return: 该分箱的ks值
    
        计算公式:KS_i = |sum_i / sum_T - (size_i - sum_i)/ (size_T - sum_T)|
        """
        # 计算每个评分区间的好坏账户数。
        # 计算各每个评分区间的累计好账户数占总好账户数比率(good %)和累计坏账户数占总坏账户数比率(bad %)。
        # 计算每个评分区间累计坏账户比与累计好账户占比差的绝对值(累计good % -累计bad %),然后对这些绝对值取最大值记得到KS值
        ks = 0.0
        # 计算全体样本中好坏样本的比重(左开右闭区间)
        good = count[1].iloc[0:idx + 1].sum() / count[1].sum() if count[1].sum()!=0 else 1
        bad = count[0].iloc[0:idx + 1].sum() / count[0].sum() if count[0].sum()!=0 else 1
        ks += abs(good - bad)
        
        good = count[1].iloc[idx + 1:].sum() / count[1].sum() if count[1].sum()!=0 else 1
        bad = count[0].iloc[idx + 1:].sum() / count[0].sum() if count[0].sum()!=0 else 1
        ks += abs(good - bad)
        return ks
    

    或者参考特征工程之分箱–Best-KS分箱
    3. 决策树分箱;
    决策树分箱步骤为:

    1. 利用sklearn决策树,DecisionTreeClassifier的.tree_属性获得决策树的节点划分值;
    2. 基于上述得到的划分值,利用pandas.cut函数对变量进行分箱;
    3. 计算各个分箱的WOE、IV值。
      具体可参考这篇博客基于sklearn决策树的最优分箱与IV值计算-Python实现

    1.2.3 统计变换

      统计变换的主要作用在于它能帮助稳定方差,始终保持分布接近于正态分布并使得数据与分布的平均值无关。
      数据右偏的话可以对所有数据取对数、取平方根等,它的原理是因为这样的变换的导数是逐渐减小的,也就是说它的增速逐渐减缓,所以就可以把大的数据向左移,使数据接近正态分布。 如果左偏的话可以取相反数转化为右偏的情况。
    通常来说,可以尝试一下几种方法:
    如果数据高度偏态,则使用对数变换

    1. 对数变换 即将原始数据X的对数值作为新的分布数据:

      x = np.log(x)
      

      当原始数据中有小值及零时, l o g ( 1 + x ) log{(1+x)} log(1+x)

      x = np.log1p(x)
      

    如果数据轻度偏态,则使用平方根变换

    1. 平方根变换 即将原始数据X的平方根作为新的分布数据
      x = np.sqrt(x)
      

    如果数据的两端波动较大,则使用倒数变换

    1. 倒数变换 即将原始数据X的倒数作为新的分析数据

      x = 1 / x
      
    2. box-cox变换
      定义:Box-Cox 变换是另一种流行的幂变换函数簇中的一个函数。该函数有一个前提条件,即数值型数值必须先变换为正数(与 log 变换所要求的一样)。如果数值是负的,可以利用常数对数值进行偏移。

      ## Import necessary modules 
      from scipy.special import boxcox1p
      from scipy.stats import boxcox_normmax
      
      def fixing_skewness(df):
          """
          This function takes in a dataframe and return fixed skewed dataframe
          """
          # 得到所有非类别型变量
          numeric_feats = df.dtypes[df.dtypes != "object"].index
      
          # 计算所有非类别型特征的偏态并排序
          skewed_feats = df[numeric_feats].apply(lambda x: x.skew()).sort_values(ascending=False)
          # 对偏态大于0.5的进行修正,大于0是右偏,小于0是左偏
          high_skew = skewed_feats[abs(skewed_feats) > 0.5]
          skewed_features = high_skew.index
      
          # 修正
          for feat in skewed_features:
          	# 这里是+1是保证数据非负,否则会弹出错误,没有其他含义,不会影响对偏态的修正
              df[feat] = boxcox1p(df[feat], boxcox_normmax(df[feat] + 1))
      

    1.2.4 类别特征编码

    1. 标签编码(LabelEncode)
      定义:LabelEncoder是对不连续的数字或者文本进行编号,编码值介于0和n_classes-1之间的标签。
      优点:相对于OneHot编码,LabelEncoder编码占用内存空间小,并且支持文本特征编码。
      缺点:它隐含了一个假设:不同的类别之间,存在一种顺序关系。在具体的代码实现里,LabelEncoder会对定性特征列中的所有独特数据进行一次排序,从而得出从原始输入到整数的映射。应用较少,一般在树模型中可以使用。

      from sklearn.preprocessing import LabelEncoder 
      le = LabelEncoder() 
      le.fit(["paris", "paris", "tokyo", "amsterdam"])  
      print('特征:{}'.format(list(le.classes_)))  
      # 输出 特征:['amsterdam', 'paris', 'tokyo']  
      print('转换标签值:{}'.format(le.transform(["tokyo", "tokyo", "paris"])))  
      # 输出 转换标签值:array([2, 2, 1]...)  
      print('特征标签值反转:{}'.format(list(le.inverse_transform([2, 2, 1]))))  
      # 输出 特征标签值反转:['tokyo', 'tokyo', 'paris']
      
    2. 独热编码(OneHotEncode)

      为什么要使用独热编码?
      独热编码是因为大部分算法是基于向量空间中的度量来进行计算的,为了使非偏序关系的变量取值不具有偏序性,并且到圆点是等距的。使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。

      为什么特征向量要映射到欧式空间?
      将离散特征通过one-hot编码映射到欧式空间,是因为,在回归、分类、聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算。

      优点:独热编码解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有0和1,不同的类型存储在垂直的空间。
      缺点:当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用PCA来减少维度。而且one hot encoding+PCA这种组合在实际中也非常有用。

      from sklearn.preprocessing import OneHotEncoder  
      enc = OneHotEncoder() 
      enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])    
      # fit来学习编码 
      enc.transform([[0, 1, 3]]).toarray()    
      # 进行编码  
      # 输出:array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
      
    3. 标签二值化(LabelBinarizer)
      定义:功能与OneHotEncoder一样,但是OneHotEncode只能对数值型变量二值化,无法直接对字符串型的类别变量编码,而LabelBinarizer可以直接对字符型变量二值化。

      from sklearn.preprocessing import LabelBinarizer  
      lb = LabelBinarizer() 
      lb.fit([1, 2, 6, 4, 2])  
      print(lb.classes_) 
      # 输出 array([1, 2, 4, 6])  
      print(lb.transform([1, 6])) 
      # 输出 array([[1, 0, 0, 0],
                    [0, 0, 0, 1]])  
      print(lb.fit_transform(['yes', 'no', 'no', 'yes'])) 
      # 输出 array([[1],
                    [0],
                    [0],
                    [1]])
      
    4. 多标签二值化(MultiLabelBinarizer)
      定义:用于label encoding,生成一个(n_examples * n_classes)大小的0~1矩阵,每个样本可能对应多个label。
      适用情形:

      每个特征中有多个文本单词。
      用户兴趣特征(如特征值:”健身 电影 音乐”)适合使用多标签二值化,因为每个用户可以同时存在多种兴趣爱好。
      多分类类别值编码的情况。
      电影分类标签中(如:[action, horror]和[romance, commedy])需要先进行多标签二值化,然后使用二值化后的值作为训练数据的标签值。

      from sklearn.preprocessing import MultiLabelBinarizer  
      mlb = MultiLabelBinarizer()  
      print(mlb.fit_transform([(1, 2), (3,)]))  
      # 输出 array([[1, 1, 0],
              [0, 0, 1]])  
      print(mlb.classes_)  
      # 输出:array([1, 2, 3])  
      print(mlb.fit_transform([{'sci-fi', 'thriller'}, {'comedy'}]))  
      # 输出:array([[0, 1, 1],
              [1, 0, 0]])  
      print(list(mlb.classes_))  
      # 输出:['comedy', 'sci-fi', 'thriller']
      
    5. 平均数编码(Mean Encoding)
      定义:平均数编码(mean encoding)的编码方法,在贝叶斯的架构下,利用所要预测的因变量(target variable),有监督地确定最适合这个定性特征的编码方式。
      适用情形:平均数编码(mean encoding),针对高基数 类别特征的有监督编码。当一个类别特征列包括了极多不同类别时(如家庭地址,动辄上万)时,可以采用。
      高基数定性特征的例子:IP地址、电子邮件域名、城市名、家庭住址、街道、产品号码。

      为什么要用平均数编码?

      • 如果某一个特征是定性的(categorical),而这个特征的可能值非常多(高基数),那么平均数编码(mean encoding)是一种高效的编码方式。在实际应用中,这类特征工程能极大提升模型的性能。
      • 因为定性特征表示某个数据属于一个特定的类别,所以在数值上,定性特征值通常是从0到n的离散整数。例子:花瓣的颜色(红、黄、蓝)、性别(男、女)、地址、某一列特征是否存在缺失值(这种NA 指示列常常会提供有效的额外信息)。
      • 一般情况下,针对定性特征,我们只需要使用sklearn的OneHotEncoder或LabelEncoder进行编码,这类简单的预处理能够满足大多数数据挖掘算法的需求。定性特征的基数(cardinality)指的是这个定性特征所有可能的不同值的数量。在高基数(high cardinality)的定性特征面前,这些数据预处理的方法往往得不到令人满意的结果。

      优点:和独热编码相比,节省内存、减少算法计算时间、有效增强模型表现。
      代码部分参考:平均数编码:针对高基数定性特征(类别特征)的数据预处理/特征工程

    2.特征选择

      特征选择的目标是寻找最优特征子集。特征选择能剔除不相关(irrelevant)或冗余(redundant )的特征,从而达到减少特征个数,提高模型精确度,减少运行时间的目的。另一方面,选取出真正相关的特征简化模型,协助理解数据产生的过程。
    特征选择的一般过程如下:

    生成子集:搜索特征子集,为评价函数提供特征子集
    评价函数:评价特征子集的好坏
    停止准则:与评价函数相关,一般是阈值,评价函数达到一定标准后就可停止搜索
    验证过程:在验证数据集上验证选出来的特征子集的有效性

    根据特征选择的形式,可分为三大类:

    Filter(过滤式):按照发散性或相关性对各个特征进行评分,设定阈值或者待选择特征的个数进行筛选
    Wrapper(包裹式):根据目标函数(往往是预测效果评分),每次选择若干特征,或者排除若干特征
    Embedded(嵌入式):先使用某些机器学习的模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征(类似于Filter,只不过系数是通过训练得来的)

    2.1 Filter(过滤式)

      过滤式的基本想法是:分别对每个特征 x i x_i xi ,计算 x i x_i xi 相对于类别标签 y y y 的信息量 S ( i ) S(i) S(i) ,得到 n n n 个结果。然后将 n n n S ( i ) S(i) S(i) 按照从大到小排序,输出前 k k k 个特征。显然,这样复杂度大大降低。那么关键的问题就是使用什么样的方法来度量 S ( i ) S(i) S(i) ,我们的目标是选取与 y y y 关联最密切的一些 特征 x i x_i xi
    下面介绍一些指标:

    Pearson相关系数
    卡方验证
    互信息和最大信息系数
    距离相关系数
    方差选择法

    2.1.1 Pearson相关系数

      皮尔森相关系数是一种最简单的,能帮助理解特征和响应变量之间关系的方法,衡量的是变量之间的线性相关性,结果的取值区间为[-1,1] , -1 表示完全的负相关(这个变量下降,那个就会上升), +1 表示完全的正相关, 0 表示没有线性相关性。Scipy的pearsonr方法能够同时计算相关系数和p-value。

    import numpy as np
    from scipy.stats import pearsonr
    
    np.random.seed(0)
    size = 300
    x = np.random.normal(0, 1, size)
    print("Lower noise:", pearsonr(x, x + np.random.normal(0, 1, size)))
    print("Higher noise:", pearsonr(x, x + np.random.normal(0, 10, size)))
    
    
    from sklearn.feature_selection import SelectKBest
    # 选择K个最好的特征,返回选择特征后的数据
    # 第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
    # 参数k为选择的特征个数
    SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
    

    Pearson相关系数的一个明显缺陷是:作为特征排序机制,他只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应的关系,Pearson相关性也可能会接近 0 。

    2.1.2 卡方验证

      经典的卡方检验是检验类别型变量对类别型变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量:
    在这里插入图片描述
    不难发现,这个统计量的含义简而言之就是自变量对因变量的相关性。用sklearn中feature_selection库的SelectKBest类结合卡方检验来选择特征的代码如下:

    from sklearn.datasets import load_iris
    from sklearn.feature_selection import SelectKBest
    from sklearn.feature_selection import chi2
    iris = load_iris()
    X, y = iris.data, iris.target  #iris数据集
    
    #选择K个最好的特征,返回选择特征后的数据
    X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
    

    sklearn.feature_selection模块中的类可以用于样本集中的特征选择/维数降低,以提高估计器的准确度分数或提高其在非常高维数据集上的性能。

    2.1.3 互信息和最大信息系数

      经典的互信息也是评价类别型变量对类别型变量的相关性的,互信息公式如下:
    在这里插入图片描述
    互信息直接用于特征选择其实不是太方便:

    • 它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较
    • 对于连续变量的计算不是很方便( X 和 Y 都是集合, x_i, y 都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感

    最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,取值区间在 [0,1] 。minepy提供了MIC功能。

    from minepy import MINE
    
    m = MINE()
    x = np.random.uniform(-1, 1, 10000)
    m.compute_score(x, x**2)
    print(m.mic())
    
    
    from sklearn.feature_selection import SelectKBest
    #由于MINE的设计不是函数式的,定义mic方法将其为函数式的,返回一个二元组,二元组的第2项设置成固定的P值0.5
    def mic(x, y):
        m = MINE()
        m.compute_score(x, y)
        return (m.mic(), 0.5)
    # 选择K个最好的特征,返回特征选择后的数据
    SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
    

    2.1.4 距离相关系数

      距离相关系数是为了克服Pearson相关系数的弱点而生的。在 x 和 x^2 这个例子中,即便Pearson相关系数是 0 ,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是 0 ,那么我们就可以说这两个变量是独立的。
    python实现
      尽管有MIC和距离相关系数在了,但当变量之间的关系接近线性相关的时候,Pearson相关系数仍然是不可替代的。有以下两点原因:

    1. Pearson相关系数计算速度快,这在处理大规模数据的时候很重要。
    2. Pearson相关系数的取值区间是[-1,1],而MIC和距离相关系数都是[0,1]。这个特点使得Pearson相关系数能够表征更丰富的关系,符号表示关系的正负,绝对值能够表示强度。当然,Pearson相关性有效的前提是两个变量的变化关系是单调的。

    2.1.5 方差选择法

      过滤特征选择法还有一种方法不需要度量特征 x_i 和类别标签 y 的信息量。这种方法先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。VarianceThreshold是特征选择的简单基线方法。它删除方差不符合某个阈值的所有特征。默认情况下,它会删除所有零差异特征,即所有样本中具有相同值的特征。

    from sklearn.feature_selection import VarianceThreshold
    X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
    # 方差选择法,返回值为特征选择后的数据
    # 参数threshold为方差的阈值
    sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
    print(sel.fit_transform(X))
    
    array([[0, 1],[1, 0],[0, 0],[1, 1],[1, 0],[1, 1]]) 
    

    方差选择的逻辑并不是很合理,这个是基于各特征分布较为接近的时候,才能以方差的逻辑来衡量信息量。但是如果是离散的或是仅集中在几个数值上,如果分布过于集中,其信息量则较小。而对于连续变量,由于阈值可以连续变化,所以信息量不随方差而变。 实际使用时,可以结合cross-validate进行检验。

    2.2 Wrapper(包裹式)

      包裹式基本思想:基于hold-out方法,对于每一个待选的特征子集,都在训练集上训练一遍模型,然后在测试集上根据误差大小选择出特征子集。西瓜书上说包装法应该欲训练什么算法,就选择该算法进行评估;随着学习器(评估器)的改变,最佳特征组合可能会改变。

    2.2.1 向前逐步选择

      每增加一个变量考虑了局部最优。
    (i) 记不含任何特征的模型为 M 0 M_0 M0,计算这个 M 0 M_0 M0的测试误差。
    (ii) 在 M 0 M_0 M0基础上增加一个变量,计算p个模型的RSS,选择RSS最小的模型记作 M 1 M_1 M1,并计算该模型 M 1 M_1 M1的测试误差。
    (iii) 在最小的RSS模型下继续增加一个变量,选择RSS最小的模型记作 M 2 M_2 M2,并计算该模型 M 2 M_2 M2的测试误差。
    (iv) 以此类推,重复以上过程知道拟合的模型有p个特征为止,并选择p+1个模型 { M 0 , M 1 , . . . , M p } \{M_0,M_1,...,M_p \} {M0,M1,...,Mp}中测试误差最小的模型作为最优模型。

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    """
    @author: admin
    @file: 向前逐步选择.py
    @time: 2021/03/15
    @desc:
    """
    import numpy as np
    import pandas as pd
    import statsmodels.api as sm
    from sklearn.linear_model import Lasso
    from sklearn.datasets import load_boston
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import r2_score
    
    
    def froward_select(train_data, test_data, target):
        """
        向前逐步回归
        :param data: 数据
        :param target:目标值
        :return:
        """
        variate = set(train_data.columns)
        variate.remove(target)
        # 参数
        selected = []  # 储存挑选的变量
        # 初始化
        # 初始化决定系数R^2,越近于1越好
        cur_score, best_score = 0.0, 0.0
        # 循环删选变量,直至对所有变量进行了选择
        while variate:
            variate_r2 = []
            # 找到局部最优
            for var in variate:
                selected.append(var)
                if len(selected) == 1:
                    model = Lasso().fit(train_data[selected[0]].values.reshape(-1, 1), train_data[target])
                    y_pred = model.predict(test_data[selected[0]].values.reshape(-1, 1))
                    # R2 = r2(test_data[target], y_pred)
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2.append((R2, var))
                    selected.remove(var)
                else:
                    model = Lasso().fit(train_data[selected], train_data[target])
                    y_pred = model.predict(test_data[selected])
                    # R2 = r2(test_data[target], y_pred)
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2.append((R2, var))
                    selected.remove(var)
            variate_r2.sort(reverse=False)  # 默认升序
            best_score, best_var = variate_r2.pop()  # pop用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
            if cur_score < best_score:  # 说明了加了该变量更好了
                variate.remove(best_var)  # 判断过了,不管是好是坏,就删了
                selected.append(best_var)
                cur_score = best_score
                print("R2={},continue!".format(cur_score))
            else:
                print('for selection over!')
                break
        selected_features = '+'.join([str(i) for i in selected])
        print(selected_features)
    
    
    def main():
        boston = load_boston()
        X = boston.data
        y = boston.target
        features = boston.feature_names
        x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.4)
        boston_train_data = pd.DataFrame(x_train, columns=features)
        boston_train_data["Price"] = y_train
        boston_test_data = pd.DataFrame(x_test, columns=features)
        boston_test_data["Price"] = y_test
        froward_select(boston_train_data, boston_test_data, 'Price')
    
    
    if __name__ == '__main__':
        main()
    
    R2=0.61744910032392,continue!
    R2=0.6908671406351847,continue!
    R2=0.7317782212152852,continue!
    R2=0.7395157511526225,continue!
    R2=0.7433588119420051,continue!
    R2=0.7454229322919887,continue!
    R2=0.7462568212024802,continue!
    R2=0.7462857832907019,continue!
    for selection over!
    LSTAT+PTRATIO+RM+DIS+B+CRIM+INDUS+TAX
    
    

    2.2.2 向后逐步选择

    向后逐步选择简述如下:

    1. 初始化时将所有特征放入模型中
    2. 每次剔除最差变量,该变量的剔除使得模型效果不明显,评估模型性能的改善
    3. 重复直到没有变量可剔除后
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    """
    @author: admin
    @file: 向后逐步挑选.py
    @time: 2021/03/16
    @desc:
    """
    import numpy as np
    import pandas as pd
    import statsmodels.api as sm
    from sklearn.linear_model import Lasso
    from sklearn.datasets import load_boston
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import r2_score
    
    
    def froward_select(train_data, test_data, target):
        """
        向前逐步回归
        :param data: 数据
        :param target:目标值
        :return:
        """
        variate = list(set(train_data.columns))
        variate.remove(target)
        # 参数
        selected = []  # 储存挑选的变量
        # 初始化
        # 初始化决定系数R^2,越近于1越好
        cur_score, best_score = 0.0, 0.0
        # 循环删选变量,直至对所有变量进行了选择
        while variate:
            variate_r2 = []
            # 找到局部最优
            for var in variate:
                variate.remove(var)
                if len(variate) == 1:
                    model = Lasso().fit(train_data[variate[0]].values.reshape(-1, 1), train_data[target])
                    y_pred = model.predict(test_data[variate[0]].values.reshape(-1, 1))
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2.append((R2, var))
                    variate.append(var)
                else:
                    model = Lasso().fit(train_data[variate], train_data[target])
                    y_pred = model.predict(test_data[variate])
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2.append((R2, var))
                    variate.append(var)
            variate_r2.sort(reverse=False)  # 升序排序r2,默认升序
            best_score, best_var = variate_r2.pop()  # pop用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
            if cur_score < best_score:  # 说明了移除了该变量更好了
                variate.remove(best_var)  # 判断过了,不管是好是坏,就删了
                selected.append(best_var)
                cur_score = best_score
                print("R2={},continue!".format(cur_score))
            else:
                print('for selection over!')
                break
        print(selected)
        selected = [var for var in set(train_data.columns) if var not in selected]
        selected_features = '+'.join([str(i) for i in selected])
    
        print(selected_features)
    
    
    def main():
        boston = load_boston()
        X = boston.data
        y = boston.target
        features = boston.feature_names
        x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.4)
        boston_train_data = pd.DataFrame(x_train, columns=features)
        boston_train_data["Price"] = y_train
        boston_test_data = pd.DataFrame(x_test, columns=features)
        boston_test_data["Price"] = y_test
        froward_select(boston_train_data, boston_test_data, 'Price')
    
    
    if __name__ == '__main__':
        main()
    
    R2=0.6130365918500247,continue!
    R2=0.6206140392385366,continue!
    R2=0.6206319773780711,continue!
    R2=0.6216812478858313,continue!
    R2=0.6217076288117218,continue!
    for selection over!
    ['CHAS', 'AGE', 'INDUS', 'ZN', 'NOX']
    TAX+Price+RAD+DIS+PTRATIO+RM+LSTAT+CRIM+B
    

    2.2.3 双向挑选

    双向挑选简述如下:
    向前向后挑选的结合
    双向挑选用的较多,能够兼顾模型复杂度与模型精度的要求。
    描述为:先两步向前挑选,再向后挑选,再反复向前向后

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    """
    @author: admin
    @file: 双向挑选.py
    @time: 2021/03/16
    @desc:
    """
    import numpy as np
    import pandas as pd
    import statsmodels.api as sm
    from sklearn.linear_model import Lasso
    from sklearn.datasets import load_boston
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import r2_score
    
    def froward_select(train_data, test_data, target):
        """
        向前逐步回归
        :param data: 数据
        :param target:目标值
        :return:
        """
        variate = list(set(train_data.columns))
        variate.remove(target)
        selected = []  # 储存挑选的变量
        selected_h = []  # 存储删除的变量
        # 初始化
        # 初始化决定系数R^2,越近于1越好
        cur_score_f, best_score_f = 0.0, 0.0
        cur_score_h, best_score_h = 0.0, 0.0
        # 循环删选变量,直至对所有变量进行了选择
        # 双向挑选—先两步前向再一步后向
        while variate:
            variate_r2_f = []
            variate_r2_h = []
            # 找到局部最优
            # 先两步前向
            for i in range(2):
                for var in variate:
                    selected.append(var)
                    if len(selected) == 1:
                        model = Lasso().fit(train_data[selected[0]].values.reshape(-1, 1), train_data[target])
                        y_pred = model.predict(test_data[selected[0]].values.reshape(-1, 1))
                        R2 = r2_score(test_data[target], y_pred)
                        variate_r2_f.append((R2, var))
                        selected.remove(var)
                    else:
                        model = Lasso().fit(train_data[selected], train_data[target])
                        y_pred = model.predict(test_data[selected])
                        R2 = r2_score(test_data[target], y_pred)
                        variate_r2_f.append((R2, var))
                        selected.remove(var)
                variate_r2_f.sort(reverse=False)  # 降序排序r2,默认升序
                best_score_f, best_var_f = variate_r2_f.pop()  # pop用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
                if cur_score_f < best_score_f:  # 说明了加了该变量更好了就不移除了,否则就移除
                    selected.append(best_var_f)
                    cur_score_f = best_score_f
                    print("R2_f={},continue!".format(cur_score_f))
                else:
                    variate.remove(best_var_f)
                    break
            # 再一步后向
            for var in variate:
                variate.remove(var)
                if len(variate) == 1:
                    model = Lasso().fit(train_data[variate[0]].values.reshape(-1, 1), train_data[target])
                    y_pred = model.predict(test_data[variate[0]].values.reshape(-1, 1))
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2_h.append((R2, var))
                    variate.append(var)
                else:
                    model = Lasso().fit(train_data[variate], train_data[target])
                    y_pred = model.predict(test_data[variate])
                    R2 = r2_score(test_data[target], y_pred)
                    variate_r2_h.append((R2, var))
                    variate.append(var)
            variate_r2_h.sort(reverse=False)  # 升序排序r2,默认升序
            best_score_h, best_var_h = variate_r2_h.pop()  # pop用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
            if cur_score_h < best_score_h:  # 说明了移除了该变量更好了
                variate.remove(best_var_h)
                selected_h.append(best_var_h)
                cur_score_h = best_score_h
                print("R2_h={},continue!".format(cur_score_h))
            else:
                print('for selection over!')
                selected = [var for var in set(train_data.columns) if var not in selected_h]
                selected_features = '+'.join([str(i) for i in selected])
                print(selected_features)
                break
    
    
    
    def main():
        boston = load_boston()
        X = boston.data
        y = boston.target
        features = boston.feature_names
        x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.4)
        boston_train_data = pd.DataFrame(x_train, columns=features)
        boston_train_data["Price"] = y_train
        boston_test_data = pd.DataFrame(x_test, columns=features)
        boston_test_data["Price"] = y_test
        froward_select(boston_train_data, boston_test_data, 'Price')
    
    
    if __name__ == '__main__':
        main()
    
    R2_f=0.5290772958895777,continue!
    R2_f=0.5992603091580796,continue!
    R2_h=0.6392096900660633,continue!
    R2_f=0.6328497309792275,continue!
    R2_f=0.6424099014083555,continue!
    R2_h=0.6446960403771425,continue!
    R2_f=0.6529845736263218,continue!
    R2_f=0.6555371387702666,continue!
    R2_h=0.6524813775669193,continue!
    R2_f=0.6577033230821112,continue!
    R2_f=0.6577063213485781,continue!
    R2_h=0.6525859983540159,continue!
    R2_f=0.6577196381996436,continue!
    for selection over!
    Price+RM+CHAS+AGE+PTRATIO+TAX+NOX+CRIM+B+DIS
    

    2.2.4 递归特征消除法

      递归消除特征法使用一个基模型来进行多轮训练,每轮训练后通过学习器返回的 coef_ 或者feature_importances_ 消除若干权重较低的特征,再基于新的特征集进行下一轮训练。

    from sklearn.feature_selection import RFE
    from sklearn.linear_model import LogisticRegression
    
    #递归特征消除法,返回特征选择后的数据
    #参数estimator为基模型
    #参数n_features_to_select为选择的特征个数
    RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
    

    2.3 嵌入法

      基于惩罚项的特征选择法 通过L1正则项来选择特征:L1正则方法具有稀疏解的特性,因此天然具备特征选择的特性。先使用某些机器学习的模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征,L1正则化可以使得特征的权值系数为0。

    from sklearn.feature_selection import SelectFromModel
    from sklearn.linear_model import LogisticRegression
    
    #带L1惩罚项的逻辑回归作为基模型的特征选择   
    SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
    

    要注意,L1没有选到的特征不代表不重要,原因是两个具有高相关性的特征可能只保留了一个,如果要确定哪个特征重要应再通过L2正则方法交叉检验。
    数据预处理与特征工程—9.Lasso算法实现特征选择

    3.特征提取

      特征提取与特征选择的区别是:特征提取后的新特征是原来特征的一个映射。特征选择后的特征是原来特征的一个子集。主成分分析(Principle Components Analysis ,PCA)和线性判别分析(Linear Discriminant Analysis,LDA)是特征提取的两种主要经典方法。

    3.1 主成分分析PCA

      PCA得到的投影空间是协方差矩阵的特征向量,特征抽取后的特征要能够精确地表示样本信息,使得信息丢失很小。
    具体可参考这篇博客数据预处理—8.属性归约之主成分分析(理论及python实现)

    3.2 线性判别分析LDA

      线性判别分析LDA则是通过求得一个变换W,使得变换之后的新均值之差最大、方差最大(也就是最大化类间距离和最小化类内距离),变换W就是特征的投影方向。特征抽取后的特征,要使得分类后的准确率很高,不能比原来特征进行分类的准确率低。
    具体使用可以参考这篇博客用scikit-learn进行LDA降维
      一般来说,如果我们的数据是有类别标签的,那么优先选择LDA去尝试降维;当然也可以使用PCA做很小幅度的降维去消去噪声,然后再使用LDA降维。如果没有类别标签,那么肯定PCA是最先考虑的一个选择了。

    4.特征构造—创造新特征

    4.1. 数值特征的简单变换

    1. 单独特征列乘以一个常数(constant multiplication)或者加减一个常数:对于创造新的有用特征毫无用处;只能作为对已有特征的处理。
    df['Feature'] = df['Feature'] + n
    df['Feature'] = df['Feature'] - n
    df['Feature'] = df['Feature'] * n
    df['Feature'] = df['Feature'] / n
    
    1. 任何针对单独特征列的单调变换(如对数):不适用于决策树类算法。对于决策树而言, X X X X 3 X^3 X3 X 5 X^5 X5之间没有差异, X 2 X^2 X2 X 4 X^4 X4 X 6 X^6 X6 之间没有差异,除非发生了舍入误差。
      如果 u ( x 1 , y 1 ) > u ( x 2 , y 2 ) u(x1, y1) > u(x2, y2) u(x1,y1)>u(x2,y2),则 v ( x 1 , y 1 ) = f ( u ( x 1 , y 1 ) ) > v ( x 2 , y 2 ) = f ( u ( x 2 , y 2 ) ) v(x1, y1) = f(u(x1, y1)) > v(x2, y2)=f(u(x2, y2)) v(x1,y1)f(u(x1,y1))>v(x2,y2)f(u(x2,y2)),那么 f ( ) f() f()就是其单调变换。
    import numpy as np
    # 计算n次方
    df['Feature'] = df['Feature']**2
    # 计算log变换
    df['Feature'] = np.log(df['Feature'])
    
    1. 线性组合(linear combination):借助线性组合,线性学习器可以很好扩展到大量数据,并有助于构建复杂模型解决非线性问题。仅适用于决策树以及基于决策树的ensemble(如gradient boosting,random forest),因为常见的axis-aligned split function不擅长捕获不同特征之间的相关性;不适用于SVM、线性回归、神经网络等。如:
      将两个特征的值相乘形成的特征组合;

      df['Feature'] = df['A'] * df['B']
      

      将五个特征的值相乘形成的特征组合;

      df['Feature'] = df['A'] * df['B'] * df['C'] * df['D'] * df['E']
      
    2. 多项式特征(polynomial feature):1.3 sklearn中的preprocessing.PolynomialFeatures——多项式回归
      当两个变量各自与 y 的关系并不强时候,把它们结合成为一个新的变量可能更会容易体现出它们与 y 的关系。特征a和特征b的多项式输出是: [ 1 , a , b , a 2 , a b , b 2 ] [1, a, b, a^2, ab, b^2] [1,a,b,a2,ab,b2]或者 [ 1 , a , b , a b ] [1, a, b, ab] [1,a,b,ab]

      import numpy as np
      from sklearn.preprocessing import PolynomialFeatures
      X = np.arange(6).reshape(3, 2)
      print(X)
      # 输出:array([[0, 1],
                    [2, 3],
                    [4, 5]])
      # 设置多项式阶数为2
      poly = PolynomialFeatures(2)
      print(poly.fit_transform(X))
      # 输出:array([[ 1.,  0.,  1.,  0.,  0.,  1.],
                    [ 1.,  2.,  3.,  4.,  6.,  9.],
                    [ 1.,  4.,  5., 16., 20., 25.]])
      #默认的阶数是2,同时设置交互关系为true
      poly = PolynomialFeatures(interaction_only=True)
      print(poly.fit_transform(X))
      # 输出:array([[ 1.,  0.,  1.,  0.],
                    [ 1.,  2.,  3.,  6.],
                    [ 1.,  4.,  5., 20.]])
      
    3. 比例特征(ratio feature): X 1 X 2 \frac{X1}{X2} X2X1
      计算两个特征的数值比例: X 1 X 2 \frac{X1}{X2} X2X1

      df['Feature'] = df['X1']/df['X2']
      
    4. 绝对值(absolute value)
      计算特征值的绝对值: ∣ X ∣ |X| X
      例子:某数据的相关系数特征。

      import numpy as np
      df['Feature'] = np.abs(df['Feature'])
      
    5. m a x ( X 1 , X 2 ) , m i n ( X 1 , X 2 ) , X 1 x o r X 2 max(X_1,X_2),min(X_1,X_2),X_1 xor X_2 max(X1,X2)min(X1,X2)X1xorX2

      # 最大值特征
      df['Feature'] = df.apply(lambda x: max(x['X1'], x['X2']), axis=1)
      # 最小值特征
      df['Feature'] = df.apply(lambda x: min(x['X1'], x['X2']), axis=1)
      # 异或特征—计算两特征的异或值:X1 xor X2。
      df['Feature'] = df.apply(lambda x: x['X1'] ^ x['X2'], axis=1)
      
    6. 排名编码特征
      按特征值对全体样本进行排序,以排序序号作为特征。这种特征对异常点不敏感,不会导致特征值冲突。例子:广告历史曝光量排名。

      X = [10, 9, 9, 8, 7]
      df = pd.DataFrame({'X': X,})
      df['num'] = df['X'].rank(ascending=0, method='dense')
      
          X    num
      0    10    1.0
      1    9    2.0
      2    9    2.0
      3    8    3.0
      4    7    4.0
      

    4.2 类别特征与数值特征的组合

      用N1和N2表示数值特征,用C1和C2表示类别特征,利用pandas的groupby操作,可以创造出以下几种有意义的新特征:(其中,C2还可以是离散化了的N1)

    1. 分组统计中位数
    df.groupby(['C1']).agg({'N1': 'median'})
    
    1. 分组统计平均数
    df.groupby(['C1']).agg({'N1': 'mean'})
    
    1. 分组统计众数
    from scipy import stats
    df.groupby(['C1'])['N1'].agg(lambda x: stats.mode(x)[0][0]))})
    
    1. 分组统计最小值
    df.groupby(['C1']).agg({'N1': 'min'})
    
    1. 分组统计最大值
    df.groupby(['C1']).agg({'N1': 'max'})
    
    1. 分组统计标准差
    df.groupby(['C1']).agg({'N1': 'std'})
    
    1. 分组统计方差
    df.groupby(['C1']).agg({'N1': 'var'})
    
    1. 分组统计频数
    df.groupby(['C1']).agg({'N1': 'count'})
    

    仅仅将已有的类别和数值特征进行以上的有效组合,就能够大量增加优秀的可用特征。

    1. 统计频数
      直接统计类别特征的频数,这个不需要 groupby 也有意义。
    df.groupby(['C1']).agg({'C1': 'count'})
    

    4.3 分组统计和基础特征工程方法结合

      将分组统计和线性组合等基础特征工程方法结合(仅用于决策树),可以得到更多有意义的特征。

    1. 中位数分组与线性组合结合
    df = pd.merge(df, df.groupby(['C1'])['N1'].median().reset_index().rename(columns={'N1': 'N1_Median'}),
                  on='C1', how='left')
    df['N1+Median(C1)'] = df['N1'] + df['N1_Median']
    df['N1-Median(C1)'] = df['N1'] - df['N1_Median']
    df['N1*Median(C1)'] = df['N1'] * df['N1_Median']
    df['N1/Median(C1)'] = df['N1'] / df['N1_Median']
    
        C1    C2    N1    N2  N1_Median N1+Median(C1) N1-Median(C1) N1*Median(C1) N1/Median(C1)
    0    A    a    1    1.1  1.0      2.0           0.0           1.0           1.00
    1    A    a    1    2.2  1.0      2.0           0.0           1.0           1.00
    2    A    a    2    3.3  1.0      3.0           1.0           2.0           2.00
    3    B    a    2    4.4  2.5      4.5           -0.5          5.0           0.80
    4    B    a    3    5.5  2.5      5.5           0.5           7.5           1.20
    5    C    b    3    6.6  4.0      7.0           -1.0          12.0          0.75
    6    C    b    4    7.7  4.0      8.0           0.0           16.0          1.00
    7    C    b    4    8.8  4.0      8.0           0.0           16.0          1.00
    8    D    b    5    9.9  5.0      10.0           0.0          25.0          1.00
    9    D    b    5    10.0 5.0      10.0           0.0          25.0          1.00
    
    1. 平均数分组与线性组合结合
    df = pd.merge(df, df.groupby(['C1'])['N1'].mean().reset_index().rename(columns={'N1': 'N1_Mean'}),
                  on='C1', how='left')
    df['N1+Mean(C1)'] = df['N1'] + df['N1_Mean']
    df['N1-Mean(C1)'] = df['N1'] - df['N1_Mean']
    df['N1*Mean(C1)'] = df['N1'] * df['N1_Mean']
    df['N1/Mean(C1)'] = df['N1'] / df['N1_Mean']
    
        C1    C2    N1    N2   N1_Mean  N1+Mean(C1) N1-Mean(C1) N1*Mean(C1) N1/Mean(C1)
    0    A    a    1    1.1  1.333333 2.333333    -0.333333   1.333333    0.750000
    1    A    a    1    2.2  1.333333 2.333333    -0.333333   1.333333    0.750000
    2    A    a    2    3.3  1.333333 3.333333    0.666667    2.666667    1.500000
    3    B    a    2    4.4  2.500000 4.500000    -0.500000   5.000000    0.800000
    4    B    a    3    5.5  2.500000 5.500000    0.500000    7.500000    1.200000
    5    C    b    3    6.6  3.666667 6.666667    -0.666667   11.000000   0.818182
    6    C    b    4    7.7  3.666667 7.666667    0.333333    14.666667   1.090909
    7    C    b    4    8.8  3.666667 7.666667    0.333333    14.666667   1.090909
    8    D    b    5    9.9  5.000000 10.000000   0.000000    25.000000   1.000000
    9    D    b    5    10.0 5.000000 10.000000   0.000000    25.000000   1.000000
    

    4.3 笛卡尔乘积创造新特征

      通过将单独的特征求笛卡尔乘积的方式来组合2个或更多个特征,从而构造出组合特征。最终获得的预测能力将远远超过任一特征单独的预测能力。

    4.3.1 类别特征进行笛卡尔乘积特征组合

    例如:类别特征color和类别特征light进行笛卡尔乘积特征组合
    特征 color 取值:red, green, blue
    特征 light 取值:on, off
    这两个特征各自可以离散化为3维和2维的向量,对它们做笛卡尔乘积转化,就可以组合出长度为6的特征,它们分别对应着原始值对 (red, on),(red, off),(green, on),(green, off),(blue, on),(blue, off)

    import pandas as pd
    
    color = ['on', 'on', 'off', 'off', 'off', ]
    light = ['red', 'green', 'blue', 'red', 'green', ]
    df = pd.DataFrame({'color': color, 'light': light})
    print(df)
    
    
    def cartesian_product_feature_crosses(df, feature1_name, feature2_name):
        feature1_df = pd.get_dummies(df[feature1_name], prefix=feature1_name)
        feature1_columns = feature1_df.columns
        feature2_df = pd.get_dummies(df[feature2_name], prefix=feature2_name)
        feature2_columns = feature2_df.columns
        # 对两个onehot编码得到的dataframe进行拼接
        combine_df = pd.concat([feature1_df, feature2_df], axis=1)
        crosses_feature_columns = []
        for feature1 in feature1_columns:
            for feature2 in feature2_columns:
                # 构造新的列名
                crosses_feature = '{}&{}'.format(feature1, feature2)
                crosses_feature_columns.append(crosses_feature)
                # 笛卡尔乘积
                combine_df[crosses_feature] = combine_df[feature1] * combine_df[feature2]
        combine_df = combine_df.loc[:, crosses_feature_columns]
        return combine_df
    combine_df = cartesian_product_feature_crosses(df, 'color', 'light')
    print(combine_df)
    
      color  light
    0    on    red
    1    on  green
    2   off   blue
    3   off    red
    4   off  green
       color_off&light_blue  ...  color_on&light_red
    0                     0  ...                   1
    1                     0  ...                   0
    2                     1  ...                   0
    3                     0  ...                   0
    4                     0  ...                   0
    

    4.3.2 连续特征与类别特征之间的笛卡尔乘积特征组合

      只要把连续特征看成是一维的类别特征就好了,这时候组合后特征对应的值就不是 0/1 了,而是连续特征的取值。

    4.3.3 连续特征之间的笛卡尔乘积特征组合

      笛卡尔乘积组合特征方法一般应用于类别特征之间,连续值特征使用笛卡尔乘积组合特征时一般需要先进行离散化,然后再进行特征组合。例如:经度和纬度特征进行笛卡尔乘积特征组合

    import pandas as pd
    import numpy as np
    lat = [
      '0  < lat <= 10',
      '10 < lat <= 20',
      '20 < lat <= 30'
    ]
    lon = [
      '0  < lon <= 15',
      '15 < lon <= 30',
        np.nan
    ]
    df = pd.DataFrame({'lat': lat, 'lon': lon})
    print(df)
    
    def cartesian_product_feature_crosses(df, feature1_name, feature2_name):
        feature1_df = pd.get_dummies(df[feature1_name], prefix=feature1_name)
        feature1_columns = feature1_df.columns
        feature2_df = pd.get_dummies(df[feature2_name], prefix=feature2_name)
        feature2_columns = feature2_df.columns
        # 对两个onehot编码得到的dataframe进行拼接
        combine_df = pd.concat([feature1_df, feature2_df], axis=1)
        crosses_feature_columns = []
        for feature1 in feature1_columns:
            for feature2 in feature2_columns:
                # 构造新的列名
                crosses_feature = '{}&{}'.format(feature1, feature2)
                crosses_feature_columns.append(crosses_feature)
                # 笛卡尔乘积
                combine_df[crosses_feature] = combine_df[feature1] * combine_df[feature2]
        combine_df = combine_df.loc[:, crosses_feature_columns]
        return combine_df
    combine_df = cartesian_product_feature_crosses(df, 'lat', 'lon')
    print(combine_df)
    
                  lat             lon
    0  0  < lat <= 10  0  < lon <= 15
    1  10 < lat <= 20  15 < lon <= 30
    2  20 < lat <= 30             NaN
       lat_0  < lat <= 10&lon_0  < lon <= 15  ...  lat_20 < lat <= 30&lon_15 < lon <= 30
    0                                      1  ...                                      0
    1                                      0  ...                                      0
    2                                      0  ...                                      0
    
    [3 rows x 6 columns]
    

    4.4 用基因编程创造新特征

      遗传编程创造新特征是基于 genetic programming 的 symbolic regression(符号回归)。symbolic regression的具体实现方式是遗传算法(genetic algorithm)。一开始,一群天真而未经历选择的公式会被随机生成。此后的每一代中,最「合适」的公式们将被选中。随着迭代次数的增长,它们不断繁殖、变异、进化,从而不断逼近数据分布的真相。
      目前,python环境下最好用的基因编程库为gplearn。gplearn 这个库提供了解决思路:随机化生成大量特征组合方式,解决了没有先验知识,手工生成特征费时费力的问题。

    通过遗传算法进行特征组合的迭代,而且这种迭代是有监督的迭代,存留的特征和label相关性是也来越高的,大量低相关特征组合会在迭代中被淘汰掉,用决策树算法做个类比的话,我们自己组合特征然后筛选,好比是后剪枝过程,遗传算法进行的则是预剪枝的方式。

    基因编程的两大用法:

    • 转换(SymbolicTransformer):把已有的特征进行组合转换,组合的方式(一元、二元、多元算子)可以由用户自行定义,也可以使用库中自带的函数(如加减乘除、min、max、三角函数、指数、对数)。组合的目的,是创造出和目标y值最“相关”的新特征。这种相关程度可以用spearman或者pearson的相关系数进行测量。spearman多用于决策树(免疫单特征单调变换),pearson多用于线性回归等其他算法。它并不直接预测目标变量,而是转化原有的特征、输出新的特征,这在特征工程的阶段尤为有效。
    • 回归(Symbolic Regressor):它利用遗传算法得到的公式,直接预测目标变量的值。
    # 数据集:波士顿数据集
    # 训练Ridge模型
    est = Ridge()
    est.fit(boston.data[:300, :], boston.target[:300])
    print(est.score(boston.data[300:, :], boston.target[300:]))
    # 输出:0.759145222183
    # 使用超过20代的2000人。选择最好的100个hall_of_fame,然后使用最不相关的10作为我们的新功能。因为我们使用线性模型作为估算器,所以这里使用默认值metric='pearson'。
    function_set = ['add', 'sub', 'mul', 'div',
                    'sqrt', 'log', 'abs', 'neg', 'inv',
                    'max', 'min']
    gp = SymbolicTransformer(generations=20, population_size=2000,
                             hall_of_fame=100, n_components=10,
                             function_set=function_set,
                             parsimony_coefficient=0.0005,
                             max_samples=0.9, verbose=1,
                             random_state=0, n_jobs=3)
    gp.fit(boston.data[:300, :], boston.target[:300])
    # 将新构造的特征拼接到原始数据上
    gp_features = gp.transform(boston.data)
    new_boston = np.hstack((boston.data, gp_features))
    # 使用新的特征重新训练Ridge模型
    est = Ridge()
    est.fit(new_boston[:300, :], boston.target[:300])
    print(est.score(new_boston[300:, :], boston.target[300:]))
    # 输出:0.841750404385
    

    使用新构造的特征训练模型效果很显著。

    4.5 GBDT特征构造

      GBDT 是一种常用的非线性模型,基于集成学习中 boosting 的思想,由于GBDT本身可以发现多种有区分性的特征以及特征组合,决策树的路径可以直接作为 LR 输入特征使用,省去了人工寻找特征、特征组合的步骤。所以可以将 GBDT 的叶子结点输出,作为LR的输入。选用GBDT有如下两个关键点:

    1. 采用ensemble决策树而非单颗树
      一棵树的表达能力很弱,不足以表达多个有区分性的特征组合,多棵树的表达能力更强一些。GBDT 每棵树都在学习前面棵树尚存的不足,迭代多少次就会生成多少颗树。多棵树正好满足 LR 每条训练样本可以通过 GBDT 映射成多个特征的需求。
    2. 采用 GBDT 而非 RF
      RF 也是多棵树,但从效果上有实践证明不如 GBDT。且 GBDT 前面的树,特征分裂主要体现对多数样本有区分度的特征;后面的树,主要体现的是经过前 N 颗树,残差仍然较大的少数样本。优先选用在整体上有区分度的特征,再选用针对少数样本有区分度的特征,思路更加合理,这应该也是用 GBDT 的原因。
    import numpy as np
    import random
    from sklearn.datasets import make_classification
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import GradientBoostingClassifier
    from sklearn.preprocessing import OneHotEncoder
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import roc_curve, roc_auc_score
    
    # 生成随机数据
    np.random.seed(10)
    X, Y = make_classification(n_samples=1000, n_features=30)
    X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state=233, test_size=0.4)
    # LR模型
    LR = LogisticRegression()
    LR.fit(X_train, Y_train)
    y_pred = LR.predict_proba(X_test)[:, 1]
    fpr, tpr, _ = roc_curve(Y_test, y_pred)
    auc = roc_auc_score(Y_test, y_pred)
    print('LogisticRegression: ', auc)
    
    # 训练GBDT模型
    gbdt = GradientBoostingClassifier(n_estimators=10)
    gbdt.fit(X_train, Y_train)
    # 将训练好的树应用到X_train,返回叶索引,shape大小为(600,10,1)
    print(gbdt.apply(X_train)[:, :, 0])
    # 对GBDT预测结果进行onehot编码
    onehot = OneHotEncoder()
    onehot.fit(gbdt.apply(X_train)[:, :, 0])
    print(onehot.transform(gbdt.apply(X_train)[:, :, 0]))
    # 训练LR模型
    lr = LogisticRegression()
    lr.fit(onehot.transform(gbdt.apply(X_train)[:, :, 0]), Y_train)
    # 测试集预测
    Y_pred = lr.predict_proba(onehot.transform(gbdt.apply(X_test)[:, :, 0]))[:, 1]
    fpr, tpr, _ = roc_curve(Y_test, Y_pred)
    auc = roc_auc_score(Y_test, Y_pred)
    print('GradientBoosting + LogisticRegression: ', auc)
    
    LogisticRegression:  0.9349156965074267
    GradientBoosting + LogisticRegression:  0.9412133681252508
    

    GBDT 算法的特点可以用来发掘有区分度的特征、特征组合,减少特征工程中人力成本,且业界现在已有实践,GBDT+LR、GBDT+FM 等都是值得尝试的思路。不同场景,GBDT 融合 LR/FM 的思路可能会略有不同,可以多种角度尝试。

    4.6 聚类特征构造

    聚类算法有:
    在这里插入图片描述
    聚类特征构造步骤为:

    1. 从预处理后的特征集中选择一个或多个特征;当只选择一个数值型特征时,聚类算法构造特征相当于使用聚类算法进行特征分箱
    2. 选择适合聚类算法对已选择的特征进行聚类,并输出聚类类标结果;
    3. 对聚类类标结果进行编码;一般聚类类标结果为一个数值,但实际上这个数值并没有大小之分,所以一般需要进行特征编码

    下面以使用 k-mean 算法对用户兴趣爱好进行聚类为例:

    import pandas as pd
    import jieba
    import numpy as np
    from mitie import total_word_feature_extractor
    from sklearn.cluster import KMeans
    from sklearn.preprocessing import OneHotEncoder
    # 构造特征集
    hobby = [
        '健身', '电影', '音乐', '读书', '历史',
        '篮球', '羽毛球', '足球',
    ]
    df = pd.DataFrame({'兴趣': hobby})
    display(df.head(20))
    # 输出:
        兴趣
    0	健身
    1	电影
    2	音乐
    3	读书
    4	历史
    5	篮球
    6	羽毛球
    7	足球
    # 加载Embedding模型
    mitie_model_filename = 'total_word_feature_extractor_zh.dat'
    twfe = total_word_feature_extractor(mitie_model_filename)
    # 把词语转换成embedding向量
    embeding_array = np.array(list(df['兴趣'].apply(
        lambda w: twfe.get_feature_vector(w))))
    # k-mean距离
    kmeans = KMeans(n_clusters=2, random_state=0).fit(embeding_array)
    kmean_label = kmeans.labels_
    print('kmeans.labels_:{}'.format(kmean_label))
    # 输出:kmeans.labels_:[1 1 1 1 1 0 0 0]
    kmean_label = kmean_label.reshape(-1, 1)
    print('kmean_label shape={}'.format(kmean_label.shape))
    # 输出:kmean_label shape=(8, 1)
    # 特征编码
    enc = OneHotEncoder()
    onehot_code = enc.fit_transform(kmean_label)
    print(onehot_code.toarray())
    # 输出:
    [[0. 1.]
     [0. 1.]
     [0. 1.]
     [0. 1.]
     [0. 1.]
     [1. 0.]
     [1. 0.]
     [1. 0.]]
    

    聚类算法在特征构造中的应用:

    1. 利用聚类算法对文本聚类,使用聚类类标结果作为输入特征;
    2. 利用聚类算法对单个数值特征进行聚类,相当于使用聚类算法进行特征分箱;
    3. 利用聚类算法对R、F、M数据进行聚类,类似RFM模型,然后再使用代表衡量客户价值的聚类类标结果作为输入特征;

    4.7 日期/时间变量处理

      对日期/时间型变量,可以通过如下处理将时间变量变成离散型。
    时间是否为一个节日,是否在一个时间段(类别型);或者计算距离某个日子变成间隔型;或者某个时间段内发生了多少次变成组合型等等;这个需要结合具体应用场景。使其变成离散型。

    可以基于某个基准日期,转化为天数
    以观察点为基准,将所有开户日期转为距离观察点的天数(month-on-book)


    如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!
    在这里插入图片描述


    展开全文
  • 特征构造

    千次阅读 2020-12-21 15:22:43
    A B逾期的客户是正样本 C 能够被内催催回来的客户 1.2 机器学习模型的完整工程流程 准备 明确需求 模型设计 业务抽象成分类/回归问题 定义标签(目标值) 样本设计 特征工程 数据处理,选取合适的样本...
  • 客户流失预测

    2021-02-25 15:05:43
    深入了解用户画像及行为偏好,挖掘出影响用户流失的关键因素,并通过算法预测客户访问的转化结果,从而更好地完善产品设计,提升用户体验 二.读取数据 三.特征工程 3.1相关性分析 四.建模与模型评估 4.1模型比较...
  • 第三章 5G的四大特征 (内在) 3.1 泛在(网络自身的存在) 3.2 低功耗 3.3 网络虚拟化 3.4 网络智能化 第四章 5G关键的技术(内在技术) 4.1 无线接入技术 4.2 网络重构技术 4.3分布式业务服务 第五章 5G...
  • 文章目录 前言 一、R语言的中文分词及处理 二、应用Kettle进行后续处理 三、分词文件的Tableau可视化分析 1、新建数据连接 2、特征合并观察仪表盘 四、R语言增加自定义用户字典参数 六、Tableau自定义分词分析 1、...
  • 解决问题的关键是建立合理的客户价值评估模型,对客户进行分类,有针对性地进行营销。 1.2 目标 利用已有的航空数据,进行客户分类 就分类结果对不同类别的客户进行特征分析,比较不同类客户客户价值 对不同价值...
  • hive 存储 :存储数据相关标签表、人群计算表的表结构设计以及ID-Mapping的一种实现方式...开发时一般使用Hive作为数据仓库,存储标签和用户特征库等相关数据mysql 存储 :存储标签元数据、监控数据及结果集数据M...
  • 使用神经网络的自动化特征工程

    千次阅读 2021-02-27 12:35:09
    特征工程是生成精确模型的最重要步骤之一。但是没有人喜欢它,因为这个步骤非常繁琐,我坚信任何繁琐的事情都可以自动化。虽然我的解决方案并没有完全消除对手工工作的需要,但它确实大大减少了手工工作,并产生了更...
  • 4、客户识别:是指根据客户特征、购买记录信息,判断客户需求及客户价值,从而确定企业的潜在或现实客户类别的过程。 5、客户体验:是客户使用产品或接受服务后的直接感受,是客户自己与企业互动时产生的印象和感觉...
  • 客户关系管理理论 期末复习 参考教材:客户关系管理理论与应用(第二版) 栾港 编著
  • 第三次在线作业 ...2.(2.5分) 客户智能的理论基础是企业对客户采取决策的指导依据,这既包括企业分析和对待客户的理论和方法,也包括分别从客户和企业角度进行的( )。 A、满意度分析...
  • 分类信息app,通过数据挖掘分析影响用户流失的关键因素、深入了解用户行为偏好以此做出调整,提升客户留存率,增强客户黏性,并通过随机森林算法预测客户流失,通过特征创造使模型分数提高2个百分点。 项目内容: ...
  • 在企业的客户关系管理中,对客户分类,区分不同价值的客户。针对不同价值的客户提供个性化服务方案,采取不同营销策略,将有限营销资源集中于高价值客户,实现企业利润最大化目标。 在竞争激烈的航空市场里,很多...
  • 那么顾名思义,关键指标就是描述事物关键量化特征的啰。那什么才算是关键特征呢? 有些人说:最核心的就是了!这话说了等于没说。有些人说:最必不可少的才是!这也对,但是还是没抓住最核心的那个点。 大家看过明星...
  • 选择题 题目:客户关系管理(Customer ...题目:SCRM与传统CRM的根本不同之处在于,企业不是刻意地向客户营销,而是通过与客户的( )来保持与客户的关系,用以维系客户并达到鼓励客户将品牌介绍给别人。 题目:
  • 参会者们包括来自于极限编程、Scrum、DSDM、自适应软件开发、水晶系列、特征驱动开发、实效编程的代表们。官方网站:http://www.agilemanifesto.org 《敏捷宣言》提出敏捷4条价值观: 1、个人与互动胜过过程与...
  • 顾凡表示,在业务应用向现代化应用转型时,无论是平移、重构,还是共享的服务平台,应该基于企业的自身特征,把握好业务驱动重构的时机,以及根据业务情况来选择微服务化的规模,没有统一的标准。 谈到这一点,顾凡...
  • 1,查找某一话费的某一月份客户消费 2,计算客户的花费 3,0均值标准化 4,雷达图 2021年夏期期末数据挖掘项目:给定三个数据集(data1.csv/data2.csv/data_info.csv),通过本学期的学习对该数据进行数据挖掘研究....
  • 创造新的特征是一件十分困难的事情,需要丰富的专业知识和大量的时间。机器学习应用的本质基本上就是特征工程。——Andrew Ng业内常说数据决定了模型效果上限,而机器学习算法是通过数据特征做...
  • 例如,对于客户流失模型——我们可以查看流失客户的历史数据,加上客户的历史交互一起作为训练数据的输出部分。通过使用正确的算法,我们仅仅通过查看一系列的交互,就能够预测未来的客户流失情况。 然而有时我们...
  • 逾期数据 运营商 是否有相同的联系人 是否有黑名单客户在通讯录中 通话最频繁的几个人(所在地是否和他相同) 社保公积金 工资 社保 公积金 特征工程 特征选择 (feature_selection) Filter 移除低方差的特征 ...
  • 客户流失是一个关键指标,因为留住现有客户的成本要比获得新客户的成本低得多。 为了减少客户流失,电信公司需要预测哪些客户面临高流失风险。 为了发现潜在客户流失的早期迹象,首先必须对客户及其在多个渠道之间...
  • 点击上方蓝字关注我们毫无疑问,好的客户体验可以驱动更高的客户忠诚度,这也是为什么企业大力投资客户体验和客户之声(Voice of the Customer,VoC)项目的原因。随着该项...
  • 目前,模型开发的流程越来越规范化,通常可以分为业务分析、样本准备、特征工程、模型构建、模型评估及监控这几个步骤。其中,特征工程和模型构建在建模的整个流程中依然非常耗时,并且非常依赖于模型开发者对业务的...
  • 构造信用卡客户风险关键特征 #(1)行为特征;(2)经济风险特征#;(3)收入风险特征;(4)标准化数据 data_action = data[['瑕疵户','逾期','呆账','强制停卡记录','退票','拒往记录']] data_jingji = data[['借款...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 82,276
精华内容 32,910
关键字:

关键客户的特征