Реализация 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)