机器学习——特征工程——数据离散化(时间离散,多值离散化,连续数据离散化,分位数,聚类法,频率区间,二值化)

离散化:就是把无限空间中有限的个体映射到有限的空间中。数据离散化操作大多是针对连续数据进行的,处理之后的数据值域分布将从连续属性变为离散属性。

为什么离散化:模型中,同一线性系数应该对所有可能的计数值起作用。过大的计数值对无监督学习方法也会造成破坏,比如k-均值聚类,它使用欧氏距离作为相似度函数来测量数据点之间的相似度。数据向量某个元素中过大的计数值对相似度的影响会远超其他元素,从而破坏整体的相似度测量。

离散化方式会影响后续数据建模和应用效果:

  • 使用决策树往往倾向于少量的离散化区间,过多的离散化将使得规则过多受到碎片区间的影响。

  • 关联规则需要对所有特征一起离散化,关联规则关注的是所有特征的关联关系,如果对每个列单独离散化将失去整体规则性。

一、时间数据的离散化

离散化处理后将分散的时间特征转换为更高层次的时间特征。有以下数据,数据集地址:案例数据集《机器学习-特征工程-数据离散化-会员数据》,如下:

import pandas as pd
from sklearn.cluster import KMeans   #k-均值分类器
from sklearn import preprocessing

df=pd.read_table('data7.txt',names=['id','amount','income','datetime','age'])
df.info()
df.head()

输出:

将datetime字段转换为周数。

#针对时间数据的离散化
df['datetime1']=pd.to_datetime(df['datetime']).apply(lambda x:x.weekday())
df.head()

输出:

二、多值离散数据的离散化

多值离散数据要进行离散化可能是划分的逻辑有问题,需要重新划分,这个问题通常是由于业务逻辑的变更。

针对多值离散数据age字段的离散化

#查看age的值域
df.groupby('age')['age'].unique()

输出:

age
0-10      [0-10]
10-20    [10-20]
20-30    [20-30]
30-40    [30-40]
40-50    [40-50]
50-60    [50-60]
60-70    [60-70]
70-80    [70-80]
80-90    [80-90]
>90        [>90]
Name: age, dtype: object
#对age的值域进行重构
map_df=pd.DataFrame([['0-10','0-40'],['10-20','0-40'],['20-30','0-40'],['30-40','0-40'],
                    ['40-50','40-80'],['50-60','40-80'],['60-70','40-80'],['70-80','40-80'],
                    ['80-90','>80'],['>90','>80']],columns=['age','age2'])
map_df

#离散化
df=pd.merge(df,map_df,how='inner',on=['age'])
df

输出:

三、连续数据的离散化

连续数据的离散化结果可以分为两类:一类是将连续数据划分为特定区间的集合,例如{(0,10],(10,20],(20,50],(50,100]};一类是将连续数据划分为特定类,例如类1、类2、类3。

1、距离区间法

可使用等距区间或自定义区间的方式进行离散化,分段可以是线性的,也可以是指数性的。

该方法(尤其是等距区间)可以较好地保持数据原有的分布。

1.1、等距区间(线性)

等距区间和自定义区间都可以利用cut方法和digtize方法来实现,等距区间只要将bins序列定义成等距序列均可,等距区间可以理解为特殊的自定义区间。

下面我们介绍一种专用于等距区间划分的方法。

import numpy as np
small_counts = np.random.randint(0, 100, 20)
small_counts

bins=np.floor_divide(small_counts, 10)  #除法,结果向下取整

['['+str(i*10)+','+str((i+1)*10)+')' for i in bins]  #向下开区间

输出:

 

1.2、自定义区间

#1、自定义分箱区间
#1)cut方法
bins=[0,200,1000,5000,10000]
df['amount1']=pd.cut(df['amount'],bins)
df
#2)digitize方法
bins=bins=[0,200,1000,5000,10000]  #注意:bins数据是有要求的,bins内的数据一定要是降序或者升序的数据,不能是一堆无序数据。
indices=np.digitize(df['amount'],bins) #返回值为每个值所属区间的索引。
indices
df['amount2']=[str(bins[i-1])+"~"+str(bins[i]) for i in indices] 
df

输出:

 

digitize方法的返回值为区间上限所在bins中的索引。

1.3、指数性区间

