Toggle navigation
Home
▼ Details
Products and pricing
Chart gallery
User stories
Text analytics
CDC NAMCS Library
Blog
Tutorials
Contact
Sign in
Post Editor
← All help posts
View post
Save
<!--img src="/uploads/images/image-tempering-market-share-data-2025-11-04-17-30-43.png" alt="" style="max-width: 400px"/--> <img src="/uploads/images/image-tempering-market-share-data-2025-11-04-15-39-09.png" alt="" style="width: 1000px; max-width: 100%"/> Respondents can overstate behavior changes in an anticipated future share distribution when one or more new products are offered. In this tutorial we demonstrate how a scale question can be used to adjust overstated market share distributions in an exercise called "tempering". In this example, we use a data process to calculate a tempered share by reducing the new product shares, and redistributing the reduced shares back into the products that respondents currently use. The following examples all assume that the code below is executing within a data process (aka "green card") under *Project Settings ... > Data* or in dynamic precalculate under *Project Settings > Precalculate* ## Example questionnaire A survey asks for current prescribing behavior in **Q100**. Then in **Q200** the survey asks for a new distribution assuming that Product C is available for prescribing. If Product C receives a larger market share than expected, you can use a scale question such as **Q210** to temper down the stated shares. **Q100.** Approximately what percentage of the following products do you currently prescribe: * Q100\_1 Product A \_\_\_\_ % * Q100\_2 Product B \_\_\_\_ % **Q200.** Should Product C be available for prescribing, what will your future prescribing distribution be: * Q200\_1 Product A \_\_\_\_ % * Q200\_2 Product B \_\_\_\_ % * Q200\_3 Product C \_\_\_\_ % **Q210.** What is your overall likelihood of using Product C? 1: Not at all likely 2: Somewhat likely 3: Fairly likely 4: Very likely ## Choose a factor to weight stated shares by Determine a likelihood factor (%) for each value in **Q210**. How you do this is up to you. It might be based on a question like **Q210** (What is your overall likelihood of using Product C?). Your firm might establish the following tempering factors: 1 (Not at all likely): 0% 2 (Somewhat likely): 33% 3 (Fairly likely): 50% 4 (Very likely): 67% ## Temper and reallocate shares Our standard tempering algorithm works as follows. For each respondent: * Calculate a temper factor ε for the new product * Reduce or "temper" stated share of the new product by that temper factor. * Reallocate that reduced share to products based on change in stated share from prior scenario. This is illustrated in the diagram at the top of this page: ## Protobi tempering algorithm Protobi provides a built in algorithm **temper()** for tempering. It works at the respondent or "row" level. It takes the stated shares for the prior scenario and new scenario, plus a temper factor for the newly introduced product. ### Example dataset First let's create an example respondent dataset with two rows: ```js let rows = [ { respondent: 1, Q100_1: 0.6, // product A share before Q100_2: 0.4, // product B share before Q100_3: null, // product C share before Q200_1: 0.4, // product A share in new scenario Q200_2: 0.3, // product B share in new scenario Q200_3: 0.3, // product C share in new scenario, Q210: 4 }, { respondent: 2, Q100_1: 0.6, Q100_2: 0.4, Q100_3: null, Q200_1: 0.6, // example where existing Product A shares stay the same Q200_2: 0.2, Q200_3: 0.2, Q210: 4 } ] ``` ### Apply tempering ```js // define temper factors per your organization's standards let temper_factors = { 1: 0.00, 2: 0.33, 3: 0.50, 4: 0.67 } // temper each row for (let row of rows) { let prior = Protobi.pick(row, ["Q100_1", "Q100_2", "Q100_3"]) let next = Protobi.pick(row, ["Q200_1", "Q200_2", "Q200_3"]) let temper_factor = temper_factors[row.Q210] // row.Q210 is 4 so temper factor is 0.67 or a 0.33 reduction let eps = [null, null, 1 - temper_factor] let result = Protobi.temper(prior, next, eps) Protobi.apply(row, result, ["tQ200_1", "tQ200_2", "tQ200_3"]) $("#out").append($("<pre>").html(JSON.stringify(row,null,4))) } ``` ### Result The rows now include tempered share values: ```json [ { "respondent": 1, "Q100_1": 0.6, "Q100_2": 0.4, "Q100_3": null, "Q200_1": 0.4, "Q200_2": 0.3, "Q200_3": 0.3, "Q210": 4, "tQ200_1": 0.46666, "tQ200_2": 0.33333, "tQ200_3": 0.2000 }, { "respondent": 2, "Q100_1": 0.6, "Q100_2": 0.4, "Q100_3": null, "Q200_1": 0.6, "Q200_2": 0.2, "Q200_3": 0.2, "Q210": 4, "tQ200_1": 0.6, "tQ200_2": 0.26666, "tQ200_3": 0.13333 } ] ``` ## Appendix: Source code Below is the source code for the tempering algorithm built into Protobi data process tools. You don't actually need to read or use the code below, it's built in to Protobi. But it does illustrate how you can create custom methods of your own to add or override those in Protobi. ```js /** * Returns an array of values from a row, one for each column name */ Protobi.pick =function(row,cols) { return cols.map(col=> row[col]) } /** * Applies an array of values to a row, one for each column name */ Protobi.apply = function(row, vals, cols) { cols.forEach((col, idx) => row[col] = vals[idx]) } /** * Tempers the transition from prior shares to next shares based on epsilon factors. * * This function adjusts share transitions by applying a tempering factor (epsilon) to * selected items, reducing their change magnitude, and redistributing the "tempered away" * amount to items without epsilon factors (null epsilon values) proportionally based on * their absolute change magnitudes. * * @param {number[]} prior - Array of prior shares that sum to 1.0 * @param {number[]} next - Array of target future shares that sum to 1.0 * @param {(number|null)[]} epsilon - Array of temper factors (0-1) or null. * Non-null values reduce the change for that item. * Null values indicate items that receive redistributed amounts. * @returns {number[]} Array of tempered shares that sum to 1.0 * * @example * // Product 0 decreases by 0.2, Product 1 decreases by 0.1, Product 2 increases by 0.3 * // Product 2's increase is tempered by 0.333, reducing it by 0.1 * // The 0.1 is redistributed to Products 0 and 1 proportional to their change magnitudes * const prior = [0.6, 0.4, 0]; * const next = [0.4, 0.3, 0.3]; * const epsilon = [null, null, 0.333]; * const result = temper(prior, next, epsilon); * // Returns: [0.4667, 0.3333, 0.2000] */ Protobi.temper =function (prior, next, epsilon) { const n = prior.length; const changes = next.map((val, i) => val - prior[i]); const result = [...next]; // start with next values // Calculate total reduction from tempered items let totalReduction = 0; for (let i = 0; i < n; i++) { if (epsilon[i] !== null) { // The reduction is the change multiplied by epsilon const reduction = changes[i] * epsilon[i]; totalReduction += reduction; // Apply the tempered change: change * (1 - epsilon) result[i] = prior[i] + changes[i] * (1 - epsilon[i]); } } // Calculate total absolute change for non-tempered items (null epsilon) let totalAbsChange = 0; for (let i = 0; i < n; i++) { if (epsilon[i] === null) { totalAbsChange += Math.abs(changes[i]); } } // Redistribute the reduction proportionally to non-tempered items if (totalAbsChange > 0) { for (let i = 0; i < n; i++) { if (epsilon[i] === null) { const proportion = Math.abs(changes[i]) / totalAbsChange; result[i] += proportion * totalReduction; } } } return result; } ```
Publishing
Date
Status
Published
Draft
Slug
edit
Content
Thumbnail
Categories
Manage
New to Protobi?
Charts
Making Changes
Intermediate topics for editors
Frequently Asked Questions
SERMO Topics
Tutorial Pages
Internal Docs
Data Processing
Videos
Obsolete
GSG Admin
SERMO Admin
GSG Topics
How to...
Basics for viewers
Basics for editors
For project admins
Advanced topics
Assessments
Articles (in-progress)
New and updated articles
Process data in Protobi
superseded
Text open-end questions
Troubleshooting
Tracking studies
Organizing the view
API References
Tools
AI Database
Checking AI...
Convert to MD
Danger zone
Delete