DataFrames, CSV and tabular data in Julia
Build and reshape tables, filter and transform columns, aggregate by group, join tables, and handle missing values without surprises.
Building and inspecting
using DataFrames, CSV
df = DataFrame(
id = 1:5,
region = ["north", "south", "north", "east", "south"],
amount = [100.0, 250.0, missing, 400.0, 50.0],
shipped = [true, false, true, true, false],
)
names(df)
size(df)
first(df, 3)
describe(df) # per-column summary, including missing counts
df.amount # a column as a vector
df[!, :amount] # same, no copy
df[:, :amount] # a copy| Verb | Does |
|---|---|
select | Choose and rename columns |
filter | Keep rows matching a predicate |
transform | Add or replace columns, keeping the rest |
select with a function | Add columns and drop the others |
subset | Keep rows, treating missing as false |
groupby + combine | Aggregate per group |
sort | Order rows by columns |
innerjoin / leftjoin | Join on a key |
Transforming and grouping
using DataFramesMeta # optional, for @chain and friends
transform(df, :amount => (x -> coalesce(x, 0.0)) => :amount_clean)
transform(df, :amount => ByRow(x -> x === missing ? 0.0 : x) => :amount2)
# note the difference between the two arrow forms
transform(df, :amount => sum => :total) # whole column
transform(df, :amount => ByRow(abs) => :abs_amount) # element-wise
filter(:shipped => ==(true), df)
subset(df, :amount => ByRow(>(100)), skipmissing = true)
g = groupby(df, :region)
combine(g, :amount => sum => :revenue,
:amount => mean => :avg,
nrow => :count)
sort(df, :amount; rev = true, nullsfirst = false)ByRow wraps a function so it is applied per element instead of to the whole column. Forgetting it is the most common source of confusing errors in transform.
Missing values and joins
sum(df.amount) # missing, because one value is missing
sum(skipmissing(df.amount))
sum(coalesce.(df.amount, 0.0))
eltype(df.amount) # Union{Missing, Float64}
dropmissing(df)
disallowmissing(df)
# joins: check the key type and uniqueness first
left = DataFrame(id = [1, 2, 3], name = ["a", "b", "c"])
right = DataFrame(id = [2, 3, 4], score = [10, 20, 30])
innerjoin(left, right, on = :id)
leftjoin(left, right, on = :id)
outerjoin(left, right, on = :id, source = :origin => ["left", "right"])⚠️
A join where the key has duplicates on both sides produces a cross product for those keys and silently multiplies your row count. Check uniqueness with
nrow(df) == length(unique(df.id)) before joining, and compare nrow before and after.FAQ
Why is my sum missing when only one value is absent?
Arithmetic on
missing propagates, by design: a sum that silently ignored unknowns would be wrong. Use skipmissing to drop them deliberately, or coalesce to substitute a value.How do I add a column computed from several columns?
Use
transform with a function that takes the frame or a ByRow function over a tuple: ByRow((a, b) -> a + b) applied to [:x, :y].Related
Strings, IO and working with files Plotting with Plots.jl and Makie
Last refreshed 2026-09-18.