[FAQ] omework 5 (2026): Why does `/predict` return 200 OK for `"Paid_Ads"`, `"tiktok"` or a negative count, and how do I reject bad input?

未关闭 适合新手
#524 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

@github-actions 已经在做这个了。

开始于 2026年10月29日。

  • #525 来自 @github-actions —— 未关闭

评估

难度
1/5
预计耗时
1 小时以内
新手友好度
72/100
Issue 类型
文档
描述清晰度
描述清楚
活跃度
活跃

调研方向

阅读 machine-learning-zoomcamp 作业解答中的 FAQ 答案以及链接的 predict.py 上下文。Issue 已经解释了验证行为,并展示了一个单独的请求模型示例。检查说明和示例是否与链接的可运行版本一致。完成标准是 FAQ 清楚地区分已评分作业的行为与实验,并说明哪些无效输入会返回 422。

由索引模型根据 Issue 内容生成。

描述

faq-proposal
Course

machine-learning-zoomcamp

Question

Homework 5 (2026): I sent "lead_source": "Paid_Ads" (capital letters) to the API and got HTTP 200 with a different probability than for "paid_ads". "tiktok", "interaction_count": -3 and an income typo of 7927600 also return 200. Shouldn't the API reject these?

Answer

The course API validates types, not values, and DictVectorizer silently ignores categories it didn't see in training. Your graded answers are unaffected: the homework leads are all valid. In a real service, though, these mistakes go unnoticed.

What happens with the Q3 lead (/predict from the provided predict.py):

change status probability
none 200 0.533
lead_source: "Paid_Ads" 200 0.553
lead_source: "tiktok" 200 0.553
annual_income: 7927600 (×100 typo) 200 0.000
interaction_count: -3 200 0.167
number_of_courses_viewed: 2.5 422 —

Why:

  • DictVectorizer one-hot encodes only the feature=value pairs it saw during fit. "Paid_Ads" and "tiktok" match no column, so the whole lead_source block becomes zeros, and both get the same score.
  • Pydantic checks that annual_income is a float and that interaction_count is an int. Without Field constraints, any float or int passes. Only 2.5 fails, because it isn't a valid int.
  • Income isn't scaled, so a ×100 typo multiplies a −1.2e-5 weight by about 8 million and pushes the probability to 0.

**Fix: validate values in the request model. Read the allowed categories from the model itself so they can't drift:

from typing import Literal, Optional
from pydantic import BaseModel, Field, create_model, field_validator

def vocabulary(feature):
    names = pipeline.steps[0][1].get_feature_names_out()
    return tuple(n.split("=", 1)[1] for n in names
                 if n.startswith(f"{feature}=") and not n.endswith("=NA"))

class Numbers(BaseModel):
    number_of_courses_viewed: Optional[int] = Field(None, ge=0)
    annual_income: Optional[float] = Field(None, ge=0, lt=1_000_000)
    interaction_count: Optional[int] = Field(None, ge=0)
    lead_score: Optional[float] = Field(None, ge=0, le=1)

    @field_validator("lead_source", "industry", "employment_status", "location",
                     mode="before", check_fields=False)
    @classmethod
    def clean(cls, v):  # "Paid_Ads" -> "paid_ads", "North America" -> "north_america"
        if isinstance(v, str):
            return v.strip().lower().replace(" ", "_") or None
        return v

Lead = create_model("Lead", __base__=Numbers, {
    f: (Optional[Literal[vocabulary(f)]], None)
    for f in ["lead_source", "industry", "employment_status", "location"]})

Now "Paid_Ads" scores the same as "paid_ads" (0.533). "tiktok", negative counts, the income typo and lead_score: 4.1 return 422 with a clear message, and missing fields still fall back to the training medians. Add model_config = ConfigDict(extra="forbid") to reject misspelled field names such as leadscore too.

Don't change the provided predict.py for the graded Q4/Q6 runs. Use a separate app for experiments.

Full working version with 23 tests: https://github.com/devotuoma/machine-learning-zoomcamp/tree/hw05-deployment/cohorts/2026/homework/05-deployment/solution

Checklist
  • I have searched existing FAQs and this question is not already answered
  • The answer provides accurate, helpful information
  • I have included any relevant code examples or links
主要语言
Python
星标
8
派生
20
平均合并
7 天 9 小时
30 天内合并 PR
8

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

DataTalksClub/faq 的其他 Issue

查看 DataTalksClub/faq 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。