【问题标题】:Patsy: New levels in categorical fields in test dataPatsy:测试数据中分类字段的新级别
【发布时间】:2017-07-14 12:10:14
【问题描述】:

我正在尝试使用 Patsy(带有 sklearn、pandas)来创建一个简单的回归模型。 R 风格的公式创建是一个主要的吸引力。

我的数据包含一个名为“ship_city”的字段,其中可以包含印度的任何城市。由于我将数据划分为训练集和测试集,因此有几个城市只出现在其中一个集中。下面给出一个代码sn-p:

df_train_Y, df_train_X = dmatrices(formula, data=df_train, return_type='dataframe')
df_train_Y_design_info, df_train_X_design_info = df_train_Y.design_info, df_train_X.design_info
df_test_Y, df_test_X = build_design_matrices([df_train_Y_design_info.builder, df_train_X_design_info.builder], df_test, return_type='dataframe')

最后一行抛出如下错误:

patsy.PatsyError:将数据转换为分类时出错:观察 值为 'Kolkata' 的值与任何预期水平都不匹配

我相信这是一个非常常见的用例,其中训练数据不会包含所有类别字段的所有级别。 Sklearn 的 DictVectorizer 可以很好地处理这个问题。

有什么方法可以让 Patsy 完成这项工作?

【问题讨论】:

    标签: python scikit-learn patsy


    【解决方案1】:

    问题当然是,如果你只是给 patsy 一个原始的值列表,它就无法知道还有其他可能发生的值。您必须以某种方式告诉它完整的可能值集是什么。

    一种方法是使用levels= 参数到C(...),例如:

    # If you have a data frame with all the data before splitting:
    all_cities = sorted(df_all["Cities"].unique())
    # Alternative approach:
    all_cities = sorted(set(df_train["Cities"]).union(set(df_test["Cities"])))
    
    dmatrices("y ~ C(Cities, levels=all_cities)", data=df_train)
    

    如果您使用 pandas 的默认 categorical support,另一个选项是 record the set of possible values when you set up your data frame;如果 patsy 检测到您传递给它的对象是 pandas 分类对象,那么它会自动使用 pandas 类别属性,而不是试图通过查看数据来猜测可能的类别。

    【讨论】:

    • 我很欣赏这个答案,但它遇到了 timctran 的答案所面临的同样问题。在投入生产之前,我们不会知道我们将要遇到的所有可能的关卡。印度的城镇数量太大而无法包含在模型中。首先,这些地方没有详尽的清单。不管你信不信,新的不断涌现。 cities 就是这样一个例子。
    • 好吧,在这种情况下,您甚至希望发生什么? patsy 是否输出了一个与原始矩阵相比增加了新列的矩阵?你会用它们做什么?
    • 正如我在问题中提到的,我觉得 sklearn 的 Dictvectoriser 处理得很好。它不会引发错误。它只是对模型说“这是一个与我以前见过的任何城市价值都不匹配的记录”。它只是将所有现有列标记为 0。我只是认为 Patsy 是一个成熟的库,也可以处理这个非常常见的用例。但显然不是。
    • 啊,这是一个有趣的策略。信不信由你,你是第一个提出这个要求的人——至少在我看到它的地方:-)。 (即使在这里也遇到了一个 1.5 年前的问题......)......但是,对于任何类型的线性模型,返回全零都会给出非常不正确的结果,比如 patsy 的设计目的,所以我不确定这是个好主意。让我们在这里继续讨论:github.com/pydata/patsy/issues/110
    【解决方案2】:

    我遇到了类似的问题,我在拆分数据之前构建了设计矩阵。

    df_Y, df_X = dmatrices(formula, data=df, return_type='dataframe')
    df_train_X, df_test_X, df_train_Y, df_test_Y = \
        train_test_split(df_X, df_Y, test_size=test_size)
    

    然后作为应用拟合的示例:

    model = smf.OLS(df_train_Y, df_train_X)
    model2 = model.fit()
    predicted = model2.predict(df_test_X)
    

    从技术上讲,我还没有构建测试用例,但自从实施上述方法后,我再也没有遇到过Error converting data to categorical 错误。

    【讨论】:

    • 是的,这是一种可能的解决方法。但这种方法的问题在于,现在从测试集泄漏到训练集。理想情况下,在训练时,我们不应使用测试数据中尚未包含在训练数据中的任何信息。通过这种方式,我们在测试中模拟生产中实际发生的情况。以我上面的问题为例,如果有些城市我只会在生产中知道,那么将这些城市作为用于训练模型的数据中的列是不正确的(实际上甚至不可能)。我希望这很清楚。
    • 我明白你的担忧。话虽如此,我的理解是,我的回答不会泄露信息,因为它会在培训时提供任何额外的信息。它只是使模型与数据集中的其他项目兼容。在 R 中,这相当于在不更改数据的情况下调整级别。如果您的模型中没有可用城市的发生率很高,那么也许将城市集中在一起形成一个更具包容性的模型将是可行的方法;但这倾向于模型设计,与您的测试和训练集兼容性问题分开。
    • 例如,假设我们有一个关于三个城市 A、B、C 的数据。在生产中会有第四个城市 D 和第五个城市 E。所以在这种情况下,方法可能是对 A、B、C 进行虚拟编码,因此不是 A、B 或 C 是​​任何其他城市。但是,我们不能指望该模型以最佳方式工作,因为它将所有看不见的城市聚集在一起。相反,我们可以设计变量,例如 city_population(数值或分类:sm、med、lg)、city_density 等,并将每个城市映射到其特征。然后可以将该模型应用于不在原始数据集中的城市。
    猜你喜欢
    • 2018-11-19
    • 2017-11-17
    • 2018-02-21
    • 1970-01-01
    • 2014-07-07
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多