python 等深分箱 等宽分箱结合二分箱的数据分析

                                                                               python 等深分箱 等宽分箱结合二分箱的数据分析

Python里可以通过pcut(等深分箱 每箱的样本量基本一致)和cut(等宽分箱 样本量之间有相同的宽度)对样本进行分箱。详见如下代码部分。本文的数据来自网络,部分代码也有所参照,这里做了注释和延伸,旨在技术交流,如有冒犯之处请联系博主及时处理。

 

#coding:utf-8
import datetime
import pandas as pd
def RFM():

    trad_flow = pd.read_csv(r'../input/RFM_TRAD_FLOW.csv',encoding="GBK")
    trad_flow_new = trad_flow.copy()
    ##trad_flow_new['time_new']=trad_flow_new['time'].apply(lambda x :timeFormat(x))
    trad_flow_new['time_format'] = trad_flow_new.time.apply(timeFormat)
    ##pd.set_option('display.max_rows', 9)
    pd.set_option('precision', 2) #小数点保留位
    pd.set_option('display.max_columns', 18) #最大列数
    pd.set_option('expand_frame_repr', False) #不换行显示
    pd.set_option('display.width', 200)#横向最多显示的字符数
    ##print(trad_flow_new.head(10))
    ##对用户按照列cumid、type分组,列transID统计数量
    F = trad_flow_new.groupby(['cumid','type'])[['transID']].count()
    ##print(F.head())
    ##对DataFrame F按照type、transID进行pivot,即行列转换
    F_trans = pd.pivot_table(F, index='cumid', columns='type', values='transID')
    ##print(F_trans.head())
    # 计算不包含Normal的数据
    ## 查看returned_goods、Normal 列是否有空值,如果有则用0代替。shape[0]是行数,shape[1]是列数
    ##print(F_trans[F_trans.returned_goods.isnull()].shape[0])#shape[1]
    ## 仅仅对数据列里有NULL的用0来填充
    ##F_trans=F_trans[F_trans.isnull().T.any()].fillna(0)
    F_trans = F_trans.fillna(0)
    ##F_trans['Special_offer'] = F_trans['Special_offer'].fillna(0) ##单独对列FillNa
    ## 计算兴趣比,这里是 特价/(特价+正常)
    F_trans['interest'] = F_trans.Special_offer/(F_trans.Special_offer+F_trans.Normal)
    ##print(F_trans.head())
    #print(trad_flow_new[trad_flow_new['cumid']==19021]) #查看cumid等于19021的明细
    ##顾客价值信息取向
    M = trad_flow_new.groupby(['cumid','type'])[['amount']].sum()
    M_trans = pd.pivot_table(M,index='cumid',columns='type',values='amount')
    M_trans = M_trans.fillna(0)
    M_trans['value']=M_trans.Normal + M_trans.Special_offer+M_trans.returned_goods
    ##print(M_trans.head(10))
    trad_flow_new['time_new']=trad_flow_new.time.apply(to_time)
    R = trad_flow_new.groupby(['cumid'])[['time_new']].max()
    ##print(R.head())
    from sklearn import preprocessing
    #这里是等深分箱q即quantile,这里参数是分成两箱。
    threshold = pd.qcut(F_trans['interest'], 2, retbins=True)[1][1]

    print("F 值二分类右边界:\t"+str(threshold))


    #对F dataframe做二分类转换
    binarizer = preprocessing.Binarizer(threshold=threshold) ## 定义二分类转换器
    single_row=F_trans['interest'].values.reshape(-1,1) ## 提取interest列到ndarray中,这里-1是指行数未知
    b_f_interest = pd.DataFrame(binarizer.transform(single_row)) ##通过二分类转换器转换单列并生成DataFrame
    b_f_interest.index = F_trans.index
    b_f_interest.columns=['interest']

    #对M dataframe的二分类转换
    threshold = pd.qcut(M_trans['value'], 2, retbins=True)[1][1]
    print("M 值二分类右边界:\t" + str(threshold))
    binarizer = preprocessing.Binarizer(threshold=threshold)
    single_row = M_trans['value'].values.reshape(-1,1)
    b_m_value = pd.DataFrame(binarizer.transform(single_row))
    b_m_value.index = M_trans.index
    b_m_value.columns=['value']
    ##print(b_m_value.head())

    #对R dataframe的二分类转换
    threshold = pd.qcut(R['time_new'],2,retbins=True)[1][1]
    print("R 值二分类右边界:\t" + str(threshold))
    binarizer = preprocessing.Binarizer(threshold=threshold)
    single_row = R.time_new.values.reshape(-1,1)
    b_r_time= pd.DataFrame(binarizer.transform(single_row))
    b_r_time.index = R.index
    b_r_time.columns=['time']
    total = pd.concat([b_f_interest,b_m_value,b_r_time],axis=1)
    ##print(total.head())
    ##定义标签,按照FMR 2*2*2 = 8种情况定义出客户标签
    label = {
        (0, 0, 0): '无兴趣-低价值-沉默',
        (1, 0, 0): '有兴趣-低价值-沉默',
        (1, 0, 1): '有兴趣-低价值-活跃',
        (0, 0, 1): '无兴趣-低价值-活跃',
        (0, 1, 0): '无兴趣-高价值-沉默',
        (1, 1, 0): '有兴趣-高价值-沉默',
        (1, 1, 1): '有兴趣-高价值-活跃',
        (0, 1, 1): '无兴趣-高价值-活跃'
    }

    total['label'] = total[['interest','value','time']].apply(lambda x:label[((x[0],x[1],x[2]))], axis = 1)
    print(total.head())

