gpt4 book ai didi

python - 创建一个自定义的 sklearn TransformerMixin 来一致地转换分类变量

转载 作者:太空狗 更新时间:2023-10-30 00:53:19 27 4
gpt4 key购买 nike

这个问题不是duplicate正如有人建议的那样。为什么?因为在那个例子中,所有可能的值都是已知的。在这个例子中,他们不是。此外,除了对未知值使用自定义转换器之外,这个问题还特别询问如何以与初始转换完全相同的方式执行转换。我再次确定我最终必须回答我自己的问题。


在创建自定义 scikit-learn 转换器时,您如何保证或“强制”转换方法仅输出最初适合的列?

下图说明。这是我的示例转换器。

import numpy as np
import pandas as pd
from sklearn.base import TransformerMixin
from sklearn.linear_model import LogisticRegression

class DFTransformer(TransformerMixin):

def fit(self, df, y=None, **fit_params):
return self

def transform(self, df, **trans_params):
self.df = df
self.STACKER = pd.DataFrame()

for col in self.df:
dtype = self.df[col].dtype.name
if dtype == 'object':
self.STACKER = pd.concat([self.STACKER, self.get_dummies(col)], axis=1)
elif dtype == 'int64':
self.STACKER = pd.concat([self.STACKER, self.cut_it(col)], axis=1)

return self.STACKER

def get_dummies(self, name):
return pd.get_dummies(self.df[name], prefix=name)

def cut_it(self, name, bins=5):
s = self.df[name].copy()
return pd.get_dummies(pd.cut(s, bins), prefix=name)

这是一些虚拟数据。我的方法之一是使用 pd.cut in-efforts 对大范围的整数或 float 进行分箱。另一种方法使用 pd.get_dummies 将唯一值转换为列。

df = pd.DataFrame({'integers': np.random.randint(2000, 20000, 30, dtype='int64'),
'categorical': np.random.choice(list('ABCDEFGHIJKLMNOP'), 30)},
columns=['integers', 'categorical'])

trans = DFTransformer()
X = trans.fit_transform(df)
y = np.random.binomial(1, 0.5, 30)
lr = LogisticRegression()
lr.fit(X, y)

X_test = pd.DataFrame({'integers': np.random.randint(2000, 60000, 30, dtype='int64'),
'categorical': np.random.choice(list('ABGIOPXYZ'), 30)},
columns=['integers', 'categorical'])
lr.predict(trans.transform(X_test))

我遇到的问题是,当我去转换“测试”数据(我想对其进行预测的数据)时,转换很可能不会输出完全相同的列,因为不同的分类值(例如:模糊的值可能出现一次,然后再也看不到或听不到)。

例如,上面的代码会产生这个错误:

Traceback (most recent call last):
File "C:/Users/myname/Downloads/SO009949884.py", line 44, in <module>
lr.predict(trans.transform(X_test))
File "C:\python36\lib\site-packages\sklearn\linear_model\base.py", line 324, in predict
scores = self.decision_function(X)
File "C:\python36\lib\site-packages\sklearn\linear_model\base.py", line 305, in decision_function
% (X.shape[1], n_features))
ValueError: X has 14 features per sample; expecting 20

问题:如何确保我的转换方法以相同的方式转换我的测试数据?

我能想到的一个糟糕的解决方案是:转换训练数据、转换测试数据、查看列相交的位置、修改我的转换函数以将输出限制为这些列。或者,为缺失的内容填写空白栏。这是不可扩展的。当然有更好的方法吗?我不想事先知道输出列必须是什么。

我的总体目标是以一致的方式跨训练和测试数据集转换分类变量。我有 150 多列要转换!

最佳答案

我写了一篇博文来解决这个问题。下面是我构建的变压器。

class CategoryGrouper(BaseEstimator, TransformerMixin):  
"""A tranformer for combining low count observations for categorical features.

This transformer will preserve category values that are above a certain
threshold, while bucketing together all the other values. This will fix issues
where new data may have an unobserved category value that the training data
did not have.
"""

def __init__(self, threshold=0.05):
"""Initialize method.

Args:
threshold (float): The threshold to apply the bucketing when
categorical values drop below that threshold.
"""
self.d = defaultdict(list)
self.threshold = threshold

def transform(self, X, **transform_params):
"""Transforms X with new buckets.

Args:
X (obj): The dataset to pass to the transformer.

Returns:
The transformed X with grouped buckets.
"""
X_copy = X.copy()
for col in X_copy.columns:
X_copy[col] = X_copy[col].apply(lambda x: x if x in self.d[col] else 'CategoryGrouperOther')
return X_copy

def fit(self, X, y=None, **fit_params):
"""Fits transformer over X.

Builds a dictionary of lists where the lists are category values of the
column key for preserving, since they meet the threshold.
"""
df_rows = len(X.index)
for col in X.columns:
calc_col = X.groupby(col)[col].agg(lambda x: (len(x) * 1.0) / df_rows)
self.d[col] = calc_col[calc_col >= self.threshold].index.tolist()
return self

