Brings a data frame into a fabricate call as a level of its own, so
that real data can be crossed or linked with other real data.
fabricate(data = ) starts from one frame and builds down from it;
import_level makes each frame a named level, which is the thing
cross_levels and link_levels work on.
Arguments
- data
A data frame. Its rows are the level's units.
- ...
Column expressions evaluated against the imported columns, as in any other level.
Nis the number of rows imported.- .id
Optional string naming the column of
datathat already identifies its rows. Left off, a column named after the level is used when the data has one, the way a join matches on a shared name, and otherwise fabricatr numbers the rows itself.
Value
A fabricatr_level object, meaningful only as a named
argument to fabricate. It contributes the imported rows, an ID
column named after the argument it is assigned to, and one column per
expression in .... Like declare_level, it stands alone
rather than nesting into the frame in hand, so it can be named in a later
cross_levels or link_levels.
Which column is the ID
A level's ID column is named after the level, and import_level only
decides what goes in it. Three cases, in order:
.id = "pid"uses that column of the imported data, renamed to the level's name. It has to exist, and its values have to be distinct and non-missing, because a level's rows are its units.Left off, a column already named after the level is used as it stands:
individuals = import_level(df)wheredfhas anindividualscolumn keeps that column rather than putting a second ID beside it.Otherwise the rows are numbered, as
add_levelnumbers them.
A column called N is refused. N is the number of rows the
level is building in every expression it evaluates, so the two cannot both
be in view; rename the column before importing it, or use
fabricate(data = ), which evaluates nothing at a level and keeps it.
An imported ID keeps its own type and values, where a fabricated one is a zero-padded character string. That is the point of importing it: the column still matches the same key in the data it came from. It also means an integer key stays an integer, so a model formula reading it will treat it as a quantity unless you make it a factor.
Examples
individuals <- data.frame(individuals = c("ann", "bob", "cyd"),
ind_shock = c(-0.4, 0.1, 0.8))
periods <- data.frame(year = 2020:2022, period_shock = c(0.2, -0.1, 0.3))
# Each frame keeps its own key: `individuals` by name, `year` by `.id`
fabricate(
individuals = import_level(individuals),
period = import_level(periods, .id = "year"),
obs = cross_levels(
.by = c("individuals", "period"),
Y = ind_shock + period_shock + rnorm(N)
)
)
#> # A tibble: 9 × 6
#> individuals ind_shock period period_shock obs Y
#> <chr> <dbl> <int> <dbl> <chr> <dbl>
#> 1 ann -0.4 2020 0.2 1 -0.249
#> 2 bob 0.1 2020 0.2 2 -0.926
#> 3 cyd 0.8 2020 0.2 3 0.0342
#> 4 ann -0.4 2021 -0.1 4 -0.829
#> 5 bob 0.1 2021 -0.1 5 0.170
#> 6 cyd 0.8 2021 -0.1 6 2.20
#> 7 ann -0.4 2022 0.3 7 -0.648
#> 8 bob 0.1 2022 0.3 8 -0.582
#> 9 cyd 0.8 2022 0.3 9 0.0863
# Imported units with fabricated units nested inside them
fabricate(
villages = import_level(data.frame(villages = c("v1", "v2"),
v_income = c(10, 12))),
citizens = nest_level(N = 3, income = v_income + rnorm(N))
)
#> # A tibble: 6 × 4
#> villages v_income citizens income
#> <chr> <dbl> <chr> <dbl>
#> 1 v1 10 1 9.53
#> 2 v1 10 2 9.09
#> 3 v1 10 3 10.4
#> 4 v2 12 4 12.6
#> 5 v2 12 5 11.4
#> 6 v2 12 6 12.5