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

# Results

> Turn responses and study metadata into analysis-ready tables.

A `Results` object contains interview records and associated study information. Use it to inspect completion, trace answers to inputs, and select data for analysis. `Results.select()` returns a tabular `Dataset`; it does not rerun the study.

One result record holds all answers from one interview, together with its scenario, agent, and model. A survey with five questions therefore normally produces five answer columns per interview, rather than five rows. This is the object returned by `job.run()`; the same selection and export methods also work with retrieved human responses.

## Inspect and compare data

The example below creates four fabricated records so the analysis can run without credentials or model costs. It is a demonstration of data operations, not a research finding.

```python theme={null}
from edsl import Agent, Model, QuestionMultipleChoice, Result, Results, Scenario, Survey

question = QuestionMultipleChoice(
    question_name="clarity", question_text="Is the message clear?",
    question_options=["Clear", "Unclear"],
)
survey = Survey([question])
# Fabricated observations for demonstrating data operations, not research findings.
results = Results(survey=survey, data=[
    Result(agent=Agent(), scenario=Scenario({"record_id": key, "condition": condition}),
           model=Model("test"), iteration=0, answer={"clarity": answer}, survey=survey)
    for key, condition, answer in [
        ("r1", "short", "Unclear"), ("r2", "explicit", "Clear"),
        ("r3", "short", "Clear"), ("r4", "explicit", "Clear"),
    ]
])
table = results.select("scenario.record_id", "scenario.condition", "answer.clarity")
# Display in a notebook: put table on the last line of a cell.
# Display in a script: table.print()
# Convert to pandas when you need DataFrame operations.
frame = table.to_pandas()
counts = frame.groupby(["scenario.condition", "answer.clarity"]).size()
clear = results.filter("clarity == 'Clear'")
table.to_csv("clarity.csv")
```

The counts contain one Clear and one Unclear answer for `short`, and two Clear answers for `explicit`. The filtered Results contains three records. `clarity.csv` retains the record identifier and condition beside each answer.

## Select columns and retain provenance

Use `results.columns` to inspect available columns. The part before the dot tells you where a value came from:

| Column in this example | What it tells you |
| - | - |
| `answer.clarity` | The answer to the question named `clarity`. |
| `scenario.condition` | Which message condition was evaluated. |
| `scenario.record_id` | Which source record the answer belongs to. |
| `model.model` | Which model generated it. |

`agent.*` selects profile information, `prompt.*` selects recorded prompts, and `"answer.*"` selects all answer columns. Keep the fields needed for your comparison beside the answers—for example, the condition when comparing messages and the model when comparing models.

Inspect prompts and raw responses when diagnosing validation failures. Report missing or failed interviews alongside completed observations; a completed process does not guarantee that every planned observation is present.

## Filter, export, and reshape

