实施 Pipeline 以确保训练和测试虚拟变量相同的最佳方法是啥?
Posted
技术标签:
【中文标题】实施 Pipeline 以确保训练和测试虚拟变量相同的最佳方法是啥?【英文标题】:What is the best way to implement Pipeline to make sure train and test dummy variables are the same?实施 Pipeline 以确保训练和测试虚拟变量相同的最佳方法是什么? 【发布时间】:2020-01-05 19:17:32 【问题描述】:我正在构建一个自定义转换器,它执行几个步骤来预处理数据。首先是它应用了我编写的一组功能,这些功能将采用现有功能并设计新功能。从那里,分类变量将被一次性编码。最后一步是从 DataFrame 中删除不再需要的特征或列。
我使用的数据集是 Kaggle House Prices 数据集。
这里的问题是确保测试集中的分类虚拟变量与训练集中相同,因为训练集中某个特征的某些类别可能不在测试集中,因此测试集不会” t 有该类别的虚拟变量。我已经完成了研究,遇到了这个solution,我正在尝试在我的自定义转换器类中实现第一个答案。首先,我不确定这是否是最好的方法。其次,我收到了一个下面提到的错误。
我已经包含了我应用于数据的函数的完整列表,但仅在下面显示了几个实际函数。
class HouseFeatureTransformer(BaseEstimator, TransformerMixin):
def __init__(self, funcs, func_cols, drop_cols, drop_first=True):
self.funcs = funcs
self.func_cols = func_cols
self.train_cols = None
self.drop_cols = drop_cols
self.drop_first = drop_first
def fit(self, X, y=None):
X_trans = self.apply_funcs(X)
X_trans.drop(columns=self.drop_cols, inplace=True)
#save training_columns to compare to columns of any later seen dataset
self.train_cols = X_trans.columns
return self
def transform(self, X, y=None):
X_test = self.apply_funcs(X)
X_test.drop(columns=self.drop_cols, inplace=True)
test_cols = X_test.columns
#ensure that all columns in the training set are present in the test set
#set should be empty for first fit_transform
missing_cols = set(self.train_cols) - set(test_cols)
for col in missing_cols:
X_test[col] = 0
#reduce columns in test set to only what was in the training set
X_test = X_test[self.train_cols]
return X_test.values
def apply_funcs(self, X):
#apply each function to respective column
for func, func_col in zip(self.funcs, self.func_cols):
X[func_col] = X.apply(func, axis=1)
#one hot encode categorical variables
X = pd.get_dummies(X, drop_first=self.drop_first)
return X
#functions to apply
funcs = [sold_age, yrs_remod, lot_shape, land_slope, rfmat, bsmt_bath, baths,
other_rooms, fence_qual, newer_garage]
#feature names
func_cols = ['sold_age', 'yr_since_remod', 'LotShape', 'LandSlope', 'RoofMatl', 'BsmtBaths', 'Baths', \
'OtherRmsAbvGr', 'Fence', 'newer_garage']
#features to drop
to_drop = ['Alley', 'Utilities', 'Condition2', 'HouseStyle', 'LowQualFinSF', 'EnclosedPorch', \
'3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC', 'MiscFeature', 'MiscVal', \
'YearBuilt', 'YrSold', 'YearRemodAdd', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath', \
'TotRmsAbvGrd', 'GarageYrBlt', '1stFlrSF', '2ndFlrSF', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'ExterQual', \
'ExterCond', 'BsmtQual', 'BsmtCond', 'KitchenQual', 'FireplaceQu', 'GarageQual', 'GarageCond', 'BsmtFinType2', \
'Exterior1st', 'Exterior2nd', 'GarageCars', 'Functional', 'SaleType', 'SaleCondition']
#functions to transform data
def sold_age(row):
'''calculates the age of the house when it was sold'''
return row['YrSold'] - row['YearBuilt']
def yrs_remod(row):
'''calculates the years since house was remodeled'''
yr_blt = row['YearBuilt']
yr_remodeled = row['YearRemodAdd']
yr_sold = row['YrSold']
if yr_blt == yr_remodeled:
return 0
else:
return yr_sold - yr_remodeled
def lot_shape(row):
'''consolidates all irregular categories into one'''
if row['LotShape'] == 'Reg':
return 'Reg'
else:
return 'Irreg'
在拟合期间,我应用函数,虚拟化分类,删除不需要的列,然后将列保存到 self.train_cols。当我进行转换时,除了将转换后的列保存到 test_cols 之外,我执行相同的步骤。我将这些列与拟合中获得的列进行比较,并从训练中的测试集中添加任何缺失的列,如我链接的答案所示。我得到的错误如下:
KeyError: "['Alley' 'Utilities' 'Condition2' 'HouseStyle' 'PoolQC' 'MiscFeature'\n 'ExterQual' 'ExterCond' 'BsmtQual' 'BsmtCond' 'KitchenQual' 'FireplaceQu'\n 'GarageQual' 'GarageCond' 'BsmtFinType2' 'Exterior1st' 'Exterior2nd'\n 'Functional' 'SaleType' 'SaleCondition'] not found in axis"
我正在尝试了解为什么会出现此错误,以及是否有比我执行此过程更好的方法来实现此过程。
【问题讨论】:
你能不能也展示一个数据和函数的最小例子,func_cols,drop_cols?没有这些信息,您的问题是不完整的 谢谢。我已经编辑了帖子并包含了其他信息。 【参考方案1】:以下是我在您的代码中记下的几件事,可能会有所帮助
错误是抱怨您尝试删除的某些列在数据框中不存在。要解决此问题,您可以替换代码以删除列data = np.random.rand(50,4)
df = pd.DataFrame(data, columns=["a","b","c","d"])
drop_columns=['b', 'c', 'e', 'f']
## code to drop columns
columns = df.columns
drop_columns = set(columns) & set(drop_columns)
df.drop(columns=drop_columns, inplace=True)
Fit 函数仅用于从训练数据推断转换参数。并且仅使用训练数据调用。在您的情况下,您只是在应用函数并删除指定的列之后推断训练数据的剩余列。您不需要实际应用这些功能。如您所知,每个函数添加了哪些列以及您需要删除哪些列。您只能使用列上的一些集合操作来找到它。
您还可以简化转换函数,因为您已经知道要包含哪些列,因此您首先添加缺少的列,而不是只取要包含的列而不是删除列
【讨论】:
谢谢你,开发者。关于您的第二个要点,我将函数包括在内,然后对 cat 变量进行虚拟化。在 CV 期间,我不知道某个变量的哪些类别将包含在训练集中,因此我试图在拟合期间保存那些虚拟猫变量,以确保它们包含在转换中,即之后的任何转换数据集合身。在拟合期间保存虚拟变量以应用于转换是否有意义? 我在上一条评论中的问题仍然存在,但我能够弄清楚我在删除列时遇到错误,因为我试图在模拟变量后删除列所以猫可变列以“_cat_type”为后缀,因此没有要删除的原始列。 是的,在拟合期间保存那些虚拟猫变量是完全可以的,因为您想在预测期间使用相同的值进行转换以上是关于实施 Pipeline 以确保训练和测试虚拟变量相同的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 make_pipeline() 标准化训练和测试数据集
如何使用 scikit learn 确保测试集和训练集具有相同的功能?
如何使用 GridSearchCV 和 sklearn Pipeline 用训练数据的估算值估算测试数据