【指南】离散化解析与代码示例

2024年11月07日 由 alex 发表 101 0

1


大多数机器学习模型都要求数据为数值型——所有对象或类别数据必须先转换为数值格式。然而,实际上,有时类别数据会非常有用(对于人类来说,大多数时候它比我们的机器更有用)。离散化(或分箱)正是做到了这一点——将数值数据转换为类别数据!


根据你的目标,有很多方法可以对数据进行分类。在这里,我们将使用一个简单的数据集来展示六种不同的分箱方法。从等宽到基于聚类的方法,我们将把这些数值扫入一些类别箱中!


什么是离散化?

离散化,也称为分箱,是将连续数值变量转换为离散类别特征的过程。它涉及将连续变量的范围划分为多个区间(箱子),并根据数据点的值将其分配到这些箱子中。


为什么我们需要分箱?

  1. 处理异常值:分箱可以在不移除数据点的情况下减少异常值的影响。
  2. 提高模型性能:某些算法(如伯努利朴素贝叶斯)在类别输入上表现更好。
  3. 简化可视化:分箱后的数据更容易进行可视化和解释。
  4. 减少过拟合:它可以防止模型在高精度数据中拟合噪声。


哪些数据需要分箱?


通常从分箱中受益的数据:

  1. 范围广泛的连续变量:值分布范围较大的变量通常可以从分组中受益。
  2. 偏态分布:分箱可以帮助规范化严重偏斜的数据。
  3. 含有异常值的变量:分箱可以处理极端值的影响。
  4. 高基数数值数据:具有许多唯一值的变量可以通过分箱进行简化。


通常不需要分箱的数据:

  1. 已经是类别数据:已经是离散类别的变量不需要进一步分箱。
  2. 唯一值较少的离散数值数据:如果变量只有少量的可能值,分箱可能不会提供额外的好处。
  3. 数值ID或代码:这些是唯一的标识符,不是用于分析的。
  4. 时间序列数据:虽然可以对时间序列数据进行分箱,但它通常需要专门的技术和仔细考虑,但总体上较少见。


3


数据集

为了演示这些分箱技术,我们将使用这个人工数据集。假设这是某个高尔夫球场在15天内收集的天气状况数据。


4


import pandas as pd
import numpy as np
# Create the dataset as a dictionary
data = {
    'UVIndex': [2, 10, 1, 7, 3, 9, 5, 11, 1, 8, 3, 9, 11, 5, 7],
    'Humidity': [15, 95, 10, 98, 18, 90, 25, 80, 95, 40, 20, 30, 85, 92, 12], 
    'WindSpeed': [2, 90, 1, 30, 3, 10, 40, 5, 60, 15, 20, 45, 25, 35, 50],
    'RainfallAmount': [5,2,7,3,18,3,0,1,25,0,9,0,18,7,0],    
    'Temperature': [68, 60, 63, 55, 50, 56, 57, 65, 66, 68, 71, 72, 79, 83, 81],  
    'Crowdedness': [0.15, 0.98, 0.1, 0.85, 0.2, 0.9, 0.92, 0.25, 0.12, 0.99, 0.2, 0.8, 0.05, 0.3, 0.95]
}
# Create a DataFrame from the dictionary
df = pd.DataFrame(data)


利用这个数据集,我们来看看如何将各种分箱技术应用到我们的列上!


方法一:等宽分箱

等宽分箱将变量的范围划分为指定数量的区间,所有这些区间的宽度都相同。


常见数据类型:这种方法适用于分布大致均匀的数据,并且当最小值和最大值具有实际意义时效果良好。


在我们的案例中:我们将对UV指数变量应用等宽分箱。我们将创建四个箱子:低、中、高和非常高。我们选择这种方法对UV指数进行分箱,因为它为我们提供了清晰、直观的指数范围划分,这有助于理解不同的指数范围如何影响打高尔夫的决策。


5


# 1. Equal-Width Binning for UVIndex
df['UVIndexBinned'] = pd.cut(df['UVIndex'], bins=4, 
                             labels=['Low', 'Moderate', 'High', 'Very High'])


方法二:等频分箱(分位数分箱)

等频分箱创建的箱子包含大致相同数量的观测值。


常见数据类型:这种方法对于偏态数据或当你希望确保各类别之间均衡表示时特别有用。


在我们的案例中:我们将对等湿度变量应用等频分箱,创建三个箱子:低、中和高。我们选择这种方法对湿度进行分箱,是因为它能确保每个类别中有相同数量的观测值,如果湿度值在其范围内分布不均匀,这将非常有帮助。


