Overview of DataFramesMeta.jl
masterDataFrames.jl objects. It acts as a high-level syntactic sugar layer for common DataFrame manipulations.repository·master·Indexed 19 days ago
https://github.com/juliadata/dataframesmeta.jlA Julia package providing macro-based syntactic sugar for DataFrames.jl objects to simplify common data manipulation tasks. Inspired by R's dplyr, it offers a domain-specific language (DSL) with verbs such as @select, @transform, @subset, @orderby, @combine, and @groupby. It includes row-wise versions of macros (e.g., @rtransform), support for piping operations via @chain, and utilities like @with for high-performance column operations and @passmissing for handling missing values.
DataFrames.jl objects. It acts as a high-level syntactic sugar layer for common DataFrame manipulations.DataFramesMeta.jl is a Julia package designed to transform and summarize tabular data. It provides a domain-specific language (DSL) using Julia macros to create a convenient syntax for working with DataFrames.jl objects.
Key characteristics:
dplyr: It mirrors dplyr concepts to provide a familiar workflow for R users.@) to simplify common data manipulation tasks.DataFrames.jl features.The AsTable(cols) function allows you to treat a selection of columns as a single NamedTuple. This is useful for performing operations on a group of columns at once.
:y = sum(AsTable(vars))), no other columns may be referenced in that specific expression. The command :y = sum(AsTable(cols)) + :d will fail.AsTable supports column selectors like Not, Between, regular expressions, and lists of names/symbols.AsTable is escaped by default; you do not need to use the $ prefix for column names inside AsTable on the right-hand side.# Example: Summing a list of variable names
vars = ["a", "b"]
@rtransform df :y = sum(AsTable(vars))
# Example: Using AsTable with a custom function
function fun_with_new_name(x::NamedTuple)
nms = string.(propertynames(x))
new_name = Symbol(join(nms, "_"), "_sum")
s = sum(x)
(; new_name => s)
end
@rtransform df $AsTable = fun_with_new_name(AsTable([:a, :b]))To reference columns inside DataFramesMeta macros, use Symbols. For example, use :x to refer to the column df.x. If you have a variable varname that holds a Symbol, use the interpolation syntax $varname to refer to that column.
# Direct symbol
@transform(df, :new_col = :old_col + 1)
# Using a variable containing a symbol
varname = :old_col
@transform(df, :new_col = $varname + 1)DataFramesMeta.jl supports the "split-apply-combine" workflow using @groupby.
@groupby followed by @combine to calculate statistics for each group (e.g., calculating average sleep per taxonomic order).@groupby followed by @transform to add new columns where calculations are performed relative to the group (e.g., de-meaning a value relative to its group mean).# Grouped summary statistics
@chain msleep begin
@groupby :order
@combine begin
:avg_sleep = mean(:sleep_total)
:min_sleep = minimum(:sleep_total)
:max_sleep = maximum(:sleep_total)
:total = length(:sleep_total)
end
end
# Grouped transformations
@chain msleep begin
@groupby :order
@transform :sleep_genus = :sleep_total .- mean(:sleep_total)
endDataFramesMeta.jl re-exports the @chain macro from Chain.jl. This allows you to pipe the output of one operation into the next, creating a readable, left-to-right data processing pipeline. This avoids the need to create multiple temporary named DataFrames.
@chain msleep begin
@select :name :sleep_total
@rsubset :sleep_total > 16
endDataFramesMeta uses AsTable in three distinct ways depending on its position in a transformation:
$AsTable on the Left-Hand Side (LHS): Used to create multiple columns at once where the column names are determined programmatically. Note: This requires escaping with $ until the deprecation period for unquoted column names on the LHS ends.@astable macro-flag: Used within a transformation to create multiple columns at once when the number of columns is known in advance.AsTable(cols) on the Right-Hand Side (RHS): Used for multi-column transformations. Unlike the LHS version, this requires input columns to be provided.To apply operations row-by-row without manual vectorization, use the @byrow macro within DataFramesMeta.jl macros. Alternatively, you can use specific row-wise macros that use @byrow by default: @rtransform, @rtransform!, @rselect, @rselect!, @rorderby, @rsubset, and @rsubset!.
@byrow as an argument to @transform, @transform!, @select, @select!, @combine, @subset, @subset!, @orderby, or @with.@byrow to multiple operations in a single block, place it at the beginning of the block.@byrow with a GroupedDataFrame, the functions operate on individual rows and do not take the grouping into account (similar to ByRow in DataFrames.jl).Note: @byrow is not a standalone macro and must be used within DataFramesMeta.jl macros.
# Example: Using @byrow inside @transform
@transform(df, @byrow :y = :x == 1 ? true : false)
# Example: Using @byrow in a block for multiple operations
@subset df @byrow begin
:a > 1
:b < 5
endIf an entire argument is wrapped in $() or $, DataFramesMeta bypasss its internal anonymous function creation and passes the argument directly to the underlying DataFrames.jl function. This allows you to use the DataFrames.jl "mini-language", such as src => fun => dest pairs.
You can use the . operator with a list of functions to apply multiple operations to multiple columns simultaneously:
@transform df $([:a, :b] .=> [sum mean])You can pass complex transformation pairs directly into macros like @transform or @subset:
my_transformation = :a => (t -> t .+ 100) => :c
@transform df $my_transformation
@subset df $(:a => t -> t .>= 2)Warnings:
@orderby and @with do not transparently call underlying DataFrames.jl functions; escaping entire transformations here is considered unstable.@rtransform, @rsubset) will not automatically wrap src => fun => dest in ByRow.using Statistics
using DataFrames
df = DataFrame(a = [1, 2], b = [30, 40]);
# Apply multiple functions to multiple columns
@transform df $([:a, :b] .=> [sum mean])
# Use a pre-defined transformation pair
my_transformation = :a => (t -> t .+ 100) => :c
@transform df $my_transformation
# Use a transformation pair in @subset
@subset df $(:a => t -> t .>= 2)To use DataFramesMeta.jl, install it via the Julia package manager. It will automatically install DataFrames.jl as a dependency. For the tutorial workflow, it is recommended to use a temporary environment and also install CSV and HTTP for data loading.
# Enter pkg-mode by pressing ]
pkg> activate --temp
pkg> add DataFramesMeta
pkg> add CSV HTTPTo use the package in your script or REPL, load it using:
using DataFramesMeta
using CSV, HTTP, StatisticsThe $ syntax allows you to refer to columns via a Symbol, String, or column position using a variable or literal. This is essential for working with column names that are not hardcoded.
You can use $ to reference a column name stored in a variable:
nameA = :A
df2 = @transform(df, :C = :B - $nameA)You can use $ on the left-hand side to name new columns using variables or complex expressions:
newcol = "C"
@select(df, $newcol = :A + :B)
# Using complex expressions requires parentheses
@by(df, :B, $("A complicated" * " new name") = first(:A))$1) with Symbol or String references in @transform, @with, or @eachrow. However, you can mix Symbols and Strings.$(get_column_name(x)).df = DataFrame(A = 1:3, :B = [2, 1, 2])
nameA = :A
df2 = @transform(df, :C = :B - $nameA)
nameA_string = "A"
df3 = @transform(df, :C = :B - $nameA_string)
newcol = "C"
@select(df, $newcol = :A + :B)
@by(df, :B, $("A complicated" * " new name") = first(:A))Many Julia functions (like parse) error when encountering missing values. To ensure functions return missing instead of erroring when any input is missing, wrap your row-wise transformations in the @passmissing macro. This uses Missings.passmissing under the hood.
This is typically used in conjunction with @byrow or row-wise macros like @rtransform.
# Example: Using @passmissing with @rtransform to handle missing strings
@rtransform df @passmissing :x = parse(Int, :x_str)