Turns rows of a persona data frame (one respondent per row, demographics plus
survey or attitude answers) into a silicon_panel whose personas can be
administered survey items. It is built for frames following the LLMR persona
contract, such as the bundled anes_2024_personas: the demographic fields
are those that LLMR::llm_persona_demographic_fields() names, every other
column is a stated answer, answers are shown under their question wording
when the frame carries a dictionary or questions gives one, and each
persona is rendered as a person to answer in character ("You are this
person: ... On a questionnaire you gave these answers: ...").
Usage
panel_from_personas(
data,
n = NULL,
rows = NULL,
weights = NULL,
questions = NULL,
na_strings = NULL
)Arguments
- data
A persona data frame, such as anes_2024_personas. Those 100 rows are diversity-selected United States respondents and carry no survey weights, so they stand for no population.
- n
Optional panel size. With
NULL, every selected row is used; with a number, rows are sampled (without replacement whenndoes not exceed the pool, otherwise with replacement).- rows
Optional row selector: a numeric vector of whole-number row positions, a logical vector with one entry per row, or a predicate
function(df)returning such a logical vector. Applied before sampling. Character and factor selectors are refused, since a factor's codes are not row positions.- weights
Optional survey weights for the draw: a column name in
data, or a numeric vector aligned to the selected rows. Used only whennis given.NULL(default) draws uniformly. A weight column is never rendered into the persona text.- questions
Optional named character vector of question texts keyed by column name, as in
c(services = "Should the government provide fewer or more services?"). It takes precedence over the question in the frame's dictionary. Names that are not columns ofdatadraw a warning.- na_strings
Regular expressions, matched ignoring case against each value and value label, that mark it as missing.
NULL(the default) uses the patterns of FocusGroup'sfg_default_na_strings(), which match the missing-data labels of the ANES and similar releases: "Inapplicable", "Refused", "Don't know", "Not asked", "DK/RF", "No post-election interview", "Insufficient partial, interview deleted", "RESTRICTED", "Error", "Technical error", "Not reported", and the like.character(0)treats no label as missing. Answers that use such words ("2. Refused to take sides", "I keep missing the bus") are kept.
Value
A silicon_panel: a tibble with persona_id, the demographic
columns as the persona text gives them (NA where a value is left out),
and persona, with the attributes margins, source, and source_rows.
Details
Unlike panel_from_margins() and panel_from_data(), this constructor keeps
each selected respondent's answers together. The margins attribute contains
the demographic distribution of the selected rows, and the source_rows
attribute gives, for each persona in persona_id order, the row of data
it was drawn from. A persona can therefore be traced to its source record
with attr(panel, "source_rows")[panel$persona_id], which still holds after
the panel's rows are subset.
For a reproducible draw, set a seed before calling (the function never sets one itself).
Rendering of values
Each value of a rendered field is written as text by these rules.
A labeled column, such as
haven::read_dta()andhaven::read_sav()return, is decoded from itslabelsattribute; haven itself is not needed. A labeled code is shown as its label without the code prefix ("1. Male" becomes "Male"). A code without a label on a scale labeled only at its ends is shown with the scale, as in "5 on a scale from 1 (Fewer services) to 7 (More services)"; on a scale centered on zero the ends are the labeled codes -m and m, even when its midpoint is labeled too. A negative code without a label is left out as missing, with a warning. Any other code without a label is shown as the code, with a warning, unless the column labels at most one nonnegative code or only top and bottom codes ("80. Age 80 or older"), in which case the column holds numbers and the value is shown as one. Values that an SPSS file declares missing (na_values,na_range) are left out.A factor's levels are its labels. Levels as
haven::as_factor()writes them ("1. Fewer services", "[1] 1. Fewer services", and bare numbers for unlabeled codes) are decoded by the rules above; a level without a code prefix ("Refused" from a file whose labels carry none) counts as a label whose code is unknown. A character column that mixes coded labels with bare numbers, asas.character(haven::as_factor())writes it, is decoded the same way. Code prefixes are removed from factor levels and from character values.NA, empty values, and missing-data labels are left out. A value or a value label is one when it matchesna_stringsand either carries a missing-data code (negative, or 90 and above: "-9 Refused", "998. Don't know") or says nothing but the matched wording once codes, interviewer markers, and asides in parentheses are set aside ("Refused to answer", "Don't know (VOL)"), as FocusGroup decides, so a free-text answer such as "I refused to answer the door" is kept. A value with a negative code prefix that does not matchna_stringsis shown, with a warning, since many releases use negative codes for missing data; the labels of negative codes on a scale centered on zero ("-3. Far left" beside "3. Far right") draw none.Numbers are written in full: 100000, not 1e+05.
A label exactly 80 characters long draws a warning. Stata files cut value labels at 80 characters, and the ANES 2024 release has labels cut there.
Identifier columns (named, ignoring case,
id,caseid,case_id,respondent_id,respid,resp_id,persona_id,uid,record_id, orrow_id, or with a variable label that calls them a case or respondent ID, as the ANES label of V240001 does), the column named byweights, a column namedpersona, andideology_scoreare never rendered.
The values left out as missing are reported in one message per call, naming each field and the number of personas whose text omits it. A stated answer shown under its column name, for want of a question wording, draws a warning.
Examples
set.seed(110)
panel <- panel_from_personas(anes_2024_personas, n = 8)
panel
# A labeled column, as haven::read_dta() returns it, is decoded from its
# labels: the unlabeled 5 is placed on its scale and -9 is left out.
survey <- data.frame(age = c("18-29", "65 or older", "30-49"))
survey$services <- structure(c(1, 5, -9), labels = c(
"1. Government should provide many fewer services" = 1,
"7. Government should provide many more services" = 7,
"-9. Refused" = -9))
labeled_panel <- panel_from_personas(
survey, questions = c(services = "Government services and spending"))
labeled_panel$persona