如何在sklearn中对连续属性进行离散化?

时间:2014-04-24 11:35:24

标签: scikit-learn discretization

我的数据包含连续和分类功能的混合。下面是我的数据在csv格式中的一小部分(将其视为由在不同城市运营商店的超级商店链收集的数据)

city,avg_income_in_city,population,square_feet_of_store_area,  store_type ,avg_revenue
NY  ,54504            , 3506908   ,3006                       ,INDOOR    , 8000091
CH  ,44504            , 2505901   ,4098                       ,INDOOR    , 4000091
HS  ,50134            , 3206911   ,1800                       ,KIOSK     , 7004567
NY  ,54504            , 3506908   ,1000                       ,KIOSK     , 2000091

她可以看到avg_income_in_city,square_feet_of_store_area和avg_revenue是连续值,其中city,store_type等是分类类(还有一些我没有在这里展示以保持数据的简洁性)。

我希望对数据建模以预测收入。问题是如何使用sklearn“离散”连续值? sklearn是否为连续值的离散化提供了任何“现成的”类/方法? (就像我们在Orange中一样,例如Orange.Preprocessor_discretize(data,method = orange.EntropyDiscretization())

谢谢!

5 个答案:

答案 0 :(得分:8)

答案是否定的。 scikit-learn中没有binning。正如eickenberg所说,你可能想要使用np.histogram。假设scikit-learn中的特征是连续的,而不是离散的。没有装箱的主要原因可能是大部分sklearn是基于文本,图像特征或来自科学界的数据集开发的。在这些设置中,分箱很少有用。你知道一个免费提供的数据集,其中binning真的有用吗?

答案 1 :(得分:4)

您也可以考虑将分类变量数字化,例如通过指标变量,一个程序也称为一个热编码

尝试

from sklearn.preprocessing import OneHotEncoder

并使其适合您的分类数据,然后使用数值估算方法,如线性回归。只要没有太多类别(城市可能有点太多),这可以很好地运作。

对于连续变量的离散化,您可以考虑使用适应的bin大小进行分级,或者等效地,在直方图归一化之后进行均匀分级。 numpy.histogram在这里可能会有所帮助。此外,虽然Fayyad-Irani群集未在sklearn中实施,但请随时查看sklearn.cluster您的数据的自适应离散化(即使它只是1D),例如通过KMeans。

答案 2 :(得分:2)

更新(2018年9月):从0.20.0版开始,有一个函数sklearn.preprocessing.KBinsDiscretizer,它使用几种不同的策略离散化了连续特征:

  • 大小一致的垃圾箱
  • 内部具有尽可能相等数量的样本的容器
  • 基于K均值聚类的容器

不幸的是,目前,该函数不接受自定义间隔(这对我来说真是令人讨厌,因为这正是我想要的,也是我最终来到这里的原因)。如果要达到相同的目的,可以使用Pandas函数cut

import numpy as np
import pandas as pd
n_samples = 10
a = np.random.randint(0, 10, n_samples)

# say you want to split at 1 and 3
boundaries = [1, 3]
# add min and max values of your data
boundaries = sorted({a.min(), a.max() + 1} | set(boundaries))

a_discretized_1 = pd.cut(a, bins=boundaries, right=False)
a_discretized_2 = pd.cut(a, bins=boundaries, labels=range(len(boundaries) - 1), right=False)
a_discretized_3 = pd.cut(a, bins=boundaries, labels=range(len(boundaries) - 1), right=False).astype(float)
print(a, '\n')
print(a_discretized_1, '\n', a_discretized_1.dtype, '\n')
print(a_discretized_2, '\n', a_discretized_2.dtype, '\n')
print(a_discretized_3, '\n', a_discretized_3.dtype, '\n')

产生:

[2 2 9 7 2 9 3 0 4 0]

[[1, 3), [1, 3), [3, 10), [3, 10), [1, 3), [3, 10), [3, 10), [0, 1), [3, 10), [0, 1)]
Categories (3, interval[int64]): [[0, 1) < [1, 3) < [3, 10)]
 category

[1, 1, 2, 2, 1, 2, 2, 0, 2, 0]
Categories (3, int64): [0 < 1 < 2]
 category

[1. 1. 2. 2. 1. 2. 2. 0. 2. 0.]
 float64

请注意,默认情况下,pd.cut返回类型为Category的dtype为interval[int64]的pd.Series对象。如果您指定自己的labels,则输出的dtype仍为Category,但元素的类型为int64。如果希望系列具有数字dtype,则可以使用.astype(np.int64)

我的示例使用整数数据,但它与浮点数一样适用。

答案 3 :(得分:1)

您可以使用pandas.cut方法,如下所示:

bins = [0, 4, 10, 30, 45, 99999]
labels = ['Very_Low_Fare', 'Low_Fare', 'Med_Fare', 'High_Fare','Very_High_Fare']
train_orig.Fare[:10]
Out[0]: 
0     7.2500
1    71.2833
2     7.9250
3    53.1000
4     8.0500
5     8.4583
6    51.8625
7    21.0750
8    11.1333
9    30.0708
Name: Fare, dtype: float64

pd.cut(train_orig.Fare, bins=bins, labels=labels)[:10]
Out[50]: 
0          Low_Fare
1    Very_High_Fare
2          Low_Fare
3    Very_High_Fare
4          Low_Fare
5          Low_Fare
6    Very_High_Fare
7          Med_Fare
8          Med_Fare
9         High_Fare
Name: Fare, dtype: category
Categories (5, object): [High_Fare < Low_Fare < Med_Fare < Very_High_Fare < Very_Low_Fare]

答案 4 :(得分:0)

感谢上述想法;

要离散化连续值,可以使用:

  1. 熊猫cutqcut函数(输入数组必须为一维

  1. sklearn的KBinsDiscretizer函数(参数encode设置为“普通”)

    • 参数strategy = uniform将以与pd.cut相同的方式离散化。
    • 参数strategy = quantile将以与pd.qcut函数相同的方式离散化

由于先前的答案中提供了cut / qcut的示例,因此让我们继续使用KBinsDiscretizer上的干净示例:

import numpy as np
from sklearn.preprocessing import KBinsDiscretizer

A = np.array([[24,0.2],[35,0.3],[74,0.4], [96,0.5],[2,0.6],[39,0.8]])
print(A)
# [[24.   0.2]
#  [35.   0.3]
#  [74.   0.4]
#  [96.   0.5]
#  [ 2.   0.6]
#  [39.   0.8]]


enc = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
enc.fit(A)
print(enc.transform(A))
# [[0. 0.]
#  [1. 0.]
#  [2. 1.]
#  [2. 1.]
#  [0. 2.]
#  [1. 2.]]

如输出所示,每个特征已离散为3个bin。 希望这对您有所帮助:)


最后的笔记:

  • 要比较cut versus qcut,请参见此post
  • 对于您的分类功能,您可以利用KBinsDiscretizer(encode='onehot')对该功能执行一键热编码