Как сделать дискретизацию непрерывных атрибутов в склеарне?

Мои данные состоят из сочетания непрерывных и категориальных функций. Ниже приведен небольшой фрагмент того, как мои данные выглядят в формате 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]

Благодаря идеям выше;

Чтобы дискретизировать непрерывные значения, вы можете использовать:

  1. функции Pandas cut или qcut (входной массив должен быть одномерным)

или

  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 ячейки. Надеюсь, это помогло:)


Заключительные примечания:

  • Сравнивать cut versus qcutсм. этот пост
  • Для своих категориальных функций вы можете использовать KBinsDiscretizer(encode='onehot') для выполнения быстрого кодирования этой функции
Другие вопросы по тегам