Panel data frame: private API
PortfolioOptimisers.panel_frame_columns — Function
panel_frame_columns(f::NumericPanelField, decode::Bool)
panel_frame_columns(f::CategoricalPanelField, decode::Bool)
panel_frame_columns(f::TensorPanelField, decode::Bool)Return the table columns one Panel Field contributes to a panel_dataframe, in column order.
A column is the triple (name, vals, omsk): its name, the slab of values over the panel's own axes, and the slab of its observed mask, or nothing when the Panel Field carries none. Every slab is assets on a static panel and observations × assets on a time-varying one, so panel_array_view slices any of them by asset.
The column count is where a table and a Feature Matrix part company. A Feature Matrix is numeric, so a categorical Panel Field spreads into one indicator column per level. A table column holds a string, so the same Panel Field is one column carrying the level itself. A tensor Panel Field is the same in both: one column per trailing-axis label, under the "<field>=<label>" name panel_field_labels gives it, because a label axis is the one thing a flat table cannot carry as an axis of its own.
Algorithm
The method that Julia selects is the algorithm.
NumericPanelField: one column, named after the Panel Field, holding its values.CategoricalPanelField: one column, named after the Panel Field, holding the level each code names underdecode, and the codes themselves otherwise.TensorPanelField: one column per trailing-axis label, named"<field>=<label>", holding that label's slice.
Arguments
f: The Panel Field.decode::Bool: Whether a categorical Panel Field renders its levels rather than its codes. The other two kinds carry no codes and ignore it.
Returns
cols::Vector{Tuple{String, Any, Any}}: One(name, vals, omsk)triple per column, in column order.
Related
PortfolioOptimisers.panel_frame_fields — Function
panel_frame_fields(pnl::AssetPanel, fields::Nothing)
panel_frame_fields(pnl::AssetPanel, fields)Resolve the Panel Fields a panel_dataframe call names, in the order it names them.
Algorithm
The method that Julia selects is the algorithm.
fieldsisnothing: every Panel Field, in panel order.- Otherwise: one Panel Field per entry, looked up by
panel_field, in the orderfieldswrites them.
Arguments
pnl: The Asset Panel.fields: The Panel Field names to include, ornothingfor every one of them.
Validation
- The panel holds a Panel Field under each name. Raises a
KeyError. Seepanel_field.
Returns
fs: The Panel Fields, in column order.
Related
PortfolioOptimisers.panel_frame_assets — Function
panel_frame_assets(nx::VecStr, assets::Nothing) -> Vector{Int}
panel_frame_assets(nx::VecStr, assets::AbstractString) -> Vector{Int}
panel_frame_assets(nx::VecStr, assets) -> Vector{Int}Resolve the asset labels a panel_dataframe call names into positions on the panel's asset axis.
The panel does not name its own assets: its Panel Fields share an asset axis, and the carrier that holds them names it. So the names are the caller's, and this is where a name becomes the position every slab is sliced by.
Algorithm
The method that Julia selects is the algorithm.
assetsisnothing: every position, in axis order.assetsis one label: that label's position.- Otherwise: one position per label, in the order
assetswrites them.
Arguments
nx: The asset names of the panel's universe. SeeVecStr.assets: The asset labels to include, ornothingfor every one of them.
Validation
nxnames every entry ofassets. Raises aKeyError.- No entry of
assetsrepeats. Raises anArgumentError.
Returns
j::Vector{Int}: The selected positions on the asset axis, in column order.
Related
PortfolioOptimisers.panel_frame_block! — Function
panel_frame_block!(df::DataFrames.DataFrame, A::AbstractVector, names::VecStr) -> nothing
panel_frame_block!(df::DataFrames.DataFrame, A::AbstractMatrix, names::VecStr) -> nothingWrite one slab of a Panel Field into a wide table, as one column per asset.
Algorithm
The method that Julia selects is the algorithm, and the slab's rank is what says whether the panel is static.
- A vector slab is static and carries no observation axis, so each asset's value becomes a one-row column.
- A matrix slab is time-varying, so each asset's column of the slab becomes a column of the table.
Arguments
df: The table under construction. It is written to.A: The slab, already sliced to the selected assets.names: The column name of each selected asset, in slab column order. SeeVecStr.
Returns
nothing.dfcarries the result.
Related
PortfolioOptimisers.panel_frame_field — Function
panel_frame_field(pnl::AssetPanel, f::AbstractPanelField, j::VecInt, nxj::VecStr, ts, decode::Bool) -> DataFrames.DataFrame
panel_frame_field(pnl::AssetPanel, f::TensorPanelField, j::VecInt, nxj::VecStr, ts, decode::Bool)Render one Panel Field as the table of its own shape: one row per observation, one column per asset.
This is what a panel_dataframe call that names a single Panel Field returns. A numeric or a categorical Panel Field already is observations × assets, so the table needs no second key and no layout, and it carries neither the universe masks nor the observed mask: it is the Panel Field itself, laid out as it stands.
A TensorPanelField is refused here. Its values are observations × assets × labels, so no arrangement of one row per observation and one column per asset holds them; a long or a wide layout does, by spreading the label axis into columns.
Algorithm
The method that Julia selects decides whether the Panel Field has this shape.
- Open the table with the observation column, unless the panel is static.
- Write the Panel Field's one value column, as one table column per selected asset.
Arguments
pnl: The Asset Panel.f: The Panel Field.j: The selected positions on the asset axis. SeeVecInt.nxj: The name of each selected asset, in the orderjwrites them. SeeVecStr.ts: The observation labels, ignored when the panel is static.decode::Bool: Whether a categorical Panel Field renders its levels rather than its codes.
Validation
fis not aTensorPanelField. Raises anArgumentError.
Returns
df::DataFrames.DataFrame: The observations × assets table, with an"observation"column first when the panel is time-varying.
Related
PortfolioOptimisers.panel_frame_long — Function
panel_frame_long(pnl::AssetPanel, fs, j::VecInt, nxj::VecStr, ts, decode::Bool) -> DataFrames.DataFrameRender the selected Panel Fields in the long layout: one row per (observation, asset), one column per Panel Field column.
The rows a time-varying panel writes are filtered by the active mask, so every row of the table is an asset that was in the universe at that observation. The estimation mask stays as its own "emsk" column, because it varies within the rows that survive the filter. A static panel has neither mask and neither column, and its rows are its assets.
Algorithm
- Open the table with the
"observation"and"asset"key columns, unless the panel is static, which carries the asset key alone. - Walk the Panel Fields in order, and each one's columns from
panel_frame_columns. Ravel each slab in row order, so an entry lands on the row its two keys name, and follow a Panel Field's value column with its observed-mask column when it carries one. - Append the estimation mask, and drop every row the active mask does not hold.
Arguments
pnl: The Asset Panel.fs: The Panel Fields, in column order.j: The selected positions on the asset axis. SeeVecInt.nxj: The name of each selected asset, in the orderjwrites them. SeeVecStr.ts: The observation labels, ignored when the panel is static.decode::Bool: Whether a categorical Panel Field renders its levels rather than its codes.
Returns
df::DataFrames.DataFrame: The long table.
Related
PortfolioOptimisers.panel_frame_wide — Function
panel_frame_wide(pnl::AssetPanel, fs, j::VecInt, nxj::VecStr, ts, decode::Bool) -> DataFrames.DataFrameRender the selected Panel Fields in the wide layout: one row per observation, one column per (Panel Field column, asset).
A column name is the Panel Field column, an "@", and the asset: "mcap@AAPL", "beta=size@AAPL", "mcap::observed@AAPL". The layout keeps every cell of the panel, so both universe masks come with it, as the "amsk@<asset>" and "emsk@<asset>" blocks. Nothing is filtered, which is what makes the wide layout the lossless one and the long layout the one that reads.
A column name is a rendering, not a key. A caller that needs the two parts back reads the long layout, whose keys are columns of their own, rather than splitting a name on its separators.
Algorithm
- Open the table with the
"observation"column, unless the panel is static, whose one row is every asset at once. - Walk the Panel Fields in order, and each one's columns from
panel_frame_columns, writing each as a block of one column per selected asset throughpanel_frame_block!. - Append the active-mask and estimation-mask blocks, unless the panel is static.
Arguments
pnl: The Asset Panel.fs: The Panel Fields, in column order.j: The selected positions on the asset axis. SeeVecInt.nxj: The name of each selected asset, in the orderjwrites them. SeeVecStr.ts: The observation labels, ignored when the panel is static.decode::Bool: Whether a categorical Panel Field renders its levels rather than its codes.
Returns
df::DataFrames.DataFrame: The wide table.
Related