Polars extension for general data science use cases
Polars extension for general data science use cases
Polars for Data Science
Discord | Documentation | User Guide | Want to Contribute?
pip install polars-ds
PDS is a modern data science package that
It stands on the shoulders of the great Polars dataframe. You can see examples. Here are some highlights!
…E.g. running a quick linear regression and see the predictions and residues:
df.select(pds.lin_reg(pl.col("x1"), pl.col("x2"), target=pl.col("y"), add_bias=False, return_pred=True))
shape: (10_000, 1)
┌───────────────────────┐
│ lr_pred │
│ --- │
│ struct[2] │
╞═══════════════════════╡
│ {-0.3121,0.392769} │
│ {-0.459507,-0.048989} │
│ {-0.469473,-0.215709} │
│ {-0.243764,-0.707016} │
│ {-0.511278,-0.785299} │
│ … │
└───────────────────────┘Generating polynomial features and display a statsmodels-like regression summary:
…Other available simple models (non-persistent):
Various string distances:
df.select( # Column "word", compared to string in pl.lit(). It also supports column vs column comparison
pds.str_leven("word", pl.lit("asasasa"), return_sim=True).alias("Levenshtein"),
pds.str_osa("word", pl.lit("apples"), return_sim=True).alias("Optimal String Alignment"),
pds.str_jw("word", pl.lit("apples")).alias("Jaro-Winkler"),
)Array, list distances:
df = pl.DataFrame({
"x": [[1,2,3], [4,5,6]]
, "y": [[0.5, 0.2, 0.3], [4.0, 5.0, 6.1]]
})
df.select(
x = pl.col('x').cast(pl.Array(inner=pl.Float64, shape=3))
, y = pl.col('y').cast(pl.Array(inner=pl.Float64, shape=3))
).lazy().select(
pds.arr_sql2_dist('x', 'y')
).collect()
shape: (2, 1)
┌───────┐
│ x │
│ --- │
│ f64 │
╞═══════╡
│ 10.78 │
│ 0.01 │
└───────┘Replace arr_sql2_dist with list_sql2_dist. Note: sql2 stands for squared l2 distance, which is the same as squared euclidean distance.
……See SKLEARN_COMPATIBILITY for more details.
…Since Polars >=1.34 supports collect_batches(), you can also use this to perform batched machine learning
for df_batch in pipe.transform(df, return_lazy=True).collect_batches():
X_batch, y_batch = your_function_to_turn_df_batch_into_model_inputs(df_batch)
ml_model.update(X_batch, y_batch)See pipeline examples for more details and caveats.
Get all neighbors within radius r, call them best friends, and count the number. Due to limitations, this currently doesn't preserve the index, and is not fast when k or dimension of data is large.
…Under some mild assumptions, (e.g. columns implement to_numpy()), PDS works with other eager dataframes. For example, with Pandas:
from polars_ds.compat import compat as pds2
df_pd["linear_regression_result"] = pds2.lin_reg(
df_pd["x1"], df_pd["x2"], df_pd["x3"],
target = df_pd["y"],
return_pred = True
)
df_pdThe magic here is the compat module and the fact that most eager dataframes implement the array protocal.
Other common numerical functions such as: pds.convolve, pds.query_r2, pds.principal_components, etc. See our docs for more information.
import polars_ds as pdsTo make full use of the Diagnosis module, do
pip install "polars_ds[plot]"Feel free to take a look at our benchmark notebook!
Generally speaking, the more expressions you want to evaluate simultaneously, the faster Polars + PDS will be than Pandas + (SciPy / Sklearn / NumPy). The more CPU cores you have on your machine, the bigger the time difference will be in favor of Polars + PDS.
This library will only depend on python Polars (for most of its core) and will try to be as stable as possible for polars>=1.4.0. Exceptions will be made when Polars's update forces changes in the plugins. However, Polars updates quickly and older versions may not be tested. Currently, it is actively tested for Polars>=1.33.
This package is also not tested with Polars streaming mode and is not designed to work with data so big that has to be streamed. This concerns plugin expressions like pds.lin_reg, etc, which won't work with streaming. By the same token, Polars large index version is not supported at this point, and I welcome any 3rd packaging. However, I will try to support some expressions with the streaming engine, as they may be important.
The guide here is not specific to LTS CPU, and can be used generally.
The best advice for LTS CPU is that you should compile the package yourself. First clone the repo and make sure Rust is installed on the system. Create a python virtual environment and install maturin in it. Next set the RUSTFLAG environment variable. The official polars-lts-cpu features are the following:
RUSTFLAGS=-C target-feature=+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt,+cmpxchg16bIf you simply want to compile from source, you may set target cpu to native, which autodetects CPU features.
RUSTFLAGS=-C target-cpu=nativeIf you are compiling for LTS CPU, then in pyproject.toml, update the polars dependency to polars-lts-cpu:
polars >= 1.4.0 # polars-lts-cpu >= 1.4.0Lastly, run
maturin develop --releaseIf you want to test the build locally, you may run
# pip install -r requirements-test.txt
pytest tests/test_*If you see this error in pytest, it means setuptools is not installed and you may ignore it. It is just a legacy python builtin package.
tests/test_many.py::test_xi_corr - ModuleNotFoundError: No module named 'pkg_resources'You can then publish it to your private PYPI server, or just use it locally.
Since this project is mostly maintained by a single person, and a single person cannot be fluent with all topics in scientific programming, some of the code in this package is guided by AI and reviewed by me. I will not accept vibe-coded functions. For AI-generated PRs, see contributing.md. Once again, please understand that I have limited attention and if you submit an AI PR with thousands of lines of code, I may not keep up and decide not to include a large portion of the code due to maintenance reasons.
No open issues yet, or sync has not completed.