Filter a Results object before selecting columns when you need to preserve its study context. Use a Dataset or pandas DataFrame for grouping and reshaping. Export to CSV with `results.select(...).to_csv("answers.csv")` or use the [CLI Guide](https://docs.expectedparrot.com/en/latest/cli.md) for bounded previews and file exports.

Use [Dataset](https://docs.expectedparrot.com/en/latest/dataset.md) for tabular transformations. Put record identifiers and treatment labels in scenarios before execution; they remain available in results even if they are not inserted into question text. [Human validation](https://docs.expectedparrot.com/en/latest/research/human_validation.md#match-predictions-to-reviewed-labels) demonstrates matching external labels by record identifier and checking for duplicate matches.

## Human responses and saved work

Human responses can be retrieved through [Humanize](https://docs.expectedparrot.com/en/latest/humanize.md). Keep collection source and study identifiers when comparing human and simulated data. Save full Results objects as well as analysis tables when you need prompts, settings, and cache information later; see [Saving objects](https://docs.expectedparrot.com/en/latest/guides/saving_objects.md).

## Common methods

| Call | Arguments and result |
| - | - |
| `results.columns` | List available column names, including their namespaces. |
| `results.select("answer.clarity", "scenario.condition")` | Return a Dataset of the named columns. Pass each column separately; `"answer.*"` selects all answers. |
| `results.filter("clarity == 'Clear'")` | Return Results containing only interviews matching the expression. Use qualified names when a name occurs in more than one namespace. |
| `results.sort_by("scenario.record_id", reverse=False)` | Return Results sorted by one or more columns; `reverse=True` gives descending order. |
| `results.save("results.ep")` / `Results.load("results.ep")` | Save and restore the complete Results object, including study metadata. |

Using the four fabricated records above:

```python theme={null}
results.filter("clarity == 'Clear'").select(
    "scenario.record_id", "scenario.condition", "answer.clarity"
)
# In a notebook, the last expression displays the three matching rows.
# In a script, append .print() to display the selected table.
```

For export, select the columns you want to share:

```python theme={null}
table = results.select("scenario.record_id", "answer.clarity")
table.to_csv("answers.csv")
# Optional: table.to_pandas() for DataFrame operations.
# Optional: results.select("answer.clarity").to_list() for a Python list.
```

See [Dataset methods](https://docs.expectedparrot.com/en/latest/dataset.md#common-methods) for display, conversion, and further table transformations.

## Derive answers and summarize groups

`mutate()` returns Results with an additional answer column. It does not rerun the model:

```python theme={null}
scored = results.mutate("is_clear = clarity == 'Clear'")
scored.select("scenario.record_id", "answer.is_clear")
# Count combinations without converting to pandas:
results.tally("scenario.condition", "answer.clarity")
```

`results.rename("clarity", "message_clarity")` returns Results with the answer column renamed. `sample(n=2, seed="review")` and `shuffle(seed="review")` return new Results collections; sampling is without replacement by default. `results.bucket_by("scenario.condition")` returns a dictionary mapping group-key tuples to lists of Result records. `results.sql(query)` runs a query over a table named `self`; `remove_prefix=False` retains qualified column names, which need quoting in SQL.

## Inspect individual interviews

Indexing Results or calling `first()` gives a single `Result`:

```python theme={null}
interview = results.first()
interview.get_answer("clarity")
# Equivalent list-oriented access across interviews: results.get_answers("clarity")
interview.q_and_a()
```

| Method | Use |
| - | - |
| `interview.get_question_names()` | List the questions recorded for the interview. |
| `interview.get_question_text("clarity")`, `get_question_type("clarity")`, `get_question_options("clarity")` | Inspect question definitions associated with an answer. |
| `interview.get_value("scenario", "record_id")` | Read a value from a particular namespace. |
| `interview.transcript()` / `results.transcripts()` | Display question-and-answer transcripts for one or several interviews. |
| `interview.score_with_answer_key({"clarity": "Clear"})` | Return per-question correctness scores against an explicit reference key. |
| `interview.score(scoring_function)` | Apply a Python scoring function whose parameter names correspond to fields in the record. |

## Long tables, new inputs, and cache inspection

`results.long(scenario_fields=["record_id", "condition"])` returns a ScenarioList with one row per interview-question pair. `results.q_and_a(include_scenario=True)` returns question text, answers, comments, and scenario fields for reading or further analysis. `results.agent_answers_by_question()` returns a dictionary grouped by agent.

To use responses as inputs to another study, select the fields first: `results.select("scenario.record_id", "answer.clarity").to_scenario_list()`. Use `to_agent_list()` instead when the selected fields should become respondent traits. See [table exports](https://docs.expectedparrot.com/en/latest/dataset.md#export-and-convert-tables) for files and DataFrames.

Inspect `results.select("cache_used.*")` for reuse indicators and `results.cache` for retained cache entries. `results.relevant_cache(cache)` returns the entries in a supplied Cache referenced by these Results. `results.show_exceptions()` displays recorded interview exceptions, when available; `traceback=True` includes traceback details. A saved Results object may not include all execution history.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.