6


# 2. Equal-Frequency Binning for Humidity
df['HumidityBinned'] = pd.qcut(df['Humidity'], q=3, 
                               labels=['Low', 'Medium', 'High'])


方法三:自定义分箱

自定义分箱允许你根据领域知识或特定需求来定义自己的箱子边界。


常见数据类型:当你在领域中具有特定且有意义的阈值,或者当你想关注特定值范围时,这种方法非常理想。


在我们的案例中:我们将对降雨量应用自定义分箱。我们选择对这一列使用这种方法,是因为降雨有标准化的类别,这些类别比任意划分更有意义。


7


# 3. Custom Binning for RainfallAmount
df['RainfallAmountBinned'] = pd.cut(df['RainfallAmount'], bins=[-np.inf, 2, 4, 12, np.inf], 
                                    labels=['No Rain', 'Drizzle', 'Rain', 'Heavy Rain'])


方法四:对数分箱

对数分箱创建的箱子大小呈指数增长。这种方法基本上是先进行对数转换,然后进行等宽分箱。


常见数据类型:这种方法对于跨越多个数量级或遵循幂律分布的数据特别有用。


在我们的案例中:我们将对风速变量应用对数分箱。我们选择这种方法对风速进行分箱,是因为风对高尔夫球轨迹的影响可能不是线性的。从0到5英里/小时的变化可能比从20到25英里/小时的变化更为显著。


8


# 4. Logarithmic Binning for WindSpeed
df['WindSpeedBinned'] = pd.cut(np.log1p(df['WindSpeed']), bins=3, 
                               labels=['Light', 'Moderate', 'Strong'])


方法五:基于标准差的分箱

基于标准差的分箱是根据数据距离均值的标准差数量来创建箱子的。这种方法在处理正态分布的数据或者当你想根据数据值偏离中心趋势的程度来进行分箱时非常有用。


变化形式:用于分箱的标准差具体数量可以根据分析的具体需求进行调整。箱子的数量通常是奇数(以便有一个中心箱子)。一些实现可能会使用不等宽的箱子,在均值附近使用较窄的箱子,在尾部使用较宽的箱子。


常见数据类型:这种方法非常适合遵循正态分布的数据,或者当你想要识别异常值并了解数据的分布范围时。对于高度偏态的分布可能不太适用。


在我们的案例中:我们将把这种分箱方法应用到温度变量上。我们选择这种方法对温度进行分箱,是因为它允许我们根据温度偏离平均值的程度来进行分类,这对于理解天气模式或气候趋势特别有用。


9


# 5. Standard Deviation-Based Binning for Temperature
mean_temp, std_dev = df['Temperature'].mean(), df['Temperature'].std()
bin_edges = [
    float('-inf'),  # Ensure all values are captured
    mean_temp - 2.5 * std_dev,
    mean_temp - 1.5 * std_dev,
    mean_temp - 0.5 * std_dev,
    mean_temp + 0.5 * std_dev,
    mean_temp + 1.5 * std_dev,
    mean_temp + 2.5 * std_dev,
    float('inf')   # Ensure all values are captured
]
df['TemperatureBinned'] = pd.cut(df['Temperature'], bins=bin_edges, 
                                 labels=['Very Low', 'Low', 'Below Avg', 'Average','Above Avg', 'High', 'Very High'])


方法六:K均值分箱

K均值分箱使用K均值聚类算法来创建箱子。它根据数据点之间的相似程度将数据点分组,每个聚类成为一个箱子。


常见数据类型:这种方法非常适合于在数据中寻找可能初看并不明显的群体。它适用于具有一个或多个峰值的数据,并且能够根据数据的组织方式进行调整。


在我们的案例中:我们将对拥挤度变量应用K均值分箱。我们选择这种方法对拥挤度进行分箱,是因为它可能会揭示出高尔夫球场繁忙程度的自然分组,这些分组可能受到简单阈值分箱无法捕捉到的各种因素的影响。


10


# 6. K-Means Binning for Crowdedness
kmeans = KMeans(n_clusters=3, random_state=42).fit(df[['Crowdedness']])
df['CrowdednessBinned'] = pd.Categorical.from_codes(kmeans.labels_, categories=['Low', 'Medium', 'High'])


结论

我们尝试了六种不同的方法来对高尔夫数据中的数值进行“离散化”。因此,最终的数据集现在看起来是这样的:


11


# Print only the binned columns
binned_columns = [col for col in df.columns if col.endswith('Binned')]
print(df[binned_columns])


