Как сделать дискретизацию непрерывных атрибутов в склеарне?
Мои данные состоят из сочетания непрерывных и категориальных функций. Ниже приведен небольшой фрагмент того, как мои данные выглядят в формате 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.EntropyDiscretification())
Спасибо!
4 ответа
Обновление (сентябрь 2018 г.): по состоянию на версию 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
возвращает объект pd.Series типа dtype Category
с элементами типа interval[int64]
, Если вы укажете свой собственный labels
, dtype вывода все еще будет Category
, но элементы будут иметь тип int64
, Если вы хотите, чтобы серия имела числовой тип d, вы можете использовать .astype(np.int64)
,
Мой пример использует целочисленные данные, но он должен работать так же хорошо с плавающей точкой.
Ответ - нет. В scikit-learn нет биннинга. Как сказал Айкенберг, вы можете использовать np.histogram. Особенности в scikit-learn предполагается непрерывными, а не дискретными. Основная причина отсутствия биннинга заключается, вероятно, в том, что большая часть склеарна разработана на основе текста, изображений или набора данных научного сообщества. В этих настройках биннинг редко бывает полезен. Знаете ли вы о свободно доступном наборе данных, где биннинг действительно полезен?
Вы также можете рассмотреть возможность преобразования числовых переменных Категориального типа, например, через переменные индикатора, процедуру, также известную как одно горячее кодирование.
Пытаться
from sklearn.preprocessing import OneHotEncoder
и подгоните его под ваши категориальные данные, а затем примените метод численной оценки, такой как линейная регрессия. Пока не слишком много категорий (город может быть немного слишком много), это может работать хорошо.
Что касается дискретизации непрерывных переменных, вы можете рассмотреть бинирование с использованием адаптированного размера бина или, что эквивалентно, равномерное бинирование после нормализации гистограммы. numpy.histogram
может быть полезно здесь. Кроме того, в то время как Файяд-иранская кластеризация не внедрена в sklearn
не стесняйтесь проверить sklearn.cluster
для адаптивной дискретизации ваших данных (даже если это только 1D), например, через KMeans .
Вы можете использовать метод 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]
Благодаря идеям выше;
Чтобы дискретизировать непрерывные значения, вы можете использовать:
или
функция 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 ячейки. Надеюсь, это помогло:)
Заключительные примечания:
- Сравнивать
cut versus qcut
см. этот пост - Для своих категориальных функций вы можете использовать
KBinsDiscretizer(encode='onehot')
для выполнения быстрого кодирования этой функции