bandas — pandas-compatible DataFrames, at full speed ⚡
bandas is a pandas-compatible DataFrame library (same API names:
DataFrame, Series, read_csv, concat, merge, …) with a faster
execution engine — plus a complete data platform for databases, time series,
feature preprocessing, machine learning, deep learning and visualization.
Built for developers, data analysts, data scientists and ML engineers.
Why bandas?
- Pure columnar NumPy storage — no BlockManager overhead, no per-op index alignment.
- Numeric fast paths —
sum/mean/min/maxstraight through NumPy,bincount-powered groupby. - Optional Numba + PyArrow acceleration — compiled groupby kernels, 3–5x faster CSV reads.
- Real SQL built in —
df.sql("SELECT …")with zero extra dependencies (embedded SQLite), plus a unifiedDatabaseconnector for SQLite / DuckDB / Postgres / MySQL / SQLAlchemy. - ML/DL ready —
train_test_split,KFold, metrics,StandardScaler,OneHotEncoder,to_torch,to_tensorflow, dataset loaders. - Advanced analytics —
rolling/expanding/ewm,shift/diff/pct_change,pivot_table/melt/crosstab,str/dtaccessors, andLazyFramefor out-of-core files.
Install
One command installs everything (speed + databases + ML + plotting + Excel):
pip install bandas-df
From source:
git clone https://github.com/salim-studio/bandas.git
cd bandas
pip install -e .
Deep-learning frameworks only (torch and tensorflow are gigabytes in size
and have no wheels for the newest Python versions):
pip install "bandas-df[dl]"
Quickstart
import bandas as bd
df = bd.DataFrame({"a": [1, 2, 3], "b": [4.0, 5.0, 6.0]})
print(df.head())
print(df["a"].sum())
df2 = bd.read_csv("data.csv") # uses PyArrow when available
g = df2.groupby("city")["price"].mean()
print(g.to_pandas())
# Full pandas interop whenever you need it
pdf = df.to_pandas()
df3 = bd.from_pandas(pdf)
On 500k rows bandas is faster than pandas across the board
(sum ~1.9x, mean ~2.6x, groupby ~1.4x — see bench/bench.py).
Databases / SQL
# Zero-setup SQL — always works (embedded SQLite)
top = df.sql("SELECT city, AVG(price) AS m FROM df GROUP BY city ORDER BY m DESC")
# Query across several frames
from bandas import sql_query
out = sql_query("SELECT * FROM a JOIN b ON a.k = b.k WHERE a.v > 10", {"a": a, "b": b})
# Unified connector
from bandas.sql import Database
db = Database.sqlite("app.db") # or ":memory:"
# db = Database.duckdb("data.duckdb") # needs duckdb
# db = Database.postgres(user=..., password=..., host=..., db=...)
db.write(df, "sales")
print(db.query("SELECT COUNT(*) AS n FROM sales").to_pandas())
print(db.tables())
# pandas-style API
df.to_sql("sales", "sqlite:///app.db")
df2 = bd.read_sql("SELECT * FROM sales", "sqlite:///app.db")
Time series & windows
s = df["price"]
s.rolling(7).mean() # moving average
s.expanding().sum()
s.ewm(span=10).mean()
s.shift(1); s.diff(); s.pct_change(); s.cumsum()
df.rolling(30).mean(); df.ewm(alpha=0.3).mean()
bd.to_datetime(["2024-01-01", "2024-02-01"])
bd.date_range("2024-01-01", periods=12, freq="ME")
df["d"].dt.year / .month / .day / .dayofweek
Strings, categories & reshaping
df["name"].str.lower().str.strip().str.contains("ali")
df["name"].str.replace("a", "@").str.split(" ", expand=True)
bd.get_dummies(df, columns=["city"])
bd.melt(df, id_vars=["city"])
bd.pivot_table(df, values="price", index="city", columns="year", aggfunc="mean")
bd.crosstab(df["city"], df["year"])
bd.cut(df["age"], bins=[0, 18, 60, 100])
bd.qcut(df["price"], 4)
Preprocessing
bd.SimpleImputer(strategy="mean").fit_transform(df)
bd.StandardScaler().fit_transform(df)
bd.MinMaxScaler().fit_transform(df)
bd.RobustScaler().fit_transform(df)
bd.LabelEncoder().fit_transform(df["city"])
bd.OneHotEncoder(columns=["city"]).fit_transform(df)
Machine learning
X_train, X_test, y_train, y_test = bd.train_test_split(X, y, test_size=0.2, random_state=0)
list(bd.KFold(n_splits=5).split(X))
bd.accuracy_score(y, pred); bd.f1_score(y, pred)
bd.mean_squared_error(y, pred); bd.r2_score(y, pred)
# Drop straight into scikit-learn
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier().fit(X_train_numpy, y_train_numpy)
Deep learning
X_t, y_t = df.to_torch(target="label") # torch.Tensor
loader = bd.dl.torch_dataset(df, target="label", batch_size=64)
ds = bd.dl.tf_dataset(df, target="label") # tf.data.Dataset
Large files (lazy / out-of-core)
lf = bd.read_csv_chunked("big.csv", chunksize=100_000)
out = lf.filter(lambda d: d[d["x"] > 0]).select(["x", "y"]).collect()
print(lf.sum("x"), lf.mean("x"), lf.count())
Quick plotting
df.plot(kind="line", x="date", y="price")
df.plot(kind="bar", x="city", y="sales")
df["price"].hist(bins=50)
bd.viz.scatter(df, "a", "b"); bd.viz.heatmap_corr(df)
Full IO coverage
read_csv / read_parquet / read_json / read_excel / read_html /
read_feather / read_orc / read_sql +
to_csv / to_parquet / to_json / to_excel / to_sql —
all with pandas-compatible signatures.
Project layout
bandas/
__init__.py # public API + concat/merge/options/show_versions
series.py # Series + str/dt + rolling/ewm + cum*/shift/diff
dataframe.py # DataFrame + SQL + stats + reshape + viz + torch
groupby.py # fast GroupBy + std/var/median/first/last/nunique
io.py # every file reader + chunked
sql.py # sql_query + read_sql/to_sql + unified Database
reshape.py # get_dummies/melt/pivot/crosstab/cut/qcut
window.py # Rolling/Expanding/EWM
strings.py # Series.str
datetimes.py # Series.dt + to_datetime/date_range
preprocessing.py # Imputer/Scaler/Encoder
ml.py # split/CV/metrics/sklearn bridge
dl.py # torch/tensorflow bridges
stats.py # corr/cov/outliers/summary
lazy.py # out-of-core LazyFrame
viz.py # quick charts
ops.py / utils.py
assets/ # logo + banner
tests/ # 20 tests
bench/bench.py # bandas vs pandas benchmark
Test & benchmark
pytest -q
python bench/bench.py
python -c "import bandas; bandas.show_versions()"
Changelog
See CHANGELOG.md.
License
MIT — see LICENSE.
Metadata
Release files for bandas-df 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| bandas_df-0.4.1.tar.gz | 43.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bandas_df-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 86.3 kB
Release files / bandas_df-0.4.1.tar.gz
| Download URL | bandas_df-0.4.1.tar.gz |
|---|---|
| Size | 43.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f779522aa04394fba964ab6191d55264e4ca734693c193f4af42052341bc1eb4
|
|
BLAKE2b-256 checksum How to use checksums |
c76e0d8b5d10c65b13212014db2c16dc3f310222ec36a639166be5e805ef3fcc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / bandas_df-0.4.1-py3-none-any.whl
| Download URL | bandas_df-0.4.1-py3-none-any.whl |
|---|---|
| Size | 42.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5cb3aca5f3235580a0e851fbde09b52e6748ce22430e3b89643f54ca4a3b0523
|
|
BLAKE2b-256 checksum How to use checksums |
7ca848f16ce409e481422a36810405b203de7d5f57cf86be041cafe35c6aa965
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for bandas-df 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.