离散化,就是把无限空间中有限的个体映射到有限的空间中。数据离散的操作大多是针对连续数据进行的,处理之后的数据值域分布将从连续属性变为离散属性。
离散化通常针对连续数据进行处理,但是在很多情况下也可以针对已经是离散化的数据进行处理,这种场景一般是离散数据本身的划分过于复杂、琐碎甚至不符合业务逻辑,需要进一步做数据聚合或重新划分。
针对时间数据的离散化主要用于以时间为主要特征的数据集中和粒度转换,离散化处理后将分散的时间特征转换为更高层次的时间特征。在带有时间的数据集中,时间可能作为行记录的序列,也可能作为列(维度)记录数据特征。常见的针对时间数据的离散化操作分为两类:
1.针对一天中的时间离散化。一般是将时间戳转换为秒、分钟、小时或上下午。
2.针对日粒度以上数据的离散化。一般是将日期转换为周数、周几、月、工作日、季度、年等。
针对多值离散数据的离散化指的是要进行离散化处理的数据本身不是数值型数据,而是分类或顺序数据。例如,用户收入变量的值原来可能划分为10个区间,根据新的建模需求,只需要划分为4个区间,那么就需要对原来10个区间进行合并。
多值离散数据要进行离散化还有可能是划分的逻辑有问题,需要重新划分。例如,用户活跃度变量的值,原来分为高价值、中价值、低价值3个类别;根据业务发展的需要,新的用户活跃读变量的值定义为高价值、中价值、低价值、负价值4类。此时需要对不同类别的数据进行统一规则的离散化处理。
针对连续数据的离散化是主要的离散化应用,这些算法的结果以类别或属性标识为基础,而非数值标记。连续数据的离散化结果可以分为两类:一类是将连续数据划分为特定区间的集合,例如{(0,10],(10,20],(20,50],(50,100]};一类是将连续数据划分为特定类,例如类1、类2、类3;常见实现针对连续数据离散化的方法包括:
分位数法:使用四分位、五分位、十分位等分位数进行离散化处理,这种方法简单易行。
距离区间法:可使用等距区间或自定义区间的方式进行离散化,这种操作更加灵活且能满足自定义需求,另外该方法(尤其是等距区间)能较好地保持数据原有的分布。
频率区间法:将数据按照不同数据的频率分布进行排序,然后按照等频率或指定频率离散化,这种方法会把数据变换成均匀分布,好处是各区间的观察值是相同的,不足是已经改变了原有数据的分布形态。
聚类法:例如使用K均值将样本集分为多个离散化地簇。
卡方: 通过使用基于卡方的离散化方法,找出数据的最佳临近区间并合并,形成较大的区间。
在很多场景下,我们可能需要将变量特征进行二值化操作:每个数据点跟阈值比较,大于阈值设置为某一固定值(例如1),小于阈值设置为另一固定值(例如0),然后得到一个只拥有两个值域的二值化数据集。二值化应用的前提是数据集中所有的属性值所代表的含义相同或类似。
import pandas as pd
from sklearn.cluster import KMeans
from sklearn import preprocessing
df=pd.read_table('F:\小橙书\chapter3\data7.txt',names=['id','amount','income','datetime','age'])
df.head(5)
id | amount | income | datetime | age | |
---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 2017-04-30 19:24:13 | 0-10 |
1 | 15062 | 4024 | 4.68 | 2017-04-27 22:44:59 | 70-80 |
2 | 15028 | 6359 | 3.84 | 2017-04-27 10:07:55 | 40-50 |
3 | 15012 | 7759 | 3.70 | 2017-04-04 07:28:18 | 30-40 |
4 | 15021 | 331 | 4.25 | 2017-04-08 11:14:00 | 70-80 |
for i,single_data in enumerate(df['datetime']):
single_data_tmp=pd.to_datetime(single_data)
df['datetime'][i]=single_data_tmp.weekday()
df.head(5)
id | amount | income | datetime | age | |
---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 |
1 | 15062 | 4024 | 4.68 | 3 | 70-80 |
2 | 15028 | 6359 | 3.84 | 3 | 40-50 |
3 | 15012 | 7759 | 3.70 | 1 | 30-40 |
4 | 15021 | 331 | 4.25 | 5 | 70-80 |
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'])
df_tmp=df.merge(map_df,left_on='age',right_on='age',how='inner')
df_tmp
id | amount | income | datetime | age | age2 | |
---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-10 | 0-40 |
1 | 15064 | 7952 | 4.40 | 0 | 0-10 | 0-40 |
2 | 15080 | 503 | 5.72 | 5 | 0-10 | 0-40 |
3 | 15068 | 1668 | 3.19 | 5 | 0-10 | 0-40 |
4 | 15019 | 6710 | 3.20 | 0 | 0-10 | 0-40 |
... | ... | ... | ... | ... | ... | ... |
95 | 15098 | 2014 | 3.03 | 6 | 60-70 | 40-80 |
96 | 15046 | 6215 | 5.09 | 2 | 80-90 | >80 |
97 | 15095 | 5294 | 3.74 | 1 | 80-90 | >80 |
98 | 15074 | 5381 | 3.28 | 6 | 80-90 | >80 |
99 | 15074 | 4834 | 3.92 | 2 | 80-90 | >80 |
100 rows × 6 columns
df=df_tmp.drop('age',1)
df.head(5)
id | amount | income | datetime | age2 | |
---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-40 |
1 | 15064 | 7952 | 4.40 | 0 | 0-40 |
2 | 15080 | 503 | 5.72 | 5 | 0-40 |
3 | 15068 | 1668 | 3.19 | 5 | 0-40 |
4 | 15019 | 6710 | 3.20 | 0 | 0-40 |
方法一:自定义分箱区间实现离散化
bins=[0,200,1000,5000,10000]
df['amount1']=pd.cut(df['amount'],bins)
df.head(5)
id | amount | income | datetime | age2 | amount1 | |
---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-40 | (1000, 5000] |
1 | 15064 | 7952 | 4.40 | 0 | 0-40 | (5000, 10000] |
2 | 15080 | 503 | 5.72 | 5 | 0-40 | (200, 1000] |
3 | 15068 | 1668 | 3.19 | 5 | 0-40 | (1000, 5000] |
4 | 15019 | 6710 | 3.20 | 0 | 0-40 | (5000, 10000] |
方法二:使用聚类法实现离散化
import numpy as np
data=df.loc[:,'amount']
data_reshape=data.values.reshape(-1,1)
model_kmeans=KMeans(n_clusters=4,random_state=0)
kmeans_result=model_kmeans.fit_predict(data_reshape)
df['amount2']=kmeans_result
df.head(5)
id | amount | income | datetime | age2 | amount1 | amount2 | |
---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-40 | (1000, 5000] | 2 |
1 | 15064 | 7952 | 4.40 | 0 | 0-40 | (5000, 10000] | 1 |
2 | 15080 | 503 | 5.72 | 5 | 0-40 | (200, 1000] | 2 |
3 | 15068 | 1668 | 3.19 | 5 | 0-40 | (1000, 5000] | 2 |
4 | 15019 | 6710 | 3.20 | 0 | 0-40 | (5000, 10000] | 1 |
方法三:使用四分位数实现离散化
labels=['bad','medium','good','awesome']
df['amount3']=pd.qcut(df['amount'],4,labels=labels)
df.head(5)
id | amount | income | datetime | age2 | amount1 | amount2 | amount3 | |
---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-40 | (1000, 5000] | 2 | bad |
1 | 15064 | 7952 | 4.40 | 0 | 0-40 | (5000, 10000] | 1 | awesome |
2 | 15080 | 503 | 5.72 | 5 | 0-40 | (200, 1000] | 2 | bad |
3 | 15068 | 1668 | 3.19 | 5 | 0-40 | (1000, 5000] | 2 | bad |
4 | 15019 | 6710 | 3.20 | 0 | 0-40 | (5000, 10000] | 1 | awesome |
binarizer_scaler=preprocessing.Binarizer(threshold=df['income'].mean())
df_income=df.loc[:,'income'].values.reshape(-1,1)
income_tmp=binarizer_scaler.fit_transform(df_income)
# income_tmp
income_tmp.resize(df['income'].shape)
df['income1']=income_tmp
df.head(5)
id | amount | income | datetime | age2 | amount1 | amount2 | amount3 | income1 | |
---|---|---|---|---|---|---|---|---|---|
0 | 15093 | 1390 | 10.40 | 6 | 0-40 | (1000, 5000] | 2 | bad | 1.0 |
1 | 15064 | 7952 | 4.40 | 0 | 0-40 | (5000, 10000] | 1 | awesome | 1.0 |
2 | 15080 | 503 | 5.72 | 5 | 0-40 | (200, 1000] | 2 | bad | 1.0 |
3 | 15068 | 1668 | 3.19 | 5 | 0-40 | (1000, 5000] | 2 | bad | 0.0 |
4 | 15019 | 6710 | 3.20 | 0 | 0-40 | (5000, 10000] | 1 | awesome | 0.0 |