- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这个问题不是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/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!