<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy" -->

---
title: Fluent, not native: agents translating pandas to Polars
description: Polars ran an experiment having Claude Opus 4.8 translate pandas code to Polars in one-shot sessions across 33 test cases (PDS-H benchmark queries, EDA...
canonical: https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Fluent, not native: agents translating pandas to Polars | daily.dev
og:description: Polars ran an experiment having Claude Opus 4.8 translate pandas code to Polars in one-shot sessions across 33 test cases (PDS-H benchmark queries, EDA...
og:url: https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy
og:image: https://api.daily.dev/og/posts/hviIhfofy.png
og:image:alt: Fluent, not native: agents translating pandas to Polars
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Fluent, not native: agents translating pandas to Polars

**[Polars Blog](https://daily.dev/sources/polars)** · 16 min read · 0 upvotes · 0 comments

## Summary

Polars ran an experiment having Claude Opus 4.8 translate pandas code to Polars in one-shot sessions across 33 test cases (PDS-H benchmark queries, EDA notebooks, ETL notebooks). 31 of 33 translations ran correctly with matching output, and most code was idiomatic. Two structural 'accent' patterns persisted: translating pandas' aggregate-then-join-back structure instead of using Polars' .over() window function, and extracting scalars mid-pipeline with .item() instead of letting aggregations broadcast inside filter(). A packaged 'skill' (distributed as a Claude Code plugin, also usable with Cursor, Codex, and Copilot) nudges models toward idiomatic patterns, reducing join-back cases from 3 to 1 and eliminating the mid-pipeline .item() case, though the aggregation-shorthand stylistic tell only dropped from 48 to 40 occurrences. The same skill had a much larger effect on the older Sonnet 4.6 model, cutting wrong-pattern instances 71% by fixing spelling-level tells like list-wrapped arguments and map_elements fallbacks.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://pola.rs/posts/llm-polars-patterns>

## Questions this post answers

### Why does an LLM-translated Polars script use group_by_dynamic and join_asof instead of a simpler window function?

Language models tend to translate the pandas source structure literally rather than the underlying intent, so when pandas code builds a separate resampled frame and merges it back with merge_asof, the model mirrors that with group_by_dynamic and join_asof. The idiomatic Polars equivalent uses a single .over(pl.col('datetime').dt.truncate('5m')) call inside with_columns, computing the same per-bucket aggregate in one pass instead of two.

_Teams migrating pandas pipelines can track idiomatic Polars patterns like this on daily.dev before shipping a translation._

### Why is calling .item() in the middle of a Polars lazy pipeline a bad practice?

.item() only works on a materialized DataFrame, so using it mid-pipeline forces an early collect(), splitting one query into two, scanning the source twice and hiding the intermediate result from the optimizer. The idiomatic fix is to let the aggregation broadcast directly inside filter(), for example filter(pl.col('revenue') > pl.col('revenue').quantile(0.9)), keeping everything in the lazy plan and computing the quantile once.

_Developers optimizing Polars queries can check patterns like this against daily.dev while refining their lazy pipelines._

### How much faster is replace_strict compared to map_elements with a Python dictionary lookup in Polars?

replace_strict is about 19 times faster than map_elements with a lambda dictionary lookup at 5 million rows, because replace_strict performs the lookup inside the Polars engine while map_elements round-trips every value through the Python interpreter. Polars even emits a runtime PolarsInefficientMapWarning naming replace_strict as the exact replacement when this pattern is detected.

_Anyone optimizing Polars transformations can compare native expression alternatives like this via daily.dev._

## Similar posts on daily.dev

- [Cut Text2SQL token costs up to 81%, and stop paying for wrong answers: a Neo4j semantic layer across BigQuery and Databricks](https://daily.dev/posts/cut-text2sql-token-costs-up-to-81-and-stop-paying-for-wrong-answers-a-neo4j-semantic-layer-across-w7f20iaii) · neo4j · 0 upvotes · 0 comments
- [Harnessing Claude’s intelligence](https://daily.dev/posts/harnessing-claude-s-intelligence-x0y7hjoye) · Claude · 2 upvotes · 0 comments
- [Cursor price hikes push enterprises to Claude Code, and beyond](https://daily.dev/posts/cursor-price-hikes-push-enterprises-to-claude-code-and-beyond-2wbx3bvpe) · The Next Web · 0 upvotes · 0 comments

---

Tags: [#python](https://daily.dev/tags/python), [#claude](https://daily.dev/tags/claude), [#pandas](https://daily.dev/tags/pandas), [#polars](https://daily.dev/tags/polars)

[View this post on daily.dev](https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Fluent, not native: agents translating pandas to Polars","url":"https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy"},"datePublished":"2026-08-16T08:53:24.156Z","dateModified":"2026-08-16T08:55:24.202Z","description":"Polars ran an experiment having Claude Opus 4.8 translate pandas code to Polars in one-shot sessions across 33 test cases (PDS-H benchmark queries, EDA...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/492e98122c100051bcc66f0661115604?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/492e98122c100051bcc66f0661115604?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Polars Blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Polars Blog","logo":"https://media.daily.dev/image/upload/s--xo60W3UW--/c_limit,w_256/f_auto,q_auto/v1786870390/logos/polars?_a=BAMAMicg0","url":"https://daily.dev/sources/polars"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"python,claude,pandas,polars","timeRequired":"PT16M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Polars Blog","item":"https://daily.dev/sources/polars"},{"@type":"ListItem","position":3,"name":"Fluent, not native: agents translating pandas to Polars"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/fluent-not-native-agents-translating-pandas-to-polars-hviihfofy#faq","mainEntity":[{"@type":"Question","name":"Why does an LLM-translated Polars script use group_by_dynamic and join_asof instead of a simpler window function?","acceptedAnswer":{"@type":"Answer","text":"Language models tend to translate the pandas source structure literally rather than the underlying intent, so when pandas code builds a separate resampled frame and merges it back with merge_asof, the model mirrors that with group_by_dynamic and join_asof. The idiomatic Polars equivalent uses a single .over(pl.col('datetime').dt.truncate('5m')) call inside with_columns, computing the same per-bucket aggregate in one pass instead of two. Teams migrating pandas pipelines can track idiomatic Polars patterns like this on daily.dev before shipping a translation."}},{"@type":"Question","name":"Why is calling .item() in the middle of a Polars lazy pipeline a bad practice?","acceptedAnswer":{"@type":"Answer","text":".item() only works on a materialized DataFrame, so using it mid-pipeline forces an early collect(), splitting one query into two, scanning the source twice and hiding the intermediate result from the optimizer. The idiomatic fix is to let the aggregation broadcast directly inside filter(), for example filter(pl.col('revenue') > pl.col('revenue').quantile(0.9)), keeping everything in the lazy plan and computing the quantile once. Developers optimizing Polars queries can check patterns like this against daily.dev while refining their lazy pipelines."}},{"@type":"Question","name":"How much faster is replace_strict compared to map_elements with a Python dictionary lookup in Polars?","acceptedAnswer":{"@type":"Answer","text":"replace_strict is about 19 times faster than map_elements with a lambda dictionary lookup at 5 million rows, because replace_strict performs the lookup inside the Polars engine while map_elements round-trips every value through the Python interpreter. Polars even emits a runtime PolarsInefficientMapWarning naming replace_strict as the exact replacement when this pattern is detected. Anyone optimizing Polars transformations can compare native expression alternatives like this via daily.dev."}}]}
```