基本上,最初的动机来自于我必须处理稀疏类别值,但后来我意识到这可以应用于未知值。在给定阈值的情况下,转换器实质上将稀疏类别值组合在一起,因此由于未知值将继承 0% 的值空间,因此它们将分入 CategoryGrouperOther 组。

这里只是变压器的演示:

# dfs with 100 elements in cat1 and cat2
# note how df_test has elements 'g' and 't' in the respective categories (unknown values)
df_train = pd.DataFrame({'cat1': ['a'] * 20 + ['b'] * 30 + ['c'] * 40 + ['d'] * 3 + ['e'] * 4 + ['f'] * 3,
'cat2': ['z'] * 25 + ['y'] * 25 + ['x'] * 25 + ['w'] * 20 +['v'] * 5})
df_test = pd.DataFrame({'cat1': ['a'] * 10 + ['b'] * 20 + ['c'] * 5 + ['d'] * 50 + ['e'] * 10 + ['g'] * 5,
'cat2': ['z'] * 25 + ['y'] * 55 + ['x'] * 5 + ['w'] * 5 + ['t'] * 10})

catgrouper = CategoryGrouper()
catgrouper.fit(df_train)
df_test_transformed = catgrouper.transform(df_test)

df_test_transformed

cat1 cat2
0 a z
1 a z
2 a z
3 a z
4 a z
5 a z
6 a z
7 a z
8 a z
9 a z
10 b z
11 b z
12 b z
13 b z
14 b z
15 b z
16 b z
17 b z
18 b z
19 b z
20 b z
21 b z
22 b z
23 b z
24 b z
25 b y
26 b y
27 b y
28 b y
29 b y
... ... ...
70 CategoryGrouperOther y
71 CategoryGrouperOther y
72 CategoryGrouperOther y
73 CategoryGrouperOther y
74 CategoryGrouperOther y
75 CategoryGrouperOther y
76 CategoryGrouperOther y
77 CategoryGrouperOther y
78 CategoryGrouperOther y
79 CategoryGrouperOther y
80 CategoryGrouperOther x
81 CategoryGrouperOther x
82 CategoryGrouperOther x
83 CategoryGrouperOther x
84 CategoryGrouperOther x
85 CategoryGrouperOther w
86 CategoryGrouperOther w
87 CategoryGrouperOther w
88 CategoryGrouperOther w
89 CategoryGrouperOther w
90 CategoryGrouperOther CategoryGrouperOther
91 CategoryGrouperOther CategoryGrouperOther
92 CategoryGrouperOther CategoryGrouperOther
93 CategoryGrouperOther CategoryGrouperOther
94 CategoryGrouperOther CategoryGrouperOther
95 CategoryGrouperOther CategoryGrouperOther
96 CategoryGrouperOther CategoryGrouperOther
97 CategoryGrouperOther CategoryGrouperOther
98 CategoryGrouperOther CategoryGrouperOther
99 CategoryGrouperOther CategoryGrouperOther

甚至在我将阈值设置为 0 时也有效(这将专门为“其他”组设置未知值,同时保留所有其他类别值)。不过,我会警告不要将阈值设置为 0,因为您的训练数据集不会有“其他”类别,因此调整阈值以将至少一个值标记为“其他”组:

catgrouper = CategoryGrouper(threshold=0)
catgrouper.fit(df_train)
df_test_transformed = catgrouper.transform(df_test)

df_test_transformed

cat1 cat2
0 a z
1 a z
2 a z
3 a z
4 a z
5 a z
6 a z
7 a z
8 a z
9 a z
10 b z
11 b z
12 b z
13 b z
14 b z
15 b z
16 b z
17 b z
18 b z
19 b z
20 b z
21 b z
22 b z
23 b z
24 b z
25 b y
26 b y
27 b y
28 b y
29 b y
... ... ...
70 d y
71 d y
72 d y
73 d y
74 d y
75 d y
76 d y
77 d y
78 d y
79 d y
80 d x
81 d x
82 d x
83 d x
84 d x
85 e w
86 e w
87 e w
88 e w
89 e w
90 e CategoryGrouperOther
91 e CategoryGrouperOther
92 e CategoryGrouperOther
93 e CategoryGrouperOther
94 e CategoryGrouperOther
95 CategoryGrouperOther CategoryGrouperOther
96 CategoryGrouperOther CategoryGrouperOther
97 CategoryGrouperOther CategoryGrouperOther
98 CategoryGrouperOther CategoryGrouperOther
99 CategoryGrouperOther CategoryGrouperOther

关于python - 创建一个自定义的 sklearn TransformerMixin 来一致地转换分类变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48320396/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com