当前位置:   article > 正文

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

等距离散化方法

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

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

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

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

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

一、时间数据的离散化

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

  1. import pandas as pd
  2. from sklearn.cluster import KMeans #k-均值分类器
  3. from sklearn import preprocessing
  4. df=pd.read_table('data7.txt',names=['id','amount','income','datetime','age'])
  5. df.info()
  6. df.head()

输出:

将datetime字段转换为周数。

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

输出:

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

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

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

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

输出:

  1. age
  2. 0-10 [0-10]
  3. 10-20 [10-20]
  4. 20-30 [20-30]
  5. 30-40 [30-40]
  6. 40-50 [40-50]
  7. 50-60 [50-60]
  8. 60-70 [60-70]
  9. 70-80 [70-80]
  10. 80-90 [80-90]
  11. >90 [>90]
  12. Name: age, dtype: object
  1. #对age的值域进行重构
  2. map_df=pd.DataFrame([['0-10','0-40'],['10-20','0-40'],['20-30','0-40'],['30-40','0-40'],
  3. ['40-50','40-80'],['50-60','40-80'],['60-70','40-80'],['70-80','40-80'],
  4. ['80-90','>80'],['>90','>80']],columns=['age','age2'])
  5. map_df
  6. #离散化
  7. df=pd.merge(df,map_df,how='inner',on=['age'])
  8. df

输出:

三、连续数据的离散化

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

1、距离区间法

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

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

1.1、等距区间(线性)

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

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

  1. import numpy as np
  2. small_counts = np.random.randint(0, 100, 20)
  3. small_counts
  4. bins=np.floor_divide(small_counts, 10) #除法,结果向下取整
  5. ['['+str(i*10)+','+str((i+1)*10)+')' for i in bins] #向下开区间

输出:

 

1.2、自定义区间

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

输出:

 

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

1.3、指数性区间

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

  1. large_counts = np.array([296, 8286, 64011, 80, 3, 725, 867, 2215, 7689, 11495, 91897, 44, 28, 7971,926, 122, 22222])
  2. large_counts
  3. bins=np.floor(np.log10(large_counts)) #取对数之后再向下取整
  4. ['['+str(10**i)+','+str(10**(i+1))+')' for i in bins]

输出:

 

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

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

输出:

 

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

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

输出:

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

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

输出:

 

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

2、聚类法

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

输出:

 

3、分位数法

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

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

输出:

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

4、频率区间法

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

5、卡方

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

四、连续数据的二值化

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

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

输出:

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

参考:

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

《精通特征工程》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/272631
推荐阅读
相关标签
  

闽ICP备14008679号