Pandas分类特征留一法编码的实现

Pandas realization of leave one out encoding for categorical features

最近看了Owen Zhang kaggle rank 1选手的视频: https://youtu.be/LgLcfZjNF44 他解释了一种将分类特征编码为数字的技术,称为留一法编码。他对分类特征所做的是将每个观察值与一个值相关联,该值是对具有相同类别的所有其他观察值的响应的平均值。

我一直在尝试使用 pandas 在 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

用系列之和与元素之差替换系列的每个元素,然后除以系列的长度减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)