def timeFormat(Str):
    import datetime
    return datetime.datetime.strptime(Str,'%d%b%y:%H:%M:%S')

def to_time(t):
    import time
    out_t=time.mktime(time.strptime(t, '%d%b%y:%H:%M:%S'))   ##转换为数字类型(即与1970-1-1 8:00:00的秒数差值)方便后面qcut分箱
    return out_t

def boxsplit():
    F_x = pd.DataFrame(data={'age': [18, 19, 23, 25, 27, 29,34,45]})
    ''' Method 1 等宽分箱,宽度 w= (Max-Min)/N 即 (45-18)/3= 9,则每个分箱的右边界为 Min+(N-1)*w
    第一个分箱的边界是 18+9*1=27、第二个分箱的边界是 18+9*2=36、第三个分箱的边界是 18+9*3=45
    '''
    ##print(pd.cut(F_x['age'], 3))
    print(pd.cut(F_x['age'], 3).value_counts())

    '''  Method 2 等深分箱(等频分箱),先通过分位数计算各个分位数对应的临界值,再"等"分数据
    '''
    print(F_x.age.quantile([0, 1 / 3, 2 / 3, 1]))
    #print(pd.qcut(F_x['age'], 3, retbins=True))
    print(pd.qcut(F_x['age'], 3).value_counts())

    '''通过观察不难发现等深分箱每组的数量基本一致 而等宽分箱每组的数量可能差距较大'''

    '''卡方合并法(待补充)'''
def baseTime():
    import time
    t = (1970, 1, 1, 8, 0, 0, 3, 1, 0)
    secs = time.mktime(t)
    print("time.mktime(t) : %f" % secs)
    print("asctime(localtime(secs)): %s" % time.asctime(time.localtime(secs)))




if __name__ == '__main__':
    #print(timeFormat('14MAY10:13:31:23'))
    RFM()
    #a="14JUN09:17:58:34"
    #print(to_time(a))
    boxsplit()
    baseTime()

 

执行结果:

"F:\Program Files\Python37\python.exe" E:/DevData/GiteePython/com/shenl/ml/RFM/RFM.py
F 值二分类右边界:    0.08333333333333333
M 值二分类右边界:    2944.5
R 值二分类右边界:    1284373750.0
       interest  value  time       label
cumid                                   
10001       1.0    1.0   1.0  有兴趣-高价值-活跃
10002       0.0    0.0   0.0  无兴趣-低价值-沉默
10003       0.0    1.0   0.0  无兴趣-高价值-沉默
10004       1.0    1.0   0.0  有兴趣-高价值-沉默
10005       0.0    0.0   0.0  无兴趣-低价值-沉默
(17.973, 27.0]    5
(27.0, 36.0]      2
(36.0, 45.0]      1
Name: age, dtype: int64
0.00    18.00
0.33    23.67
0.67    28.33
1.00    45.00
Name: age, dtype: float64
(28.333, 45.0]      3
(17.999, 23.667]    3
(23.667, 28.333]    2
Name: age, dtype: int64
time.mktime(t) : 0.000000
asctime(localtime(secs)): Thu Jan  1 08:00:00 1970

Process finished with exit code 0
 

 

你可能感兴趣的:(Python基础,机器学习)