Skip to main content
Thirdwatchthirdwatch
data-analysis

Analyze Federal Contract Awards With Python and USAspending

Load normalized USAspending award exports into pandas, validate identifiers and amounts, group recipients and agencies, and compare recurring snapshots.

Jul 21, 2026 · 2 min read · 258 words
See the scraper →

A useful federal-awards notebook starts with validation, not a chart. Award searches can span long activity periods, descriptions can be missing, and a large amount can dominate every aggregate.

Export results from the USAspending Federal Awards Scraper as JSON or CSV. Keep the Actor input and run date beside the file so the analysis can be reproduced.

Validate before grouping

import pandas as pd

df = pd.read_json("dataset_items.json")
df["award_amount"] = pd.to_numeric(df["award_amount"], errors="coerce")
df["start_date"] = pd.to_datetime(df["start_date"], errors="coerce")
df["end_date"] = pd.to_datetime(df["end_date"], errors="coerce")

key = df["generated_internal_id"].fillna(df["award_id"])
duplicates = df[key.duplicated(keep=False)]
clean = df.loc[~key.duplicated()].copy()

Inspect duplicate rows before dropping them. A true repeated API row is different from two related awards that share a recognizable contract number.

Check missing recipient names, negative amounts, end dates before start dates, and unusually long descriptions. Put failed checks in a review table rather than silently repairing source values.

Summarize recipients and agencies

by_recipient = (
    clean.groupby("recipient_name", dropna=False)
    .agg(
        awards=("award_id", "nunique"),
        total_amount=("award_amount", "sum"),
        median_amount=("award_amount", "median"),
        latest_end=("end_date", "max"),
    )
    .sort_values("total_amount", ascending=False)
)

Pair totals with counts and medians. One outlier award should not be allowed to masquerade as broad market activity. Agency summaries should keep awarding and funding agencies separate because they can represent different roles.

Compare scheduled runs

Join snapshots on generated_internal_id. Record changed amounts, descriptions, and dates as field-level changes. A missing award should trigger verification, not an automatic cancellation label.

Finally, keep usaspending_url in every exception report. Public-source analysis is strongest when a reviewer can move from a surprising number to the official record in one click.

Frequently asked questions

Can award amounts be summed directly?

Only with care. Check for duplicate identifiers, modifications, category scope, and the meaning of the returned amount before presenting totals.

Why retain the source URL in an analysis table?

It lets reviewers inspect unusual values and verify records without reconstructing the search.

Related

Try it yourself

100 free credits, no credit card.

About 30 real searches. Add the MCP to Claude or Cursor in two minutes.