让我们回顾一下每种分箱技术是如何转换我们的天气数据的:

  1. 等宽分箱(UV指数):将我们的UV指数划分为四个等距范围,将暴露水平分为“低”到“非常高”四个类别。这为我们提供了对UV强度的直观解释。
  2. 等频分箱(湿度):将我们的湿度读数分为“低”、“中”和“高”三个类别,每个类别包含相同数量的数据点。这种方法确保了在不同湿度水平上的均衡表示。
  3. 对数分箱(风速):应用于我们的风速数据,这种方法考虑了风对天气条件的非线性影响,将风速分为“轻风”、“中风”或“强风”三个类别。
  4. 自定义分箱(降雨量):利用领域知识将降雨量分为从“无雨”到“大雨”的有意义类别。这种方法直接将测量结果转化为实际的天气描述。
  5. 基于标准差的分箱(温度):根据温度数据的分布进行分段,范围从“非常低”到“非常高”。这种方法突出了温度如何偏离平均值。
  6. K均值分箱(拥挤度):显示了我们的拥挤度数据中的自然分组,可能揭示了某些模式。


重要的是要避免盲目地应用分箱技术。每个变量的性质和你的分析目标都是多变的,在选择分箱方法时,牢记这一点是很有帮助的。在许多情况下,尝试多种技术并比较它们的结果,可以为你提供对数据的最深入见解!


离散化总结


import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
# Create the dataset
data = {
    'UVIndex': [2, 10, 1, 7, 3, 9, 5, 11, 1, 8, 3, 9, 11, 5, 7],
    'Humidity': [15, 95, 10, 98, 18, 90, 25, 80, 95, 40, 20, 30, 85, 92, 12], 
    'WindSpeed': [2, 90, 1, 30, 3, 10, 40, 5, 60, 15, 20, 45, 25, 35, 50],
    'RainfallAmount': [5,2,7,3,18,3,0,1,25,0,9,0,18,7,0],    
    'Temperature': [68, 60, 63, 55, 50, 56, 57, 65, 66, 68, 71, 72, 79, 83, 81],  
    'Crowdedness': [0.15, 0.98, 0.1, 0.85, 0.2, 0.9, 0.92, 0.25, 0.12, 0.99, 0.2, 0.8, 0.05, 0.3, 0.95]
}
# Create a DataFrame from the dictionary
df = pd.DataFrame(data)
# 1. Equal-Width Binning for UVIndex
df['UVIndexBinned'] = pd.cut(df['UVIndex'], bins=4, 
                             labels=['Low', 'Moderate', 'High', 'Very High'])
# 2. Equal-Frequency Binning for Humidity
df['HumidityBinned'] = pd.qcut(df['Humidity'], q=3, 
                               labels=['Low', 'Medium', 'High'])
# 3. Custom Binning for RainfallAmount
df['RainfallAmountBinned'] = pd.cut(df['RainfallAmount'], bins=[-np.inf, 2, 4, 12, np.inf], 
                                    labels=['No Rain', 'Drizzle', 'Rain', 'Heavy Rain'])
# 4. Logarithmic Binning for WindSpeed
df['WindSpeedBinned'] = pd.cut(np.log1p(df['WindSpeed']), bins=3, 
                               labels=['Light', 'Moderate', 'Strong'])
# 5. Standard Deviation-Based Binning for Temperature
mean_temp, std_dev = df['Temperature'].mean(), df['Temperature'].std()
bin_edges = [
    float('-inf'),  # Ensure all values are captured
    mean_temp - 2.5 * std_dev,
    mean_temp - 1.5 * std_dev,
    mean_temp - 0.5 * std_dev,
    mean_temp + 0.5 * std_dev,
    mean_temp + 1.5 * std_dev,
    mean_temp + 2.5 * std_dev,
    float('inf')   # Ensure all values are captured
]
df['TemperatureBinned'] = pd.cut(df['Temperature'], bins=bin_edges, 
                                 labels=['Very Low', 'Low', 'Below Avg', 'Average','Above Avg', 'High', 'Very High'])
# 6. KMeans Binning for Crowdedness
kmeans = KMeans(n_clusters=3, random_state=42).fit(df[['Crowdedness']])
df['CrowdednessBinned'] = pd.Categorical.from_codes(kmeans.labels_, categories=['Low', 'Medium', 'High'])
# Print only the binned columns
binned_columns = [col for col in df.columns if col.endswith('Binned')]
print(df[binned_columns])

文章来源:https://towardsdatascience.com/discretization-explained-a-visual-guide-with-code-examples-for-beginners-f056af9102fa
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消