Quotas can be established using two methods: directly within a question via the quotas: y
tag or as a separate standalone variable using type: quotas
. Directly setting a quota in a question is beneficial when the question options align with the quota groups and the same conditions apply. Opt for a separate variable when a new list or different conditions dictate quota group assignments.
The standalone variable approach (type: quotas
) is ideal when quota needs don't precisely match the question's option list, depend on multiple conditions or questions, involve complex selection logic, pertain to surveys across multiple countries, or when using audience sheets. This method is also particularly useful for crosslists (e.g., age by gender), combining questions to drive quota logic, sampling boosts, selecting a subsection of completes a quota should apply to, and determining when to use max groups
and selectby
variations.
Syntax
The type: quotas
tag is used to create a standalone quota variable that shows in the Quotas applet and can therefore be capped if needed. These variables can be put in the Quota variables chapter with the chapter
tag if they should not be in the main data map deliverable.
# single select quota with condition
QUOTA_NAME_HERE. QTA| Desc Here
type: quotas
optsfrom: LISTNAME_HERE {if condition here}
# with a crosslist
set list: AGEXGENDER
cross lists: QAGE,QGENDER
QUOTA_NAME_HERE. QTA| Desc Here
type: quotas
chapter: quotas
optsfrom: AGEXGENDER
# maxgroups (n > 1)
QUOTA_NAME_HERE. QTA| Desc Here
type: quotas
maxgroups: n
optsfrom: LISTNAME_HERE {if condition here}
# selectby: counts, weight, random, percentage
QUOTA_NAME_HERE. QTA| Desc Here
type: quotas
maxgroups: n #if applicable
selectby: counts, weight, random, percentage
optsfrom: LISTNAME_HERE {if condition here}
For a list of tags commonly used with quotas, see Common quota tags.
Examples
Quotas with different option buckets than question
In the example below, the quota QOCCUPATION has different quota groups than the option responses at Q1, hence the need for the standalone quota variable instead of using quotas: y
.
1. What is your occupation?
type: radio
randomize: y
1. Teacher
2. Doctor
3. Nurse
4. Electrician
5. Professor
6. Plumber
97. Other {autoother: y}
OCCUPATION. Occupation type
type: quotas
1. Educator {if anyChecked($Q1,1,5)}
2. Medical field {if anyChecked($Q1,2,3)}
3. Trade {if anyChecked($Q1,4,6)}
4. Other {if anyChecked($Q1,97)}
Quotas built from a combination of conditions
The first example below shows basic syntax combining two conditions for quota option purposes. QPROF_HRS takes answer options from both Q2 and Q3 to create the needed quota. The resulting options in the quota create combinations for every profession with their type of works hours.
2. In what area is your main profession?
type: radio
1. Education
2. Energy / Utilities
3. Government (local / state / federal)
4. Media / Advertising
97. Other (autoother: y}
3. What type of work hours do you keep?
type: radio
1. Full-time (30+ hrs per week)
2. Part-time (<30 hrs per week)
PROF_HRS. Profession and hours
type: quotas
1. Professional and full time {if anyChecked($Q2,1,2,4) and anyChecked($Q3,1)}
2. Professional and part time {if anyChecked($Q2,1,2,4) and anyChecked($Q3,2)}
3. Government and full time {if anyChecked($Q2,3) and anyChecked($Q3,1)}
4. Government and part time {if anyChecked($Q2,3) and anyChecked($Q3,2)}
5. Other and full time {if anyChecked($Q2,97) and anyChecked($Q3,1)}
6. Other and part time {if anyChecked($Q2,97) and anyChecked($Q3,2)}
A more complex example is shown below. Here, certain sections of a survey are seen based on responses about Restaurant 1 from question 7 and question 8. QROUTING creates the quota needed to easily track which sections are seen, and place quota caps if/when needed to control sample throughout the fielding.
#more complex
setlist: BRANDS
randomize: y
1. Restaurant 1
2. Restaurant 2
3. Restaurant 3
4. Restaurant 4
5. Restaurant 5
7. Which of the following restaurants have you heard of / are familiar with?
type: radio table
1. Never heard of
2. Heard of but not considered
3. Heard of and considered and / or purchased from
rowsfrom: BRANDS
8. Of the following, which have you purchased from?
type: radio table
1. Considered but not purchased from
2. Purchased from over a year ago and not in the last year
3. Purchased from within the last year
rowsfrom: BRANDS {if anyChecked($Q7R[id],3)}
ROUTING. QTA| For routing - based off Restaurant 1
type: quotas
chapter: quotas
1. Never heard of (Does not see Section 2 or 3) {if anyChecked($Q7R1,1)}
2. Deep Dive Barriers (Sees Section 2) {if anyChecked($Q7R1,2) or anyChecked($Q8R1,1,2)}
3. Deep Dive Current (Sees Section 3) {if anyChecked($Q8R1,3)}
Using selectby with quotas
The selectby
tag gives quotas flexibility in programming as well as allowing for sampling needs to be met. It accepts inputs of 'counts', 'weight', 'random', 'percentage', 'balance', 'weighted draw', or 'calculate' to specify exactly how a quota should function. A single selectby
tag can include multiple methods of selection. All selectby
methods will respect condition decorators. The option set is first limited by condition decorators, and then chosen from the remaining options in the set by the method determined by the selectby
tag. If there is a tie based on the selectby
condition, then the selection will be chosen randomly. This gives programmers the flexibility in assigning quota groups to meet researchers' needs.
The example below at Q8 collects all the restaurant brands visited in the last 12 months in the rowpunchsummary
variable, then takes the restaurant with the highest weight (WT) at the list that meets the needs for the quota for the last visit selection. If both Restaurant 4 and 5 were eligible for QLAST_VISIT based on the condition, and because the weight is the same on these two options, the system will then use 'counts' to decide which restaurant punches as QLAST_VISIT. The option with fewer punches, between Restaurants 4 and 5, will be selected.
setlist: BRANDS
randomize: y
1. Restaurant 1 {{WT: 1000}}
2. Restaurant 2 {{WT: 10}}
3. Restaurant 3 {{WT: 1}}
4. Restaurant 4 {{WT: 100}}
5. Restaurant 5 {{WT: 100}}
8. Of the following, which have you purchased from?
type: radio table
99. Never heard of
1. Not considered
2. Considered but not purchased from
3. Purchased from over a year ago
4. Purchased from within the last 12 months
rowsfrom: BRANDS
rowpunchsummary: QL12M {if anyChecked($Q8R[id],4} {desc: Q8 | Brands purchased from}
LAST_VISIT. Last visit selection
type: quotas
selectby: weight,counts
opts from: BRANDS {if anyChecked($QL12M,[id])} {weight: [WT]}
For further examples on weight, please see selectby.
Using crosslists with quotas
Crosslists are lists built from combining options from two or more lists. In a crosslist, a list entry is created for every possible permutation of options from the origin lists. Crosslists create IDs by concatenating the original list IDs and separating them with an underscore (e.g., 1_1, 1_2, etc.). The option text is also concatenated, and is separated with a comma by default (e.g., 'UK, Independent'). All conditions and option decorator data are also preserved, so they can be used by any questions or variables which reference the crosslist.
The first example below is the country selection, and Q2 is what type of hotel property the respondent works for. The crosslist takes the answers from these two questions to create the crossed quota.
CNTRY. Select country
type: radio
1. UK
2. US
3. DE
2. Is your hotel part of a chain?
type: radio
1. No, it's an independent hotel with 1-3 locations in the same country
2. Yes, it's part of a regional chain with 3+ hotels in the same country / region
3. Yes, it's part of a global chain with worldwide presence
HOTEL_TYPE. Hotel type
type: coded single select
1. Independent {if anyChecked($Q2,1)}
2. Regional Chain {if anyChecked($Q2,2)}
3. Global Chain {if anyChecked($Q2,3)}
set list: CNTRYXHOTEL
cross lists: QHOTEL_TYPE,QCNTRY
HOTEL_CNTRY. QTA| Hotel type (Q2) x CNTRY
chapter: quotas
type: quotas
optsfrom: CNTRYXHOTEL
Suppose a researcher wants to ensure their survey's respondents are representative of the Census data, based on age nested (crossed) by gender. The best way to do this would be to create a crosslist quota utilizing age and gender questions as the crosslist inputs (question label shorthand, in lieu of lists). The resulting options of this quota would then be all possible (accepted) combinations of gender and age ranges (e.g., Male, 18-24; Male, 25-34; etc.). Configured this way, Census information can then be used to set quota maximums for each age and gender grouping.
The example below shows how to take the numeric input for age entered at Q2 and store this data in an age bracket with the hidden variable QAGE_BRACKET. Then, the respondent's answer at Q1 is crossed by the resulting age bracket answer at QAGE_BRACKET. So, if Q1's response is "female" and QAGE_BRACKET's punch is "25-34," the only acceptable crosslist result is "Female, 25-34," and this is the final list and answer option pulled into the quota variable at QGENDER_AGE.
1. What is your gender?
type: radio
1. Male
2. Female
setlist: AGELIST
translate: n
1. 1-17
18. 18-24
25. 25-34
35. 35-44
45. 45-54
55. 55-64
65. 65+
2. What is your age?
type: text
datatype: whole
range: 1-99
AGE_BRACKET. Age bracket
type: radio
selectby: weight
translate: n
optsfrom: AGELIST {if $Q2 >= [id])} {weight: 10*([id])}
set list: GENDERXAGE
crosslists: Q1,QAGE_BRACKET
GENDER_AGE. QUOTA | Gender x Age
type: quotas
optsfrom: GENDERXAGE
Note that crossing more than three lists is not recommended and can cause unwarranted behavior, as well as stress the system.
max groups
Often times a respondent qualifies for more than one quota bucket. A common example is when assigning brands. The maxgroups
tag can be added to the quota widget, essentially making this a multi-punch quota. This allows the respondent to punch anywhere from the minimum of '1' up to and including the value input of the tag (e.g., '3'). In the example below, the tag maxgroups
has a value of '3', letting respondents fill up to three quota buckets.
4. Which fast food chains are you aware of?
instruct: Select all that apply
type: checkbox
randomize: y
1. McDonald's
2. Burger King
3. KFC
4. Checkers
5. Sonic
97. Other {autoother: y} {anchor: y}
99. None of these {anchor: y} {term: y}
5. Which of these fast food chains have you purchased from in the last 12 months?
type: checkbox
optsfrom: Q4-[99]
L12M_FASTFOOD. Chains purchased from in last 12 months [Max 3]
type: quotas
maxgroups: 3
optsfrom: Q5
weight decorators
If using weight
as a decorator, the quota selects the option(s) based on priority, or a weight value, defined in the survey code. The highest weight gets selected first. Weights can be static or dynamic values.
In the below example, a respondent is taken through a series of questions about food types and then is assigned to up to 2 out of 3 possible "mini-loops" to answer questions on later in the survey. Eligibility for the mini-loops is determined by what food types were purchased, and then which brands were purchased within the last 12 months. Through a combination of rowpunchsummary
variables at T5, and then a collection variable that collects all categories the respondent is eligible for, the quota then winnows down eligibility to up to two categories, selected based on weight using the weight
decorator.
Benefits of the weight
decorator include ease in updating selections for the mini loops depending on the number of respondents needed per loop and sampling availability. It is likely respondents will have bought frozen pizza versus chilled pizza or savory snacks, so the weighting is set so the less likely categories are selected if eligible. As it is desired for respondents to only see 2 out of 3 possible mini-loops, the maxgroups
tag is used to limit the number of selections.
setlist: FOODS
randomize: y
1. Frozen pizza (e.g., found in the freezer aisle)
2. Chilled pizza (e.g., not frozen, from the fridge section of the supermarket)
3. Savoury snack (e.g., potato crisps, tortilla chips)
5. Have you purchased any of the following food in the last 12 months?
type: checkbox
instruct: Select all that apply
optsfrom: FOODS
99. None of the above {exclusive: y} {term: y}
setlist: BRANDS
randomize: y
101. Screamin' Sicilian {if anyChecked($Q5,1)}
102. Red Baron {if anyChecked($Q5,1)}
201. Crosta & Mollica {if anyChecked($Q5,2)}
202. Gino D'Acampo {if anyChecked($Q5,2)}
301. Ryvita {if anyChecked($Q5,3)}
302. Jacobs {if anyChecked($Q5,3)}
9. Which of the following brands have you purchased before?
type: radio table
1. I have never bought this brand before
2. I have bought this brand but not in the last 12 months
3. I have bought this brand in the last 12 months
rowsfrom: BRANDS
rowpunchsummary: QELIG_1 {if anyChecked($Q9R[id],3)} {desc: Q9_1 Frozen pizzas eligible} {rows: [101,102]}
rowpunchsummary: QELIG_2 {if anyChecked($Q9R[id],3)} {desc: Q9_1 Chilled pizzas eligible} {rows: [201,202]}
rowpunchsummary: QELIG_3 {if anyChecked($Q9R[id],3)} {desc: Q9_1 Savoury bread snacks eligible} {rows: [301,302]}
ELIG_CAT. All eligible categories for loops
type: coded multi select
maxgroups: 99
translate: n
optsfrom: Q5.options {if anyChecked($QELIG_[id])}
CATS. QTA| Categories seen for mini loops
type: quotas
selectby: weight
maxgroups: 2
1. Frozen pizza {if anyChecked($QELIG_CAT,1)} {weight: 1}
2. Chilled pizza {if anyChecked($QELIG_CAT,2)} {weight: 10}
3. Savoury bread snacks {if anyChecked($QELIG_CAT,3)} {weight: 100}
applyif
In the case it is necessary to have quotas on a page which does not have exhaustive buckets for all respondent groups, use the applyif
tag. In order for a respondent to punch a quota bucket (or fail to and be sent to Over Quota), the condition specified at the apply if
tag must be met. If it is not met, the respondent will skip the quota, without regard for whether or not they qualify for any open bucket, or none at all. The quota variable, QRACE, which is later in the survey, is based on Q2, and therefore respondents from Canada and Mexico would not be subject to this quota.
COUNTRY. Respondent Country invisible: y type: radio cvalue: url_param('c') 1. USA 2. Canada 3. Mexico 2. What is your race or ethnic background? showif: anyChecked($QCOUNTRY,1) type: radio 1. White or Caucasian 2. Black or African American 3. Asian 4. American Indian, Alaska Native, Native Hawaiian, or other Pacific Islander 97. Other ethnicity {autoother: y; placeholder: Specify}
RACE. QUOTA | Race-Ethnicity
type: quotas
applyif: anyChecked($QCOUNTRY,1)
optsfrom: Q2
Boost
Often a survey needs a certain number of respondents for a brand, and the sampling team needs an easy way to send respondents who do not fit the need for that brand to either a Terminate or Over Quota status.
The example below has a quota ready for the sampling team to cap the 'No' bucket when no more respondents are needed that did not purchase Vans sneakers in the last 12 months. This type of quota is useful when entering a "boost" or "oversample" phase and a programmer is not available to amend code with a termination point. The tag statusifover
can be used to designate a respondent as a different status than 'Q' for Over Quota.
setlist: SNEAKERS
randomize: y
1. Adidas
2. Nike
3. New Balance
4. Vans
5. Reebok
97. Other {autoother: y} {anchor: y}
10. Which brands of sneakers have you bought in the last 12 months?
type: checkbox
optsfrom: SNEAKERS
99. None of the above {term: y}
VANS_BOOST. QTA | Vans boost
type: quotas
1. Yes bought Vans in last 12 months {if anyChecked($Q10,4)}
2. No did not buy Vans in last 12 months {if noneChecked($Q10,4)}
##statusifover: T
Audience Sheets
The audience sheet
tag or decorator is what triggers our platform to place a quota in the Audience Quotas applet instead of the Quotas applet. The audience sheet
tag/decorator requires an audience sheet as input.
In the example below, QGENDERQ uses the audience sheet 'audience_us_gender' to match results of the quota with existing US gender demographics.
setlist: GENLIST
1. Male
2. Female
GENDERQ. Gender group quota
type: quotas
audience sheet: system.audience_us_gender
optsfrom: GENLIST
Comments
0 comments
Please sign in to leave a comment.