Panel data frame
PortfolioOptimisers.panel_dataframe — Function
panel_dataframe(pnl::AssetPanel; nx::Option{<:VecStr} = nothing,
ts::Option{<:AbstractVector} = nothing, fields = nothing,
assets = nothing, layout::Symbol = :long,
decode::Bool = true) -> DataFrames.DataFrameRender an AssetPanel as a DataFrames.DataFrame.
This is the panel's interchange. The library persists no panel of its own, and a table is what every tool that is not this library already reads, so a caller writes the result with whatever they already use and a panel reaches disk, a plot or a spreadsheet without the library owning a format.
A panel does not name its own assets or its own observations, because the carrier that holds it names them. So nx and ts are the caller's, and each falls back to its own axis positions.
Three shapes are reachable, and fields picks between them. A single Panel Field name gives that Panel Field laid out as it stands, through panel_frame_field. Any other selection gives a layout: :long reads, :wide is lossless. A TensorPanelField has no shape of its own and the first refuses it, and it spreads into one column per trailing-axis label in both layouts, under the "<field>=<label>" name it takes in a Feature Matrix.
Algorithm
- Name the axes:
nxor the asset positions,tsor the observation positions, each checked against the shape the panel's Panel Fields agree on. - Resolve the assets with
panel_frame_assets. fieldsis one name: render that Panel Field withpanel_frame_fieldand return.- Otherwise resolve the Panel Fields with
panel_frame_fields, and render them withpanel_frame_longorpanel_frame_wide.
Arguments
pnl: The Asset Panel.nx: The asset names of the panel's universe, ornothingto name each asset by its position. SeeVecStr.ts: The observation labels, ornothingto name each observation by its position. A static panel has no observation axis and ignores it.fields: One Panel Field name, a collection of them, ornothingfor every Panel Field of the panel.assets: One asset label, a collection of them, ornothingfor every asset of the universe.layout::Symbol = :long::longfor one row per(observation, asset), filtered by the active mask.:widefor one row per observation and one column per(Panel Field column, asset). Ignored whenfieldsnames a single Panel Field.decode::Bool = true: Whether aCategoricalPanelFieldrenders its levels rather than its integer codes.
Validation
layoutis:longor:wide. Raises anArgumentError.length(nx)is the panel's asset axis. Raises aDimensionMismatch.length(ts)is the panel's observation axis, when the panel is time-varying. Raises aDimensionMismatch.- The panel holds every named Panel Field, and the universe holds every named asset. Raises a
KeyError.
Returns
df::DataFrames.DataFrame: The table.
Examples
julia> pnl = AssetPanel(; pf = [NumericPanelField(; name = "mcap", vals = [1.0, 2.0, 3.0]), CategoricalPanelField(; name = "sector", levels = ["Tech", "Energy"], codes = [1, 2, 1])]);julia> panel_dataframe(pnl; nx = ["A", "B", "C"])3×3 DataFrame Row │ asset mcap sector │ String Float64 String─────┼───────────────────────── 1 │ A 1.0 Tech 2 │ B 2.0 Energy 3 │ C 3.0 TechRelated