| name | python-r-translation |
| description | Python-to-R translation for data analysis. Maps Python (polars, plotnine, pyfixest, statsmodels, svy, geopandas) to R (tidyverse, ggplot2, fixest, survey, sf). Use when user has Python background or requests Python-equivalent code comments in R pipelines. |
| metadata | {"audience":"research-coders","domain":"cross-language","skill-last-updated":"2026-07-24"} |
Python-to-R Translation Skill
Python-to-R translation reference for quantitative social science data analysis. Maps Python ecosystem packages (polars, plotnine, pyfixest, statsmodels, linearmodels, svy, geopandas, scikit-learn) to R equivalents (tidyverse/dplyr, ggplot2, fixest, base R stats, plm, lme4, survey, sf, terra, tidymodels). Use when user mentions Python background, requests Python-equivalent code comments in R pipelines, needs to understand R analysis code from a Python perspective, or wants to translate Python data analysis concepts to R. Covers paradigm differences, verb-by-verb operation translations, regression modeling, causal inference, visualization, and workflow adaptation.
Cross-language translation reference for researchers moving between the Python and R data analysis ecosystems. This skill maps Python packages, idioms, and workflows to their DAAF R equivalents so that Python-background users can audit, understand, and learn from DAAF-produced R code, and so that code-producing agents can annotate their output with Python equivalents when directed.
This skill is a routing hub -- it provides overview tables, decision trees, and directs readers to the detailed reference files listed below. The reference files contain the exhaustive verb-by-verb mappings, code examples, and edge-case documentation.
What This Skill Does
- Maps the Python data analysis ecosystem to DAAF's R stack across data wrangling, modeling, visualization, causal inference, surveys, spatial analysis, and workflow tooling
- Provides a structured annotation protocol for agents to add inline Python-equivalent comments to R code
- Identifies paradigm gaps where Python and R diverge fundamentally, so users know where to expect friction
Use cases:
- Python user auditing DAAF R code and needing to understand what operations are being performed
- Agent annotating R code with Python-equivalent comments for a Python-background researcher
- Python user learning R for data analysis and needing a conceptual bridge
- Translating a specific R operation or idiom to its Python equivalent
- Understanding where Python tools have no direct R equivalent (and what the workaround is)
How to Use This Skill
Reference File Structure
Each topic in ./references/ contains focused documentation:
| File | Purpose | When to Read |
|---|
paradigm-differences.md | Core language and paradigm differences | Encountering fundamental R-vs-Python confusion |
dplyr-polars.md | Core dplyr/tidyr verbs explained for polars users (filter, mutate, joins, reshaping, window functions, piping) | Reading or writing data manipulation code |
strings-dates-factors.md | String, date/time, and factor operations (stringr, lubridate, forcats for polars users) | Working with string/date/categorical columns |
regression-modeling.md | fixest/stats/plm explained for pyfixest/statsmodels/linearmodels users | Reading or writing regression code |
visualization.md | ggplot2/plotly R explained for plotnine/plotly Python users | Reading or writing visualization code |
causal-inference.md | R causal inference ecosystem explained for Python users | Working with DiD, RDD, IV, event studies |
survey-spatial-ml.md | survey/sf/tidymodels explained for svy/geopandas/scikit-learn users | Working with surveys, spatial data, or ML |
workflow-environment.md | DAAF/R workflow explained for Python-background users | Adapting to DAAF's R execution model |
external-resources.md | Curated guides and tutorials with provenance | Seeking additional learning materials |
gotchas.md | Common Python-user mistakes in R | Debugging or reviewing code from Python perspective |
Reading Order
- Python user auditing DAAF R code:
paradigm-differences.md then the relevant domain file (e.g., dplyr-polars.md for data wrangling, regression-modeling.md for models) then gotchas.md
- Agent annotating R code with Python equivalents: Agent Code Annotation Protocol section below, then the relevant domain file for the code being annotated
- Learning R from Python background:
paradigm-differences.md then dplyr-polars.md then workflow-environment.md then external-resources.md
- Looking up a specific translation: Quick Decision Trees below, then the relevant reference file
Quick Decision Trees
"What does this R code do in Python terms?"
What kind of R operation?
|-- Data wrangling (filter, mutate, join, pivot, summarise)
| +-- ./references/dplyr-polars.md
|-- Regression / statistical modeling
| +-- ./references/regression-modeling.md
|-- Plotting / visualization
| +-- ./references/visualization.md
|-- Causal inference (DiD, RDD, IV, event studies)
| +-- ./references/causal-inference.md
|-- Surveys / spatial / machine learning
| +-- ./references/survey-spatial-ml.md
+-- Fundamental language differences (types, syntax, environment)
+-- ./references/paradigm-differences.md
"Why does this R code look different from Python?"
What looks unfamiliar?
|-- Pipe operator (|>)
| +-- ./references/paradigm-differences.md
|-- Formula interface (y ~ x1 + x2)
| +-- ./references/regression-modeling.md
|-- Unquoted column names in functions
| +-- ./references/paradigm-differences.md
|-- library() loads everything
| +-- ./references/gotchas.md
|-- factor() and levels
| +-- ./references/paradigm-differences.md
|-- <- for assignment
| +-- ./references/gotchas.md
+-- Interactive console / RStudio workflow
+-- ./references/workflow-environment.md
"What R package replaces my Python package?"
Which Python package?
|-- polars --> dplyr + tidyr + data.table
| +-- ./references/dplyr-polars.md
|-- plotnine --> ggplot2
| +-- ./references/visualization.md
|-- plotly (Python) --> plotly (R)
| +-- ./references/visualization.md
|-- pyfixest --> fixest
| +-- ./references/regression-modeling.md
|-- statsmodels (OLS, GLM) --> base R stats (lm, glm) + lmtest + sandwich
| +-- ./references/regression-modeling.md
|-- linearmodels (panel, IV) --> plm + estimatr
| +-- ./references/regression-modeling.md
|-- statsmodels MixedLM --> lme4 (lmer)
| +-- ./references/regression-modeling.md
|-- svy --> survey (Lumley)
| +-- ./references/survey-spatial-ml.md
|-- geopandas --> sf + terra
| +-- ./references/survey-spatial-ml.md
|-- scikit-learn --> tidymodels / caret
| +-- ./references/survey-spatial-ml.md
|-- marginaleffects (Python) --> marginaleffects (R)
| +-- ./references/regression-modeling.md
|-- rdrobust (Python) --> rdrobust (R)
| +-- ./references/causal-inference.md
+-- marimo --> Quarto / RMarkdown
+-- ./references/workflow-environment.md
"Something isn't working and I think it's a Python habit"
What went wrong?
|-- Used = instead of <- for assignment
| +-- ./references/gotchas.md
|-- 0-indexed access gave wrong element
| +-- ./references/gotchas.md
|-- Used True/False instead of TRUE/FALSE
| +-- ./references/gotchas.md
|-- Missing value handling surprised me (NA vs None/NaN)
| +-- ./references/paradigm-differences.md
|-- import vs library() confusion
| +-- ./references/gotchas.md
|-- Expected method chaining, got pipe errors
| +-- ./references/paradigm-differences.md
+-- Model output structure is different
+-- ./references/regression-modeling.md
Package Mapping Overview
| R Package | Python Equivalent | Fidelity | Key Difference |
|---|
| dplyr + tidyr | polars | Low | Verb grammar vs expression system; pipe vs method chaining |
| fixest | pyfixest | High | Near-identical formula syntax; minor SE default differences |
| ggplot2 | plotnine | High | Same grammar of graphics; bare names vs string quoting for aes |
| plotly (R) | plotly (Python) | High | plot_ly() vs px.scatter(); similar output |
| base R stats + lmtest + sandwich | statsmodels | Medium | Single formula syntax vs three Python dialects |
| plm + estimatr | linearmodels | Medium | pdata.frame vs pandas MultiIndex for panel structure |
| lme4 | statsmodels MixedLM | Medium | (1 | group) in formula vs separate groups=/re_formula= arguments |
| tidymodels / caret | scikit-learn | Medium | Declarative recipe pipeline vs imperative fit/predict |
| sf + terra | geopandas | Medium | st_*() functions vs GeoDataFrame methods; different CRS handling |
| survey (Lumley) | svy | Medium | Full GLM family coverage vs limited (gaussian/binomial/Poisson/gamma) |
| Quarto / RMarkdown | marimo | Medium | Knit-based linear execution vs reactive cells |
Fidelity key: High = near-direct translation, same mental model. Medium = same capability, different API patterns. Low = fundamentally different paradigm requiring conceptual remapping.
Library Versions
Translations in this skill reference specific library versions. R versions reference
CRAN releases as of March 2026 (R 4.5.3). Python versions are pinned in DAAF's Docker
environment (Python 3.12). When syntax or behavior has changed between versions, the
reference files note the change.
| R Package | R Version (CRAN) | Python Equivalent | DAAF Version |
|---|
| dplyr + tidyr + data.table | dplyr 1.2.0, tidyr 1.3.2, data.table 1.18.2 | polars | 1.39.3 |
| fixest | 0.14.0 | pyfixest | 0.60.0 |
| ggplot2 | 4.0.2 | plotnine | 0.15.3 |
| plotly (R) | 4.12.0 | plotly | 6.5.2 |
| base R stats + lmtest + sandwich | lmtest 0.9-40, sandwich 3.1-1 | statsmodels | 0.14.6 |
| plm + estimatr | plm 2.6-7, estimatr 1.0.6 | linearmodels | 7.0 |
| lme4 | 2.0-1 | statsmodels MixedLM | 0.14.6 |
| tidymodels / caret | tidymodels 1.4.1, caret 7.0-1 | scikit-learn | 1.8.0 |
| sf + terra | sf 1.1-0, terra 1.9-11 | geopandas | 1.1.3 |
| survey | survey 4.5 | svy | 0.19.0 |
| marginaleffects (R) | 0.32.0 | marginaleffects | 0.5.0 |
| rdrobust (R) | 3.0.0 | rdrobust | 1.3.0 |
| Quarto / RMarkdown | Quarto 1.7.29 | marimo | 0.19.11 |
Pinning note: linearmodels, marginaleffects, and rdrobust are version-pinned in
DAAF's Dockerfile (linearmodels==7.0, marginaleffects==0.5.0, rdrobust==1.3.0)
and pre-installed alongside the rest of the Python stack. Translations reference their
documented APIs as of March 2026.
Top 10 Paradigm Differences
These are the friction points Python users encounter most frequently when reading or writing DAAF R code. Each is covered in depth in the referenced file.
| # | Friction Point | Python Way | R Way | Reference |
|---|
| 1 | Pipe operator | df.filter(...).with_columns(...) | `df | > filter(...) |
| 2 | Unquoted column names | pl.col("x") string references | x bare name in dplyr verbs | paradigm-differences.md |
| 3 | Missing values | None, NaN, and null (context-dependent) | Single unified NA type | paradigm-differences.md |
| 4 | Formula interface | Three incompatible Python dialects | One universal ~ syntax everywhere | regression-modeling.md |
| 5 | Assignment operator | = for assignment | <- for assignment (= also works but unconventional) | gotchas.md |
| 6 | Package loading | import pkg as alias (explicit namespace) | library(pkg) exports all names | paradigm-differences.md |
| 7 | Factor / categorical | pl.Categorical (storage only) | factor() with ordered levels, auto-dummies in models | paradigm-differences.md |
| 8 | 0-indexed vs 1-indexed | x[0] is first element | x[1] is first element | gotchas.md |
| 9 | Boolean values | True / False | TRUE / FALSE | gotchas.md |
| 10 | Data frame boundary | Must call .to_pandas() for modeling | Same tibble flows everywhere: wrangle, model, plot |
Agent Code Annotation Protocol
This section defines when and how code-producing agents add inline Python-equivalent comments to DAAF R scripts.
When to Annotate
Annotations are added only when the orchestrator explicitly passes a Python-background directive to the agent. This is not a default behavior.
Trigger conditions (orchestrator activates this when any apply):
- User states they have a Python background
- User requests Python-equivalent comments in R code
- User asks to understand R code from a Python perspective
How the orchestrator passes the directive: The orchestrator adds the following to the agent prompt:
"User has Python background. Load python-r-translation skill. Add inline Python-equivalent comments for non-trivial data operations."
Comment Format
filtered <- df |> filter(year == 2020)
result <- df |>
mutate(pct = count / sum(count))
fit <- feols(y ~ x1 + x2 | state + year, data = df, vcov = ~state)
What to Annotate
- Annotate: Data wrangling (dplyr/tidyr operations), modeling calls (fixest, lm, glm, plm), visualization layer construction (ggplot2, plotly), causal inference method calls
- Do NOT annotate:
library() calls, cat()/stopifnot() validation lines, file I/O boilerplate (read_parquet, write_parquet), config sections, section separator comments
Rules
- One
# Python: comment per logical operation, placed on the line immediately above the R code
- Keep annotations to a single line; abbreviate complex Python pipelines if needed
- Python annotations are in addition to standard IAT comments (
# INTENT:, # REASONING:, # ASSUMES:), not a replacement
- Consumer agents: research-executor, code-reviewer, debugger, data-ingest
Related Skills
| Skill | Relationship |
|---|
tidyverse | R-side data wrangling -- detailed API reference for the polars equivalent |
fixest | R-side fixed effects regression -- detailed API for the pyfixest equivalent |
ggplot2 | R-side static visualization -- detailed API for the plotnine equivalent |
plotly-r | R-side interactive visualization -- detailed API for plotly Python equivalent |
r-stats | R-side general modeling -- covers base R stats, lmtest, sandwich equivalents |
plm | R-side panel/IV models -- covers linearmodels equivalents |
survey-r | R-side survey analysis -- covers svy (Python) equivalents |
sf-terra | R-side spatial data -- covers geopandas equivalents |
tidymodels | R-side ML -- covers scikit-learn equivalents |
quarto | R-side notebooks -- covers marimo workflow equivalents |
r-python-translation | Parallel skill for R-background users reading Python code -- same domain, reverse direction |
stata-python-translation | Parallel skill for Stata-background users -- shares the same Python target stack |
Note: Individual tool skills contain library-specific usage guidance (syntax, gotchas, performance). This skill provides the Python-to-R conceptual bridge -- use both together when a Python-background user is working with a specific R library.
ML interpretation/fairness asymmetry (honest signal): Python's ML interpretation and fairness ecosystem is genuinely deeper (SHAP, fairlearn, and related tooling). The R-side equivalents (iml, DALEX, kernelshap, fairmodels) are installed and covered by the tidymodels skill's interpretation.md and fairness.md, so real R workflows exist for these tasks -- but for ML-heavy interpretation or fairness translation questions the Python direction carries more depth, and translating to R may surface a residual ecosystem gap rather than a one-to-one mapping.
Topic Index
| Topic | Reference File |
|---|
| Pipe operator (` | >`) and method chaining |
| Unquoted column names (non-standard evaluation) | ./references/paradigm-differences.md |
| Missing value semantics (NA vs None/NaN/null) | ./references/paradigm-differences.md |
| Type system differences | ./references/paradigm-differences.md |
| Package/namespace model (library vs import) | ./references/paradigm-differences.md |
| 1-indexing vs 0-indexing | ./references/paradigm-differences.md |
| Data frame philosophy (tibble everywhere vs polars-pandas boundary) | ./references/paradigm-differences.md |
| Copy-on-modify vs reference semantics | ./references/paradigm-differences.md |
| dplyr verb mapping (filter, select, mutate, arrange) | ./references/dplyr-polars.md |
| summarise / group_by equivalents | ./references/dplyr-polars.md |
| tidyr verbs (pivot_longer, pivot_wider, separate, unite) | ./references/dplyr-polars.md |
| Join operations (left_join, inner_join, anti_join) | ./references/dplyr-polars.md |
| across() / where() equivalents | ./references/dplyr-polars.md |
| case_when equivalent | ./references/dplyr-polars.md |
| Window functions (over vs group_by + mutate) | ./references/dplyr-polars.md |
| Pipe chaining comparison | ./references/dplyr-polars.md |
| Lazy evaluation (scan_parquet vs arrow) | ./references/dplyr-polars.md |
| nest/unnest equivalents | ./references/dplyr-polars.md |
| readr I/O equivalents | ./references/dplyr-polars.md |
| String operations (stringr vs polars .str) | ./references/strings-dates-factors.md |