JuliaActuary / MortalityTables.jl

Easily Reference and use Actuarial Mortality Tables
https://juliaactuary.github.io/MortalityTables.jl/stable
Other
28 stars 10 forks source link

Long, tidy version of tables #111

Open alecloudenback opened 3 years ago

alecloudenback commented 3 years ago

End goal of #109

Preliminary work completed in example here: https://juliaactuary.org/tutorials/mortalitytablesdataframe/

"""
    long(m::MortalityTable)

Return an array of tuples containing `issue_age`,`attained_age`,`duration`,`select` rate, and `ultimate` rate.

"""
function long(m::MortalityTables.SelectUltimateTable)
    earliest_age = min(firstindex(m.select),firstindex(m.ultimate))
    last_age = max(lastindex(m.select),lastindex(m.ultimate))

    table = map(earliest_age:last_age) do issue_age
        map(issue_age:last_age) do attained_age
            # use `get` to provide default missing value
            ultimate = get(m.ultimate,attained_age,missing)
            if issue_age <= lastindex(m.select)
                select = get(m.select[issue_age],attained_age,missing)
            else
                select = missing
            end
            duration = attained_age - issue_age + 1
            (;issue_age,attained_age, duration, select,ultimate)
        end
    end

    vcat(table...)

end

"""
    long(m::MortalityTable)

Return an array of tuples containing `issue_age`,`attained_age`,`duration`,`select` rate, and `ultimate` rate.

"""
function long(m::MortalityTables.UltimateTable)
    earliest_age = firstindex(m.ultimate)
    last_age = lastindex(m.ultimate)

    table = map(earliest_age:last_age) do issue_age
        map(issue_age:last_age) do attained_age
            # use `get` to provide default missing value
            ultimate = get(m.ultimate,attained_age,missing)
            select = missing
            duration = attained_age - issue_age + 1
            (;issue_age,attained_age, duration, select,ultimate)
        end
    end

    vcat(table...)

end

To-dos

MatthewCaseres commented 2 years ago

Would it make sense to provide the same tables from Pymort's "Relational Tables API"? Open to feedback on the structure of the tables.

alecloudenback commented 2 years ago

@MatthewCaseres are you suggesting providing some sort of "table set" interface (e.g. a way to get all of CS0 2017 together) or about the layout of the tables themselves (i.e. how a "long" version of the tables should look)?

MatthewCaseres commented 2 years ago

I think both? I reconsidered my original idea of what a long mortality table was, and now am just trying to replicate the structure of a relational database, so that is what influences the design of the Relational() object.

Table groupings are derived from the metadata table's study/group fields. I am about to ship this - https://github.com/actuarialopensource/pymort/commit/8bdfec8cb80ab71100ae5d27109ae4bdf64ae20f which takes the metadata table and provides the table set interface.

The end goal is that I can do this -

group = getGroup(3209)
ultimates = jnp.array([MortXML(id).tables[0].Table.numpy for id in group])