Реализация Pandas оставить один кодировку для категориальных функций

Недавно я смотрел видео от Оуэна Чжана Каггла, претендента на звание 1: https://youtu.be/LgLcfZjNF44 где он объясняет метод кодирования категориальных функций в числовом, который называется "оставь один кодировку". Что он делает с категориальным признаком, так это сопоставляет значение с каждым наблюдением, которое является средним значением ответа для всех других наблюдений с той же категорией.

Я пытался реализовать эту стратегию в Python, используя панд. Хотя мне удалось создать успешный код, тот факт, что мой набор данных имеет размеры в десятки миллионов, его производительность очень низкая. Если бы кто-то мог предложить более быстрое решение, я был бы очень благодарен.

Это мой код до сих пор:

def categ2numeric(data, train=True):
    def f(series):
        indexes = series.index.values
        pomseries = pd.Series()
        for i, index in enumerate(indexes):
            pom = np.delete(indexes, i)
            pomseries.loc[index] = series[pom].mean()
        series = pomseries
        return series

    if train:
        categ = data.groupby(by=['Cliente_ID'])['Demanda_uni_equil'].apply(f)

И мне нужно включить эту серию:

            159812     28.0
            464556     83.0
            717223     45.0
            1043801    21.0
            1152917     7.0
            Name: 26, dtype: float32

к этому:

            159812     39.00
            464556     25.25
            717223     34.75
            1043801    40.75
            1152917    44.25
            dtype: float64

Или математически элемент с индексом 159812 равен среднему значению всех других элементов или:

39 = (83 + 45 + 21 + 7) / 4

2 ответа

Решение

Замените каждый элемент Серии разницей между суммой Серии и элементом, затем разделите на длину серии минус 1. Предполагая, s ваша серия:

s = (s.sum() - s)/(len(s) - 1)

Полученный результат:

159812     39.00
464556     25.25
717223     34.75
1043801    40.75
1152917    44.25

С помощью @root я обнаружил, что самым быстрым решением этой проблемы был бы такой подход:

cs = train.groupby(by=['Cliente_ID'])['Demanda_uni_equil'].sum()
cc = train['Cliente_ID'].value_counts()
boolean = (cc == 1)
index = boolean[boolean == True].index.values
cc.loc[boolean] += 1
cs.loc[index] *= 2
train = train.join(cs.rename('sum'), on=['Cliente_ID'])
train = train.join(cc.rename('count'), on=['Cliente_ID'])
train['Cliente_IDloo'] = (train['sum'] - train['Demanda_uni_equil'])/(train['count'] - 1)
del train['sum'], train['count']

Я обнаружил, что если использовать метод apply с вызываемой функцией в качестве входных данных, это займет 2 минуты, в то время как этот подход занимает всего 1 секунду, хотя это немного громоздко.

Есть библиотека: category_encoders с синтаксисом кода, аналогичным синтаксисуsikit-learn.

Итак, вы можете использовать что-то вроде:

from category_encoders import LeaveOneOutEncoder

LeaveOneOutEncoder.fit(X, y)
Другие вопросы по тегам