实施 Pipeline 以确保训练和测试虚拟变量相同的最佳方法是什么?
What is the best way to implement Pipeline to make sure train and test dummy variables are the same?
我正在构建一个自定义的 t运行sformer,它执行几个步骤来预处理数据。首先是它应用了我编写的一组函数,这些函数将采用现有功能并设计新功能。从那里,分类变量将被一次性编码。最后一步是从 DataFrame 中删除不再需要的特征或列。
我使用的数据集是 Kaggle House Prices 数据集。
这里的问题是确保测试集中的分类虚拟变量与训练集相同,因为训练集中某个特征的某些类别可能不在测试集中,因此测试集中该类别不会有虚拟变量。我已经完成研究并 运行 进入这个 solution 并且我正在尝试在我的自定义 t运行sformer class 中实现第一个答案。首先,我不确定这是否是最好的方法。其次,我遇到了下面讨论的错误。
我已经包括了我应用于数据的函数的完整列表,但下面只显示了几个实际函数。
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。当我执行 t运行sformation 时,除了将 t运行sformed 列保存到 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"
我想了解为什么会出现此错误,以及是否有比我现在的做法更好的方法来实施此过程。
以下是我在您的代码中注意到的一些可能有帮助的事情
- 错误是抱怨您要删除的某些列在数据框中不存在。要解决此问题,您可以用
替换代码以删除列
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)
拟合函数仅用于从训练数据推断变换参数。并且仅使用列车数据调用。在您的情况下,您只是在应用函数并删除指定列后推断训练数据的剩余列。您不需要实际应用这些功能。如您所知,每个函数添加了哪些列以及您需要删除哪些列。您只能在列上使用一些设置操作才能找到它。
您还可以简化转换功能,您已经知道要包含哪些列,因此您首先添加缺失的列,而不是仅采用要包含的列而不是删除列
我正在构建一个自定义的 t运行sformer,它执行几个步骤来预处理数据。首先是它应用了我编写的一组函数,这些函数将采用现有功能并设计新功能。从那里,分类变量将被一次性编码。最后一步是从 DataFrame 中删除不再需要的特征或列。
我使用的数据集是 Kaggle House Prices 数据集。
这里的问题是确保测试集中的分类虚拟变量与训练集相同,因为训练集中某个特征的某些类别可能不在测试集中,因此测试集中该类别不会有虚拟变量。我已经完成研究并 运行 进入这个 solution 并且我正在尝试在我的自定义 t运行sformer class 中实现第一个答案。首先,我不确定这是否是最好的方法。其次,我遇到了下面讨论的错误。
我已经包括了我应用于数据的函数的完整列表,但下面只显示了几个实际函数。
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。当我执行 t运行sformation 时,除了将 t运行sformed 列保存到 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"
我想了解为什么会出现此错误,以及是否有比我现在的做法更好的方法来实施此过程。
以下是我在您的代码中注意到的一些可能有帮助的事情
- 错误是抱怨您要删除的某些列在数据框中不存在。要解决此问题,您可以用 替换代码以删除列
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)
拟合函数仅用于从训练数据推断变换参数。并且仅使用列车数据调用。在您的情况下,您只是在应用函数并删除指定列后推断训练数据的剩余列。您不需要实际应用这些功能。如您所知,每个函数添加了哪些列以及您需要删除哪些列。您只能在列上使用一些设置操作才能找到它。
您还可以简化转换功能,您已经知道要包含哪些列,因此您首先添加缺失的列,而不是仅采用要包含的列而不是删除列