Asset panel summary
Report the missing cells of a panel
describe gives one row for each field of an AssetPanel, with the share of its cells that the builder filled, over all cells and over the active cells. With by, it gives one row for each field and each level of a categorical field. panel_info prints the dimensions of the panel, the coverage of its two universe masks, the same shares, and the levels of each categorical field.
DataAPI.describe — Method
DataFrames.describe(pnl::AssetPanel; by::Option{<:AbstractString} = nothing)Report the share of the cells of each Panel Field of an AssetPanel that the builder filled.
A cell is missing when the observed mask of its Panel Field is false. The builder fills that cell by the fill policy of the field, and the observed mask keeps the record, so a filled cell stays missing in this report. A Panel Field with no observed mask cannot blank, and has no missing cell.
With by = nothing the table has one row for each Panel Field. With by the name of a CategoricalPanelField, the table has one row for each other Panel Field and each level of by. A cell belongs to a level when it is active, and when by is observed there and holds that level. A tensor Panel Field counts one cell for each label.
A share is a fraction in [0, 1], not a percentage. A table that reports a percentage gives the share times 100. A share over no cell is NaN: an empty set has no share.
Algorithm
- Read the active cells with
panel_active_cells. by = nothing: count the cells of each Panel Field withpanel_field_coverage, and divide each missing count by its cell count.- Otherwise read the categorical Panel Field
bywithpanel_field. For each other Panel Field and each level, count the cells of the level withpanel_level_coverage, and divide.
Arguments
pnl: The Asset Panel.by: The name of a categorical Panel Field to group the cells by, ornothing.
Validation
- The panel holds a Panel Field named
by. Raises aKeyError. - The Panel Field
byis aCategoricalPanelField. Raises anArgumentError.
Returns
df::DataFrames.DataFrame: Withby = nothing, the columnsfield,kind,cells,missing(the share of the cells, a fraction in[0, 1]),active_cells,active_missing(the share of the active cells, a fraction in[0, 1]) andassets_missing(the count of assets whose active cells are all missing). Withby, the columnsfield,level,cells(the count of cells of the level) andmissing(their share, a fraction in[0, 1]). A share over no cell isNaN.
Examples
julia> using DataFramesjulia> pnl = AssetPanel(; pf = [NumericPanelField(; name = "mcap", vals = [1.0 2.0; 3.0 4.0; 5.0 6.0], omsk = Bool[0 1; 1 1; 1 0]), CategoricalPanelField(; name = "sector", levels = ["Tech", "Energy"], codes = [1 2; 1 2; 1 2])], amsk = Bool[1 1; 1 1; 1 0], emsk = Bool[1 1; 1 1; 1 0]);julia> select(describe(pnl), :field, :missing, :active_missing, :assets_missing)2×4 DataFrame Row │ field missing active_missing assets_missing │ String Float64 Float64 Int64─────┼────────────────────────────────────────────────── 1 │ mcap 0.333333 0.2 0 2 │ sector 0.0 0.0 0julia> describe(pnl; by = "sector")2×4 DataFrame Row │ field level cells missing │ String String Int64 Float64─────┼───────────────────────────────── 1 │ mcap Tech 3 0.333333 2 │ mcap Energy 2 0.0Related
PortfolioOptimisers.panel_info — Function
panel_info([io::IO,] pnl::AssetPanel; ts::Option{<:AbstractVector} = nothing) -> nothingPrint a report of an AssetPanel: its dimensions, the coverage of its two universe masks, the missing share of each Panel Field, and the levels of each categorical Panel Field.
The panel holds no timestamps. Pass the timestamps of the ReturnsResult or the PricesResult that holds the panel as ts, and the report prints the first and the last. A missing cell is a cell that the builder filled, as DataFrames.describe(pnl::AssetPanel) states. The show of the panel is the tree of its fields, as for each Result, and this report does not replace it.
Algorithm
- Count the cells of each Panel Field with
panel_field_coverage. Print the dimensions and the missing share of the cells withpanel_info_header. - Print the coverage of the active mask with
panel_info_mask. Print the estimation mask the same way, or print that it equals the active mask. - Print the counts of each Panel Field with
panel_info_fields, the numbers ofDataFrames.describe(pnl::AssetPanel)with the shares as percentages. - Print the levels of each categorical Panel Field with
panel_info_levels.
Arguments
io: The stream,stdoutwhen it is not given.pnl: The Asset Panel.ts: The timestamps of the observations, ornothing. A static panel does not read it.
Validation
length(ts)is the count of observations of a time-varying panel. Raises aDimensionMismatch.
Returns
nothing.
Examples
julia> pnl = AssetPanel(; pf = [NumericPanelField(; name = "mcap", vals = [1.0 2.0; 3.0 4.0; 5.0 6.0], omsk = Bool[0 1; 1 1; 1 0]), CategoricalPanelField(; name = "sector", levels = ["Tech", "Energy"], codes = [1 2; 1 2; 1 2])], amsk = Bool[1 1; 1 1; 1 0], emsk = Bool[1 1; 1 1; 1 0]);julia> panel_info(pnl; ts = ["2024-01", "2024-02", "2024-03"])Asset Panel observations : 3 (2024-01 to 2024-03) assets : 2 Panel Fields : 2 cells : 6 (observations × assets) missing : 16.7% of the cells, 10.0% of the active cellsactive mask in mask : 5 / 6 cells (83.3%) assets per obs. : min 1, median 2.0, max 2 assets in mask : 2 / 2 duration (obs.) : min 2, median 2.5, max 3estimation mask: equal to the active maskPanel Fields field kind cells missing % active cells active missing % assets missing mcap numeric 6 33.3 5 20.0 0 sector categorical 6 0.0 5 0.0 0categorical Panel Fields sector: 2 levels, by the smallest count of assets over the observations < 10 : 2 levels (Tech, Energy) 10 - 19 : 0 levels 20 - 49 : 0 levels >= 50 : 0 levelsRelated
Align the active mask to the fields
panel_align_active moves the start of each asset to the first active observation where each named field is observed, and returns the new panel and the count of removed cells.
PortfolioOptimisers.panel_align_active — Function
panel_align_active(pnl::AssetPanel, fields) -> NamedTupleRemove the leading active cells of each asset of an AssetPanel until each named Panel Field holds an observed value.
An asset enters the universe of a panel when its active mask is true, and a field of the asset can start later, for example a book value that is first reported months after the listing. The function moves the start of each asset to the first active observation where each named Panel Field is observed. Only the leading cells are removed: a missing cell after that observation stays active. An asset with no such observation leaves the universe. The estimation mask is intersected with the new active mask, so it stays a subset. An observation can be left with no active asset, and the panel admits it, as it admits a view with no asset.
After the alignment, the first active cell of each asset is observed in each named Panel Field. A second call removes nothing, and the order of fields does not change the result.
A tensor Panel Field is observed at a pair of observation and asset when each of its labels is observed there. A Panel Field with no observed mask cannot blank, and is observed at each cell. The Panel Fields do not change: a removed cell keeps its value and its observed mask.
Algorithm
- Find each named Panel Field with
panel_field, and read where it is observed withpanel_observed_cells. - For each asset, find the first observation that is active and where each named Panel Field is observed. Remove the active cells before it, or each active cell when there is no such observation, and count them.
- Intersect the estimation mask with the new active mask, and make the
AssetPanelof the Panel Fields and the two new masks.
Arguments
pnl: The Asset Panel.fields: The name of one Panel Field, or a collection of names. An empty collection removes nothing.
Validation
pnlis time-varying. Raises anArgumentError.- The panel holds each named Panel Field. Raises a
KeyError.
Returns
res::NamedTuple:pnl, the aligned Asset Panel;n, the count of cells removed from the active mask.
Examples
julia> pnl = AssetPanel(; pf = [NumericPanelField(; name = "book", vals = [1.0 2.0; 3.0 4.0; 5.0 6.0; 7.0 8.0], omsk = Bool[0 1; 0 0; 1 1; 1 0])], amsk = trues(4, 2), emsk = trues(4, 2));julia> res = panel_align_active(pnl, "book");julia> res.n2julia> res.pnl.amsk4×2 BitMatrix: 0 1 0 1 1 1 1 1Related