> ## Documentation Index
> Fetch the complete documentation index at: https://docs.woodwide.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Prediction

> Supervised classification and regression on a target column.

Prediction models learn to predict a target column from the remaining columns in your dataset. Wood Wide AI automatically detects whether the task is binary classification, multiclass classification, or regression based on the target column's values.

## Training

At training time, you must specify the `label_column` -- the column to be predicted. All other columns (or those specified via `input_columns`) are used as input features.

A portion of the training data is automatically held out for validation. After training, validation metrics are reported on this holdout set:

| Task                               | Metric     | Description                                                  |
| ---------------------------------- | ---------- | ------------------------------------------------------------ |
| Binary / multiclass classification | `accuracy` | Fraction of correct predictions on the holdout set.          |
| Regression                         | `r2`       | R-squared (coefficient of determination) on the holdout set. |

These metrics are available on the model object via `GET /models/{model_id}` in the `current_metrics` field, and on each model version via `GET /models/{model_id}/versions`.

<CodeGroup>
  ```python Python theme={null}
  import os, time, requests

  api_key = os.getenv("WOODWIDE_API_KEY")
  base_url = "https://api.woodwide.ai"
  headers = {"Authorization": f"Bearer {api_key}"}

  # Upload training data
  with open("train.csv", "rb") as f:
      resp = requests.post(
          f"{base_url}/datasets",
          headers=headers,
          files={"file": ("train.csv", f, "text/csv")},
          data={"dataset_name": "customer_churn"},
      )
  dataset_id = resp.json()["dataset"]["id"]

  # Train a prediction model
  resp = requests.post(
      f"{base_url}/models/train",
      headers=headers,
      json={
          "model_name": "churn_predictor",
          "model_type": "prediction",
          "dataset_id": dataset_id,
          "label_column": "churned",
      },
  )
  model_id = resp.json()["model"]["id"]

  # Wait for training
  while True:
      model = requests.get(
          f"{base_url}/models/{model_id}", headers=headers
      ).json()
      if model["status"] == "ready":
          break
      time.sleep(5)

  # Check validation metrics
  print(model["current_metrics"])  # e.g. {"accuracy": 0.92}
  ```

  ```python Python (SDK) theme={null}
  import time
  from pathlib import Path
  from woodwide import WoodWide

  client = WoodWide()

  dataset = client.datasets.create(
      file=Path("train.csv"),
      dataset_name="customer_churn",
      override=True,
  )

  model = client.models.train(
      model_type="prediction",
      label_column="churned",
      dataset_id=dataset.id,
  )
  model_id = model.id

  while True:
      model = client.models.retrieve(model_id)
      if model.status in {"ready", "failed"}:
          break
      time.sleep(5)

  if model.status == "failed":
      raise RuntimeError("Training failed")
  # Validation metrics: GET /models/{model_id} via HTTP (current_metrics)
  ```

  ```javascript JavaScript theme={null}
  const fs = require("fs");
  const FormData = require("form-data");

  const apiKey = process.env.WOODWIDE_API_KEY;
  const baseUrl = "https://api.woodwide.ai";
  const headers = { Authorization: `Bearer ${apiKey}` };

  // Upload training data
  const uploadForm = new FormData();
  uploadForm.append("file", fs.createReadStream("train.csv"), "train.csv");
  uploadForm.append("dataset_name", "customer_churn");

  const uploadResp = await fetch(`${baseUrl}/datasets`, {
    method: "POST",
    headers: { ...headers, ...uploadForm.getHeaders() },
    body: uploadForm,
  });
  const { dataset: { id: datasetId } } = await uploadResp.json();

  // Train a prediction model
  const trainResp = await fetch(`${baseUrl}/models/train`, {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({
      model_name: "churn_predictor",
      model_type: "prediction",
      dataset_id: datasetId,
      label_column: "churned",
    }),
  });
  const { model: { id: modelId } } = await trainResp.json();

  // Wait for training
  let model;
  while (true) {
    const modelResp = await fetch(`${baseUrl}/models/${modelId}`, { headers });
    model = await modelResp.json();
    if (model.status === "ready") break;
    await new Promise((r) => setTimeout(r, 5000));
  }

  // Check validation metrics
  console.log(model.current_metrics);  // e.g. { accuracy: 0.92 }
  ```

  ```bash curl theme={null}
  export WOODWIDE_API_KEY="your_api_key_here"
  export BASE_URL="https://api.woodwide.ai"

  # Upload training data
  DATASET_ID=$(curl -s -X POST "$BASE_URL/datasets" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -F "file=@train.csv" \
    -F "dataset_name=customer_churn" | jq -r '.dataset.id')

  # Train a prediction model
  MODEL_ID=$(curl -s -X POST "$BASE_URL/models/train" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"model_name\": \"churn_predictor\",
      \"model_type\": \"prediction\",
      \"dataset_id\": \"$DATASET_ID\",
      \"label_column\": \"churned\"
    }" | jq -r '.model.id')

  # Wait for training
  while true; do
    STATUS=$(curl -s "$BASE_URL/models/$MODEL_ID" \
      -H "Authorization: Bearer $WOODWIDE_API_KEY" | jq -r '.status')

    if [ "$STATUS" = "ready" ]; then break; fi
    if [ "$STATUS" = "failed" ]; then echo "Training failed."; exit 1; fi

    sleep 5
  done

  # Check validation metrics
  curl -s "$BASE_URL/models/$MODEL_ID" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" | jq '.current_metrics'
  # e.g. { "accuracy": 0.92 }
  ```
</CodeGroup>

## Inference

At inference time, provide a CSV with the same input columns as the training data. The target column need not be present -- if it is, it will be ignored. The model predicts the target column for each row.

<CodeGroup>
  ```python Python theme={null}
  # Run inference on new data
  with open("test.csv", "rb") as f:
      resp = requests.post(
          f"{base_url}/models/{model_id}/infer",
          headers=headers,
          files={"file": ("test.csv", f, "text/csv")},
          data={"output_type": "json"},
      )

  results = resp.json()["data"]
  print(results)
  ```

  ```python Python (SDK) theme={null}
  # Uses client and model_id from the training example above.
  from pathlib import Path

  result = client.models.infer(
      model_id,
      file=Path("test.csv"),
      output_type="json",
  )
  print(result["data"])
  ```

  ```javascript JavaScript theme={null}
  // Run inference on new data
  const form = new FormData();
  form.append("file", fs.createReadStream("test.csv"), "test.csv");
  form.append("output_type", "json");

  const resp = await fetch(`${baseUrl}/models/${modelId}/infer`, {
    method: "POST",
    headers: { ...headers, ...form.getHeaders() },
    body: form,
  });

  const { data: results } = await resp.json();
  console.log(results);
  ```

  ```bash curl theme={null}
  curl -s -X POST "$BASE_URL/models/$MODEL_ID/infer" \
    -H "Authorization: Bearer $WOODWIDE_API_KEY" \
    -F "file=@test.csv" \
    -F "output_type=json" | jq '.data'
  ```
</CodeGroup>

See [Output Formats](/api-reference/inference#prediction) for the full output schema.
