fastai 表格模型 - 如何获得新数据的预测?

Ole*_*dov 6 python tabular fast-ai

我使用的是kaggle房价数据集,它分为:训练和测试

  • 我使用训练集用 fastai 表格构建了一个模型
  • 如何预测测试数据集的值?

我知道这听起来很简单,大多数其他库都会像 model.predict(test) 那样做,但这里的情况并非如此。我搜索过 fastai 论坛以及 SO 和文档。关于这个问题有很多主题,其中大多数要么没有答案,要么是过时的解决方法(因为 fastai2 最近发布,现在简称为 fastai)。

A。model.predict 仅适用于单行,并且循环测试并不是最佳的。它非常慢。

b. model.get_preds 给出您训练的数据的结果

请建议您可以使用受过训练的学习器针对表格数据来预测新的 df 吗?

小智 8

model.get_preds用于对未见过的数据进行批量预测。您只需对这些新数据应用与训练数据相同的转换即可。

dl = model.dls.test_dl(test_data, bs=64) # apply transforms
preds,  _ = model.get_preds(dl=dl) # get prediction
Run Code Online (Sandbox Code Playgroud)

fastai 的论坛非常活跃,您可能会得到库开发人员的回复,因此将来也可以尝试一下。


Ole*_*dov 2

我发现了一个问题。对于未来的读者 - 为什么你不能get_preds为 new df 找到工作?

(在kaggle的房价先进的情况下进行测试)

问题的根源在于绝对的 nan。如果您使用一组猫特征训练模型,例如颜色 = 红色、绿色、蓝色;你的新 df 有颜色:红色、绿色、蓝色、黑色 - 它会抛出错误,因为它不知道如何处理新类(黑色)。更不用说你需要到处都有相同的列,这可能很棘手,因为如果你像我一样使用 fillmissing proc,这很好,它会为 cat 值创建新的列(是否丢失)。所以你需要对猫中的这些 nan 进行三次检查。我真的很想让它从头到尾都与 fastai 一起工作:

训练/测试的列是相同的,只有训练有 1 个额外的目标。此时,某些猫科动物中存在不同的类别。我只是决定将它们结合起来(只是为了使其工作),但它不会引入泄漏吗?

combined = pd.concat([train, test]) # test will have nans at target, but we don't care
cont_cols, cat_cols = cont_cat_split(combined, max_card=50)
combined = combined[cat_cols]
Run Code Online (Sandbox Code Playgroud)

我们在做的时候做了一些调整。

train[cont_cols] = train[cont_cols].astype('float') # if target is not float, there will be an error later
test[cont_cols[:-1]] = test[cont_cols[:-1]].astype('float'); # slice target off (I had mine at the end of cont_cols)
Run Code Online (Sandbox Code Playgroud)

成功进入 Tabular Panda

procs = [Categorify, FillMissing]

to = TabularPandas(combined,
                   procs = procs,
                   cat_names = cat_cols)

train_to_cat = to.items.iloc[:train.shape[0], :] # transformed cat for train
test_to_cat = to.items.iloc[train.shape[0]:, :] # transformed cat for test. Need to separate them
Run Code Online (Sandbox Code Playgroud)

to.items 将为我们提供转换后的猫列。之后,我们需要将所有东西重新组装在一起

train_imp = pd.concat([train_to_cat, train[cont_cols]], 1) # assemble new cat and old cont together
test_imp = pd.concat([test_to_cat, test[cont_cols[:-1]]], 1) # exclude SalePrice

train_imp['SalePrice'] = np.log(train_imp['SalePrice']) # metric for kaggle
Run Code Online (Sandbox Code Playgroud)

之后,我们按照 fastai 教程进行操作。

dep_var = 'SalePrice'
procs = [Categorify, FillMissing, Normalize]
splits = RandomSplitter(valid_pct=0.2)(range_of(train_imp))

to = TabularPandas(train_imp, 
                   procs = procs,
                   cat_names = cat_cols,
                   cont_names = cont_cols[:-1], # we need to exclude target
                   y_names = 'SalePrice',
                   splits=splits)

dls = to.dataloaders(bs=64)

learn = tabular_learner(dls, n_out=1, loss_func=F.mse_loss)
learn.lr_find()

learn.fit_one_cycle(20, slice(1e-2, 1e-1), cbs=[ShowGraphCallback()])
Run Code Online (Sandbox Code Playgroud)

此时,我们有了一个学习器,但仍然无法预测。我们这样做之后我想:

dl = learn.dls.test_dl(test_imp, bs=64)
preds, _ = learn.get_preds(dl=dl) # get prediction
Run Code Online (Sandbox Code Playgroud)

它会起作用(预处理连续值并预测),但不行。它不会填充。所以只需在测试中找到并填写nan:

missing = test_imp.isnull().sum().sort_values(ascending=False).head(12).index.tolist()
for c in missing:
    test_imp[c] = test_imp[c].fillna(test_imp[c].median())
Run Code Online (Sandbox Code Playgroud)

之后我们终于可以预测:

dl = learn.dls.test_dl(test_imp, bs=64)
preds, _ = learn.get_preds(dl=dl) # get prediction

final_preds = np.exp(preds.flatten()).tolist()

sub = pd.read_csv('../input/house-prices-advanced-regression-techniques/sample_submission.csv')
sub.SalePrice = final_preds

filename = 'submission.csv'
sub.to_csv(filename, index=False)
Run Code Online (Sandbox Code Playgroud)

对于冗长的叙述表示歉意,但我对编码相对较新,这个问题很难指出。关于如何解决在线问题的信息很少。简而言之,这是一种痛苦。

不幸的是,这仍然是解决问题的方法。如果测试中任何功能中的类数量不同,它就会崩溃。同样奇怪的是,在对 dls 进行拟合测试时它没有填充。

如果您有任何愿意分享的建议,请告诉我。