数值横跨多个数量级时,最好按照10的幂(或任何常数的幂)来进行分组:0~9、10~99、100~999、1000~9999。

large_counts = np.array([296, 8286, 64011, 80, 3, 725, 867, 2215, 7689, 11495, 91897, 44, 28, 7971,926, 122, 22222])
large_counts

bins=np.floor(np.log10(large_counts))   #取对数之后再向下取整

['['+str(10**i)+','+str(10**(i+1))+')' for i in bins]

输出:

 

该思想也可以拓展到数据的可视化上,如我们有以下数据,数据集地址:案例数据集《机器学习-特征工程-数据离散化-会员数据2》。如下:

biz_file = open('精通特征工程/精通特征工程/data/yelp_academic_dataset_business.json')
biz_df = pd.DataFrame([json.loads(x) for x in biz_file.readlines()])
biz_file.close()

biz_df.info()

输出:

 

我们对其中的变量review_count进行分布展示,正常的分布图如下:

sns.set_style('whitegrid')
fig, ax = plt.subplots()
biz_df['review_count'].hist(ax=ax, bins=100)   #review_count表示点评数量
ax.tick_params(labelsize=14)   #设置刻度线标签字体大小
ax.set_xlabel('Review Count', fontsize=14)  #横坐标
ax.set_ylabel('Occurrence', fontsize=14) #纵坐标

输出:

我们可以看到初始的review_count数据严重集中在低计数值区域,呈现一个典型的重尾分布,对于这种情况,我们可以将坐标轴修改成按照对数分布分割的刻度,如下:

sns.set_style('whitegrid')
fig, ax = plt.subplots()
biz_df['review_count'].hist(ax=ax, bins=100)   #review_count表示点评数量
ax.set_yscale('log')   #将轴的刻度设置成对数刻度
ax.set_xscale('log')   #将轴的刻度设置成对数刻度
ax.tick_params(labelsize=14)   #设置刻度线标签字体大小
ax.set_xlabel('Review Count', fontsize=14)  #横坐标
ax.set_ylabel('Occurrence', fontsize=14) #纵坐标

输出:

 

注意:此图一般很少用,因为第一直观的视觉上容易让我们错误理解数据的原始分布。

2、聚类法

#2、聚类算法
data=df['amount']
data_reshape=data.values.reshape((data.shape[0],1))
model_kmeans=KMeans(n_clusters=4,random_state=0)
kmeans_result=model_kmeans.fit_predict(data_reshape)
df['amount3']=kmeans_result
df

输出:

 

3、分位数法

固定宽度分箱非常容易计算,但如果计数值中有比较大的缺口,就会产生很多没有任何数据的空箱子。根据数据的分布特点,进行自适应的箱体定位,就可以解决这个问题。这种方法可以使用数据分布的分位数来实现。

#3、四分位数
df['amount4']=pd.qcut(df['amount'],4
                     # ,labels=['bad','medium','good','awesome']
                     )   #分位数。 10用于十分位,四用于四分位,例如 [0,.25,.5,.75,1.]用于四分位数
df

输出:

pandas.DataFrame.qcut函数返回的是分位数区间,而pandas.DataFrame.quantile,可以返回具体的分位数的值。详见《python——numpy——数据分区(digitize,cut,qcut,quantile函数)

4、频率区间法

将数据按照不同数据的频率分布进行排序,然后按照等频率或指定频率离散化,这种方法会将数据变换成均匀分布,好处是各区间的观测值是相同的,不足是已经改变了原有数据的分布状态。

5、卡方

通过使用基于卡方的离散化方法,找出数据的最佳临近区间并合并,形成较大的区间。

四、连续数据的二值化

每个数据点和阈值进行比较,大于阈值设置为某一固定值(例如1),小于阈值设置为某一固定值(例如0),然后得到一个只拥有两个值域的二值化数据集。

#针对连续变量的二值化
binarizer_scaler=preprocessing.Binarizer(threshold=df['income'].mean())  #建立对象,threshold用于设定阈值
income_tmp=binarizer_scaler.fit_transform(df['income'].values.reshape((df['income'].shape[0],1)))  #二值化转换,需要将一维数据转换为二维数据
df['income1']=income_tmp
df

输出:

income二值化的阈值设置为income的平均值。

参考:

《python数据分析和数据化运营》

《精通特征工程》

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xia ge tou lia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值