Loading data
Load a dataset's actual rows into pandas, polars, or DuckDB, run SQL directly against it, or export to CSV — plus how the API key and row limits work.
Loading a dataset's actual rows (.to_pandas(), .to_polars(), .to_duckdb(),
.sql(), .to_csv()) requires a read-scoped API key — unless the
dataset is currently keyless (ds.keyless), in which case no key is
needed. Create a key from your Aesops account's API keys settings (see
also the API's Authentication page).
client = Client(api_key="Aes_...")
ds = client.load_dataset("kenya-housing-prices")pandas
df = ds.to_pandas()Requires pandas (pip install 'aesops[pandas]').
polars
lf = ds.to_polars()Requires polars (pip install 'aesops[polars]').
DuckDB
to_duckdb() returns an in-memory DuckDB connection with a data view bound
to the dataset. DuckDB's httpfs extension does predicate + projection
pushdown, so only the row-groups your query actually touches are fetched:
con = ds.to_duckdb()
con.sql("SELECT county, avg(price) FROM data GROUP BY county").df()New to DuckDB or DuckDBPyRelation? See the DuckDB primer.
Running SQL directly
ds.sql() skips the intermediate con — same pushdown behavior, reference
the dataset as data. Returns a DuckDBPyRelation; call .df() for pandas
or .pl() for polars:
ds.sql("SELECT county, avg(price) FROM data GROUP BY 1").df()
# anything more specific than a simple limit — offset, filters, ordering —
# also goes through ds.sql() directly
ds.sql("SELECT * FROM data ORDER BY price DESC LIMIT 20").df()CSV export
Client-side conversion — no extra server compute, DuckDB reads the Parquet directly and writes the CSV locally:
ds.to_csv("/tmp/housing.csv")Limiting rows
to_pandas(), to_polars(), and to_csv() all take a limit kwarg. It's
pushed down through read_parquet, so it also cuts what crosses the network
— not just what lands in the DataFrame or file:
sample = ds.to_pandas(limit=100)
ds.to_polars(limit=100)
ds.to_csv("/tmp/sample.csv", limit=100)