Ibis sneak peek: writing to files

blog
io
new feature
sneak peek
Author

Kae Suarez

Published

March 9, 2023

Ibis 5.0 is coming soon and will offer new functionality and fixes to users. To enhance clarity around this process, we’re sharing a sneak peek into what we’re working on.

In Ibis 4.0, we added the ability to read CSVs and Parquet via the Ibis interface. We felt this was important because, well, the ability to read files is simply necessary, be it on a local scale, legacy data, data not yet in a database, and so on. However, for a user, the natural next question was “can I go ahead and write when I’m done?” The answer was no. We didn’t like that, especially since we do care about file-based use cases.

So, we’ve gone ahead and fixed that for Ibis 5.0.

Files in, Files out

Before we can write a file, we need data — so let’s read in a file, to start this off:

import ibis

ibis.options.interactive = True

t = ibis.read_csv(
    "https://storage.googleapis.com/ibis-examples/data/penguins.csv.gz"
)
t
┏━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┓
┃ species  island     bill_length_mm  bill_depth_mm  flipper_length_mm  body_mass_g  sex     year  ┃
┡━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━┩
│ stringstringfloat64float64int64int64stringint64 │
├─────────┼───────────┼────────────────┼───────────────┼───────────────────┼─────────────┼────────┼───────┤
│ Adelie Torgersen39.118.71813750male  2007 │
│ Adelie Torgersen39.517.41863800female2007 │
│ Adelie Torgersen40.318.01953250female2007 │
│ Adelie TorgersennannanNULLNULLNULL2007 │
│ Adelie Torgersen36.719.31933450female2007 │
│ Adelie Torgersen39.320.61903650male  2007 │
│ Adelie Torgersen38.917.81813625female2007 │
│ Adelie Torgersen39.219.61954675male  2007 │
│ Adelie Torgersen34.118.11933475NULL2007 │
│ Adelie Torgersen42.020.21904250NULL2007 │
│  │
└─────────┴───────────┴────────────────┴───────────────┴───────────────────┴─────────────┴────────┴───────┘

Of course, we could just write out, but let’s do an operation first — how about using selectors, which you can read more about here? Self-promotion aside, here’s an operation:

from ibis import _
import ibis.selectors as s

expr = (
    t.group_by("species")
     .mutate(s.across(s.numeric() & ~s.c("year"), (_ - _.mean()) / _.std()))
)
expr
┏━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━┓
┃ species  island     bill_length_mm  bill_depth_mm  flipper_length_mm  body_mass_g  sex     year  ┃
┡━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━┩
│ stringstringfloat64float64float64float64stringint64 │
├─────────┼───────────┼────────────────┼───────────────┼───────────────────┼─────────────┼────────┼───────┤
│ Adelie Biscoe   -1.423513-0.3668740.3129250.053074female2009 │
│ Adelie Torgersen0.9794260.1262831.8421040.380180male  2009 │
│ Adelie Torgersen1.542615-0.6134530.9245962.179266male  2008 │
│ Adelie Biscoe   0.641513-0.366874-0.451665-1.091799female2007 │
│ Adelie Biscoe   -0.2220431.3591770.0070890.434698male  2009 │
│ Adelie Torgersen1.3924321.9345271.0775141.743124male  2007 │
│ Adelie Torgersen1.1296100.8660191.2304321.634089male  2008 │
│ Adelie Dream    -0.7476860.1262830.465843-0.437586female2009 │
│ Adelie Dream    -0.860324-0.284681-1.216254-1.200835female2007 │
│ Adelie Dream    0.7541510.0440900.7716780.434698male  2007 │
│  │
└─────────┴───────────┴────────────────┴───────────────┴───────────────────┴─────────────┴────────┴───────┘

Now, finally, time to do the exciting part:

expr.to_parquet("normalized.parquet")

Like many things in Ibis, this is as simple and plain-looking as it is important. Being able to create files from Ibis instead of redirecting into other libraries first enables operation at larger scales and fewer steps. Where desired, you can address a backend directly to use its native export functionality — we want to make sure you have the flexibility to use Ibis or the backend as you see fit.

Wrapping Up

Ibis is an interface tool for analytical engines that can reach scales far beyond a laptop. Files are important to Ibis because:

  • Ibis also supports local execution, where files are the standard unit of data — we want to support all our users.
  • Files are useful for moving between platforms, and long-term storage that isn’t tied to a particular backend.
  • Files can move more easily between our backends than database files, so we think this adds some convenience for the multi-backend use case.

We’re excited to release this functionality in Ibis 5.0.

Interested in Ibis? Docs are available on this very website, at:

and the repo is always at:

Please feel free to reach out on GitHub!

Back to top