anes_2024_personas now ships with LLMRpanel, and the examples, the Studio,
and the tests use it in place of LLMR::anes_2024_personas. FocusGroup
ships an identical copy. The data were rebuilt from the May 19, 2026 Full
Release of the ANES 2024 Time Series Study with corrected coding, so the 100
respondents and their ideology_score values differ from those in LLMR's
copy. The old build had turned the middle answers of six seven-point scales
into missing values, which also tilted the selection of respondents and the
ideology scores toward people who chose the ends of those scales. It kept
four immigration-policy labels that the Stata file cuts at 80 characters,
interviewer notes such as "{VOL}", two items from the spouse/partner survey
that gave 14 personas their partner's answers, and six fields that were
empty for everyone because their items were asked only on paper or only of
the GSS re-interview sample, which this release does not include. Answers on
the six scales now read "5 on a scale from 1 (...) to 7 (...)" and feeling
thermometers "70 on a 0-100 feeling thermometer". ?anes_2024_personas
documents the coding and the selection.
Changed handles: demo_community_type is replaced by
demo_rural_urban_identity, and the three confidence items
att_val_confidence_in_the_supreme_co, att_val_confidence_in_the_scientific,
and att_val_confidence_in_the_press by att_val_trust_in_the_judiciary,
att_val_trust_in_scientists, and att_val_trust_in_traditional_media.
att_val_general_happiness and att_val_importance_of_remaining_a_de are
gone. demo_home_ownership now comes from the item asked of everyone, so its
values include "Rented for cash"; the MAGA thermometer and satisfaction with
democracy come from post-election items asked of every respondent. The frame
has 123 columns, 17 of them demographic.
Missing-data labels are left out of the persona text. panel_from_personas()
and panel_from_data() gain na_strings, regular expressions that mark a
value or value label as missing; NULL, the default, uses the patterns of
FocusGroup's fg_default_na_strings(). Before, a frame decoded with
haven::as_factor(), as the help of as_persona_frame() advised, gave
personas answers such as "-9. Refused", "-3. RESTRICTED", and "-8. Don't
know". A few patterns are anchored: "Error" must be the whole label and
"RESTRICTED" its first word, so "Terrorism" and "There is an error" are
kept. A value or value label that matches is left out when it carries a
missing-data code (negative, or 90 and above: "-9 Refused", "[-8] Don't
know", "998. Don't know (where to rate)") or says nothing but such wording
once codes, interviewer markers ("{VOL}", "(VOL)"), and asides in
parentheses are set aside ("Refused to answer", "Don't know/Refused
(VOL.)"). Answers that use such words ("2. Refused to take sides", "I
refused to answer the door") are kept. FocusGroup decides by the same rule.
Values left out are reported.
panel_from_personas() restores the dictionary and demographic fields of
anes_2024_personas from the package's copy, with a message, when base
subsetting (x[, j], subset()) has dropped them; before, the
demographics of such a subset were rendered as questionnaire answers under
their raw handles.
Identifier columns also include ResponseId, participant_id, subject_id, user_id, PROLIFIC_PID, workerId, caseno, and QKEY.
Labeled survey columns, as haven::read_dta() and haven::read_sav() return
them, are decoded from their value labels, without haven. A labeled code is
shown as its label without the code prefix, and an unlabeled code on a scale
labeled only at its ends as "5 on a scale from 1 (...) to 7 (...)", where a
scale centered on zero runs from -m to m even when its midpoint is labeled.
Before, such a column was rendered as bare codes ("spend -- 5"), or stopped
with an error when haven was not loaded. An unlabeled negative code is left
out as missing, and any other unlabeled code is shown as the code, each with
a warning naming the column. Factor levels as haven::as_factor() writes
them, and character columns as as.character(haven::as_factor()) writes
them, are decoded by the same rules, and code prefixes ("1. ") are removed
from factor levels and character values.
Numbers are written in full: "income 100000", not "income 1e+05".
Identifier columns (id, caseid, case_id, respondent_id, respid,
resp_id, persona_id, uid, record_id, and row_id, ignoring case,
and columns whose variable label calls them a case or respondent ID, as the
ANES label of V240001 does), the column named by weights, a column named
persona, and ideology_score are never rendered. Before,
panel_from_personas() and panel_from_data() without a template wrote
them into the persona text ("id -- 101; respondent_id -- R1", "wt -- 1.2"),
and panel_from_data() wrote the ideology_score of the bundled personas.
They remain columns of the panel where they were before. A
persona_template that names one of them is an error.
Values left out of the persona text are reported in a message that names
each field and the number of personas without it. Before, they were dropped
silently, and panel_from_data() without a template wrote "column: NA". A
template placeholder without a value is now filled with nothing, with a
warning; before, it showed "NA".
panel_from_personas() gains questions, question texts named by column,
which take precedence over the frame's dictionary. When column names stand
in for the questions of stated answers, as when column subsetting has
dropped a frame's dictionary, a warning lists the columns.
A value label exactly 80 characters long draws a warning: Stata files cut value labels at that length.
The demographic columns of a panel from panel_from_personas() hold the
values as the personas state them, and the margins both constructors cite
count those values, so a missing-data label is no longer a category.
In run_panel_studio(), the persona preview, now titled "Selected persona as
sent", shows the text sent with each request, rendered from the selected
fields only; before, it showed every field while only the selected ones were
sent. ideology_score, which is never rendered, is no longer offered as a
field.
The help and vignette describe each persona-item pair as an independent request with option-order randomization; claims about item-order randomization and sample-size planning are removed.
run_panel_studio() refuses malformed population margins and benchmark
shares, naming the entry, instead of dropping it.
panel_from_personas() draws the selected respondent when rows selects a
single row; it used to sample from rows 1 to that number instead. Draws from
two or more rows are unchanged.
panel_from_personas() stops with "rows indices must be whole numbers
between 1 and nrow(data), with no NA." when rows is fractional, character,
or a factor. Before, rows = c(1.9, 3.7) selected rows 1 and 3,
rows = "3" selected row 3, and a factor selected the rows numbered by its
level codes. A fractional n stops with "n must be one whole number of at
least 1."; before, n = 2.5 drew two personas.
panel_from_personas() and panel_from_data() record the source rows they
drew in a new source_rows attribute, giving for each persona in
persona_id order the row of data it came from. as_tibble() drops it
along with margins and source.
conjoint_amce() records each attribute's reference level in a new
reference attribute and prints the reference levels below the header. The
reference is still the first declared level present in the estimation data.
When that is not the first declared level, for example because every
execution showing it failed, the function warns "Some declared conjoint
levels are absent from the estimation data." and names the level that took
its place; before, the baseline changed without a message. The same warning
names any other declared level that is absent and so has no row.
conjoint_amce() stores the number of personas whose responses entered the
estimate, the clusters behind its standard errors, in a new n_clusters
attribute and prints it beside n_respondents. n_respondents still counts
every persona administered, including those whose responses all failed or
did not parse, so the two differ after such failures.
item_likert(), item_choice(), and item_open() stop with "id must be
one nonempty character string, not ..." when the id is missing, empty, or
longer than one string, and with the same message for text. Before, an
NA id or question was accepted and sent as the text "NA", and a longer
vector was accepted and failed later or built a malformed request.
item_choice() and item_likert() stop with "options has a missing or
empty label at position ..." (or "scale has ...") when a label is NA or
empty, and with "options has labels that replies cannot tell apart: ..."
when two labels are equal after ignoring case and surrounding spaces, which
is how replies are matched to labels. Before, such labels were accepted: a
repeated Likert label made its score ambiguous, and a reply matching two
labels was assigned to the first. A label set that is not character or has
fewer than two labels stops with "must be a character vector of at least two
labels" instead of a stopifnot() message.
panel_instrument() names the repeated ids in its error "Item ids must be
unique; repeated: ...".
conjoint_design() stops with "n_tasks must be one whole number of at
least 1, not ..." and with the same message for profiles_per_task.
Before, n_tasks = 2.5 built two tasks, profiles_per_task = 2.5 showed two
profiles per task, and a count of zero built an empty design.
conjoint_design() stops with "Attribute names must be unique; repeated:
..." and, for attributes named task, profile, persona_id, or chosen,
with "Attribute name ... is reserved for the design's own columns". Before,
both failed later with a tibble error about duplicated column names. It also
stops when an attribute has no levels ("must be a vector of at least one
level"), a missing or empty level ("has a missing or empty level at position
..."), or a repeated level ("repeats the level(s) ..."). Before, a repeated
level was drawn more often than the others and made conjoint_amce() stop on
a singular design matrix, and an NA level was shown as "NA".
The duplicate-profile warning of conjoint_design() names its cause. "The
attribute space is too small for distinct profiles: it holds ..." means a
task shows more profiles than the attributes can form; "Some tasks contain
duplicate profiles because 25 redraws found no distinct one, ..." means the
redraws ran out in a space that could have supplied them. Before, both cases
were reported as a space too small.
panel_bias_audit() fills order_test_note whenever order_effect_p is
NA, with the reason no p-value is reported: an open item, an option order
that did not vary, fewer than four parsed responses, identical parsed
responses, one option shown first in every parsed response, or sparse cells.
Before, only sparse cells had a note, and the other cases were NA in both
columns. When stats::chisq.test() itself fails, the note records its
message and the function warns "The first-option test for item ... did not
run: ..."; before, the failure was dropped without a trace. LLMR::report()
prints the note beside "order p = n/a".
Corrections replacing 0.6.0, which was never published.
item_order randomization is gone, and panel_instrument() refuses it
with an explanation: every persona-item pair is an independent request,
so no respondent ever sees a questionnaire order, and shuffling a
recorded position number claimed an exposure that was never administered.
item_position now documents the item's fixed instrument position.panel_benchmark() now rejects a human reference whose probabilities
fall outside [0, 1], whose shares miss one, or whose labels were never
offered. Conjoint responses are refused, since profiles differ by
respondent. An item whose every response failed to parse gets NA
shares; zero shares would claim the categories were available and
unchosen.panel_bias_audit() reports NA with a note when chi-square expected
counts are sparse, instead of an unreliable p-value.finish_reason
"length" now warns and names max_tokens as the cause. Reasoning models
can spend a small budget entirely on hidden reasoning and emit no visible
text.panel_from_personas() requires data; the ANES example must be named.
A weight that is NA or negative now stops the call, where it used to be
quietly set to zero, and weight columns must be numeric. Weights supplied
without n draw a warning, since only a sample uses them.panel_power() is removed. Its arithmetic treated model-persona
dispersion as if it were human outcome variance, which is not a sound
basis for planning a human study; a design-sensitivity function with an
explicit dispersion source may return later.Initial CRAN release.
panel_from_margins(), panel_from_data(), and
panel_from_personas() create panels from supplied margins, microdata
rows, or persona data frames. as_persona_frame() attaches question and
field metadata to a data frame. Reports identify which panel source was used.panel_administer() administers every item to every persona. It can
randomize item and option order and records item_position and
option_order. Its classed result stores response rows in $data and the
panel, instrument, benchmark, and token usage in separate fields. Response
rows retain response_text, response_id, success, model, and
provider as columns.panel_batch_submit() submits an administration to a provider's
asynchronous batch API. panel_batch_status() and panel_batch_fetch()
inspect and retrieve the job. Synchronous and batch submission share the
max_calls and confirm gate.panel_benchmark() compares response shares with supplied human
benchmarks and records benchmark coverage. plot() displays the
compared shares.panel_bias_audit() reports parse failures and first-option sensitivity.conjoint_instrument() creates conjoint choice tasks with profiles randomized
independently for each respondent. conjoint_design() returns a classed list
with profile and attribute fields, and conjoint_amce() estimates from the
recorded respondent-level profiles with standard errors clustered by
respondent in a classed result that retains run counts as columns.run_panel_studio() provides the panel workflow in an optional Shiny
application and can download responses, reports, and benchmark tables. The
studio now preserves readable long-form output, presents response shares and
diagnostics before technical details, carries administered responses into
benchmarking and analysis, supports repeated administrations and conjoint
instruments, exposes power and AMCE calculations, permits full ANES persona
inspection and field selection, honors shared generation settings, and shows
recorded call timing when it is available. Numbered configuration sections
can be collapsed while the administration action and run plan remain in
view. Persona templates and item wording have editable working defaults.
Panel construction, administration, benchmark comparison, power, and AMCE
actions are disabled when their known inputs are incomplete, with the unmet
requirement shown beside the control.
ANES construction separates sampled panels from panels made from selected
respondents. Sampled panels disclose replacement sampling above the
100-respondent source size and no longer impose a 500-person GUI ceiling;
selected panels require at least one respondent and ignore panel size.
A blank shared maximum-output-token field now uses and displays a
512-token package default, while an explicit sidebar value takes precedence.
Response text and response labels receive most of the width in display
tables, internal identifiers remain available through a column control, and
shares, benchmark deviations, and other double columns use concise
display-only rounding.