Interview guides · Indiana University
Indiana University Data Scientist Interview Questions & Guide 2026
Modeling drills for a Indiana University data scientist interview: baselines, regression interpretation, class imbalance, model defense.
The 60-second brief
The Data Scientist role at Indiana University (IU) sits at the intersection of rigorous academic research and high-impact institutional strategy. You will serve as a bridge between complex datasets and actionable insights, supporting diverse university divisions such as the Kelley School of Business or various administrative and marketing departments. Your work directly influences how the university understands student engagement, optimizes marketing outreach, and improves institutional decision-making.
Coding rounds for this role are usually data-manipulation shaped rather than data-structure shaped: group-bys, joins, time windows, ranking within a partition. Confirm the format before spending a week on graph traversal.
Focus areas
- Model seat activation as the renewal leading indicator
- Separate mastery signals from raw usage exposure
- Read item difficulty and discrimination before trusting accuracy
Overview
This position is both intellectually demanding and highly collaborative. You will not be working in a silo; you will frequently engage with faculty, administrators, and staff to translate their operational challenges into data-driven solutions. Because Indiana University operates at a massive scale, the complexity of the data is significant, requiring a candidate who is comfortable navigating ambiguity and managing stakeholders who may not have a technical background.
Where to focus your preparation
Treat the sections below as preparation areas and confirm the format with your recruiter.
Preparation focus
No round sequence has been reported for this company, so work the categories below and confirm the format with your recruiter.
What to demonstrate
- Breadth across SQL, experimentation and product reasoning
- Ability to state assumptions before choosing a method
How to prepare
- Drill the practice exercises below and time yourself
- Prepare three quantified stories about decisions you drove
Where candidates lose points
Consent and age rules silently truncate the data, not just the joins.
Where age_gated is TRUE, behavioural logging and cross-system joins are restricted, so those learners are missing from the very tables used to compute engagement. An analysis that simply inner-joins will produce a population skewed to older learners and self-serve accounts while appearing complete. Check the age_gated share of every population you report on, and state it.
Adaptive item selection holds observed accuracy flat by construction.
A selector targeting a fixed success probability, say 70%, will keep measured first-attempt accuracy near 70% whether learners are improving or not, because as theta rises the engine simply serves harder items. Reporting 'accuracy improved 3 points' on adaptive content therefore usually means the selector got more conservative, not that anyone learned more. Accuracy is only interpretable on a fixed form with unchanged item versions, which is why the first-attempt accuracy metric above carries both restrictions.
Analysing at a different unit than the one randomised
Say out loud what was randomised (user, device, account, cluster) and make the analysis unit match, or account for the clustering with cluster-robust standard errors, the delta method, or aggregation up to the randomised unit. Randomising users and then running a test over sessions understates variance and inflates the false-positive rate.
Defining the cohort on a post-treatment condition
Ask how rows entered the table. Filtering on something that treatment itself influences, such as users who finished onboarding or accounts still active at ninety days, breaks comparability between arms; define the population at an entry point that precedes exposure and keep everyone in it.
Questions & practice
Permutation test with sections as the randomisation unit
Hard · permutation test · clustering · randomisation inference · design effect
You have outcomes with learner_id, section_id, arm ('treatment' or 'control'), and mastery_events, an integer count over the study window. Assignment was made at section level, so every learner in a section shares an arm. There are 48 sections of roughly 25 learners. Write a permutation test from scratch in numpy that respects the clustering, using the difference in learner-weighted arm means as the statistic. Report the observed statistic, a two-sided p-value, and the number of permutations. No t-test, no statistics package.
Approach
- Collapse to a section table first: section_id, arm, n_learners, sum_mastery. The learner-weighted difference in means is a function of those two columns only, and computing it from the section table makes the permutation unit structurally obvious rather than a comment in the code.
- Fix the number of treated sections at the observed count and permute arm labels over the 48 sections. Permuting learner labels destroys the within-section correlation and reproduces exactly the false precision that section-level assignment exists to avoid.
- Vectorise: build a (B, 48) boolean assignment matrix, then get treated numerators and denominators with two matrix products. That runs 20,000 permutations in well under a second, which matters because you want enough replicates for the p-value to be stable in its third digit.
- Compute the statistic as sum of treated sums over sum of treated n, minus the control equivalent. This is a ratio of sums, not a mean of section means; the two differ whenever sections vary in size, and you should say which one the study was powered on.
- Two-sided p-value is (1 + count of |T_perm| >= |T_obs|) / (1 + B). Both the numerator and denominator offsets are required for validity at finite B; without them a p-value of exactly zero is reportable, and it is wrong.
- Diagnose the clustering rather than assume it: estimate the intraclass correlation from the section table and check that the permutation null SD exceeds the naive learner-level standard error by roughly sqrt(1 + (m - 1) * rho). At m = 25 and rho = 0.15 that factor is about 2.1 on the standard error, or 4.6 on variance.
Follow-up
- 48 sections, 24 per arm, baseline and variance as observed. What effect can this design actually detect at 80 percent power, and would you have run it?
- Sections range from 8 to 60 learners. Does that change which statistic you should permute?
- The institution insists on assigning by school rather than by section. What changes in the test, and what changes in the power?
Attach the calibration in force without merge_asof
Medium · as-of join · searchsorted · vectorisation · slowly changing dimensions
You have responses (response_id, content_item_id, submitted_at, is_correct) and calibration_history (content_item_id, valid_from, valid_to, irt_a, irt_b), where intervals within an item are non-overlapping and the open interval carries valid_to as NaT. Attach to each response the irt_a and irt_b in force at submitted_at. You may not use pandas.merge_asof and you may not apply row-wise. responses has about 5 million rows, calibration_history about 40 thousand. Return the input frame plus two columns, NaN where no interval covers the timestamp.
Approach
- Sort calibration_history by (content_item_id, valid_from) and factorise content_item_id across both frames into a shared integer code, so an unknown item on the response side is detectable immediately rather than joining to nothing.
- Convert both timestamps to int64 seconds and build one composite key per side, code * 2**32 + seconds. With codes well under two billion and seconds near 1.8e9, that stays inside int64 and makes a single global search possible. State the second-level resolution assumption; interval boundaries are set at second granularity, so nothing is lost.
- Call np.searchsorted(calibration_keys, response_keys, side='right') - 1 once over the whole array. That gives, for each response, the position of the latest interval starting at or before it within the same item, because the composite key orders by item first.
- Invalidate bad candidates in two places: index -1, and a candidate whose code does not match the response's code, which happens when a response precedes its item's first interval and lands on the previous item's last row.
- Invalidate a third case that is easy to miss: the candidate has a non-null valid_to and submitted_at is at or after it, meaning the response falls in a coverage gap. Without this the previous interval's parameters leak onto uncovered responses.
- Take the parameters positionally with np.take and write NaN where any invalidation fired.
Worked solution (30 min)
- codes = pd.factorize on the concatenated item ids, applied to both frames so the mapping is shared.
- cal_key = cal_code.astype('int64') * (1 << 32) + valid_from_seconds; resp_key built the same way; sort cal by cal_key.
- pos = np.searchsorted(cal_key, resp_key, side='right') - 1.
- valid = (pos >= 0) & (cal_code[pos] == resp_code) & (cal_valid_to_seconds[pos].isna() | (resp_seconds < cal_valid_to_seconds[pos])).
- Assign irt_a and irt_b via np.take(pos) where valid, NaN elsewhere, and report the NaN count by reason.
Expected result: Every response inside a covered interval carries that interval's irt_a and irt_b. Responses before the item's first valid_from, inside a coverage gap, after a closed final valid_to, or on an item absent from calibration_history carry NaN. The whole join runs in seconds on 5 million rows with no Python-level row loop.
Verify it yourself
- Brute-force 20 randomly chosen responses with a boolean mask over calibration_history and confirm an exact match.
- The NaN count equals the count produced by an independent naive filter for uncovered timestamps.
- Shifting every submitted_at forward by one second reassigns exactly the responses sitting on an interval boundary and nothing else.
Follow-up
- A backfill wrote overlapping intervals for 200 items. How do you detect that before the join rather than after, and what do you do with those responses?
- The join is correct but peak memory is unacceptable. What changes, and which part of the approach survives?
- How would you test this without a golden output to compare against?
Bootstrap a clustered interval for minutes per mastery event
Medium · bootstrap · ratio estimator · clustering · confidence intervals
You have weekly with section_id, learner_id, active_minutes, and mastery_events for one ISO week. The guardrail metric is total active_minutes divided by total mastery_events across the population, a ratio of sums rather than a mean of per-learner ratios. Write a cluster bootstrap in numpy: resample sections with replacement, recompute the ratio, and return a 95 percent percentile interval from at least 2,000 replicates. Also return the interval you get resampling learners, and state which one you would report and why.
Approach
- Reduce to a section index first: per section, the total active_minutes and the total mastery_events. Because the statistic is a ratio of sums, a replicate needs only those two totals, which makes thousands of replicates cheap and keeps the resampling unit explicit.
- Resample section indices with replacement up to the original section count, sum both totals over the resampled sections, then divide. Never average per-section ratios: that is a different estimand and it is dominated by whichever sections happen to be small.
- Guard the denominator. A replicate drawing only sections with zero mastery events is undefined. Count how often that happens and report it rather than dropping those replicates silently, because a high rate means the weekly window is too short for this metric and the interval is not the real problem.
- Take the 2.5th and 97.5th percentiles of the replicate ratios. Percentile intervals are adequate here only while the replicate distribution is roughly symmetric; check that before reporting, and move to BCa if it is skewed.
- Repeat with learners as the resampling unit and compare widths. Report the section interval. The learner interval understates width by roughly the square root of the design effect, and it is the one that will be quoted back at you when the guardrail later moves.
Follow-up
- Sections range from 8 to 60 learners. Does resampling sections with replacement bias the point estimate, the interval, or neither?
- How does the interval change if you resample learner-weeks over four weeks instead of one, and what new assumption does that introduce?
- The interval comes back wide enough to contain both a 10 percent improvement and a 10 percent regression. What do you tell the team to do?
Pace adherence at term-week six from activity history
Hard · window functions · running aggregates · term alignment
Compute the share of active enrollments at or ahead of scheduled pace at the end of term-week 6, from fct_enrollment(enrollment_id, learner_id, course_id, section_id, term_id, enrolled_at, scheduled_start_date, due_date, units_total, units_completed, status), fct_lesson_activity(enrollment_id, content_item_id, completion_status, started_at, activity_date) and dim_term(term_id, term_start_date, term_end_date, term_length_weeks). units_completed is maintained incrementally and reflects now, not week 6. Rebuild the as-of count from activity, align each enrollment to its own term calendar, and handle NULL scheduled_start_date and NULL term_id explicitly.
Approach
- Refuse the stored column for this question. units_completed is a current snapshot, so using it scores every enrollment on today's progress and labels the result week 6. That single substitution is the difference between a metric and a number that drifts upward every time you re-run it.
- Define a completed unit from activity: take MIN(started_at) per (enrollment_id, content_item_id) over rows with completion_status = 'completed', so a learner re-opening finished content does not add a unit. A COUNT over that deduplicated set ordered by first-completion time gives units completed as of any instant.
- Set the boundary per term, not per calendar: week 6 ends at term_start_date + 42 days for that enrollment's term_id. Enrollments with NULL term_id cannot be week-aligned at all; exclude them and report the count rather than defaulting them into somebody else's calendar.
- For NULL scheduled_start_date, choose between the term start and the learner's first activity, state the choice, and measure how many enrollments it touches. If the share is large, the pace metric is being defined by a data gap rather than by pacing.
- Apply the threshold as rebuilt_units >= units_total * (6.0 / term_length_weeks), guarding units_total > 0 and excluding terms shorter than 6 weeks instead of letting the ratio exceed 1.
- Be honest about the denominator: fct_enrollment.status has no effective dating, so active at the end of week 6 is not reconstructible from this schema. Exclude enrollments whose enrolled_at is after the boundary, use current status as the stated approximation, and say which direction the survivor bias runs.
Follow-up
- status has no history. What would you add to the model to make active at the end of week 6 reconstructible, and until then does the current answer over- or under-state pace?
- Two institutions on different calendars now compare their pace rates. What is still not comparable after term-week alignment?
- A holiday lands in week 4 for one institution and week 5 for another. Does your denominator punish either, and how would an instructional-day calendar change the threshold?
Daily scored submissions under rubric scoring lag
Easy · date boundaries · null semantics · reporting lag
fct_assessment_response(response_id, learner_id, content_item_id, content_version_no, submitted_at, is_correct, score_points, max_points, scoring_mode, scored_at) stores both timestamps in UTC. scored_at is NULL until a rubric item is graded and lags submitted_at by days when scoring_mode = 'rubric_human'. Produce two dense daily series over the last 90 days: submissions keyed on submission date, and completed scorings keyed on scored date. Then state the reporting lag after which each series stops moving, computed from the data rather than asserted, and say what biases your lag estimate.
Approach
- Key the two series on different columns on purpose: date(submitted_at) for volume, date(scored_at) for graded throughput, with scored_at IS NOT NULL on the second. They answer different questions and are not two versions of one number.
- Define scored as scored_at IS NOT NULL rather than is_correct IS NOT NULL. Check first whether rubric rows carry score_points with is_correct left NULL after grading; if they do, the is_correct test undercounts by exactly the rubric share.
- Estimate lag empirically with percentiles of scored_at - submitted_at grouped by scoring_mode. This is computed only over rows already scored, so it is survivorship-biased downward. Report alongside it the share of submissions in each age bucket still unscored.
- Generate a dense date spine and LEFT JOIN both series onto it so a zero-volume day is a 0, not an absent row that a chart will interpolate across.
- Name the timezone problem instead of guessing: these tables carry a locale on the learner but no timezone, so a local-calendar day series is not computable from this schema. Say that rather than pretending date(submitted_at) is an institution's day.
Worked solution (15 min)
- Build the date spine for the 90-day window, then the two aggregates, then join.
- Run a distribution of is_correct for rows with scored_at IS NOT NULL to decide which column defines scored.
- Compute median and p95 of scored_at - submitted_at per scoring_mode, and the unscored share by 1, 3, 7 and 14 day age buckets.
- Write one sentence stating the reporting lag you are imposing and what it costs.
Expected result: Two gap-free 90-row daily series, submitted_count and scored_count, plus a lag table per scoring_mode with median lag, p95 lag, and the still-unscored share by age bucket.
Verify it yourself
- SUM(submitted_count) over the window equals COUNT(*) of responses whose submitted_at falls in the window.
- For a window ending today, SUM(scored_count) is at or below SUM(submitted_count), and the gap is concentrated in the final days rather than spread evenly.
- Rows with scoring_mode = 'auto' should show a lag near zero. A large auto lag means scored_at is written by a batch job, and the whole lag model needs rebuilding around that job's schedule.
Follow-up
- The last five days of the submitted series will be revised upward as late rows land. How do you present a series whose recent points are known to be incomplete?
- Rubric grading is done by people with weekly schedules. What does that do to a daily scored series, and would an ISO week grain be more honest?
- If you had to pick a single cut-off date after which the data is considered final, how would you derive it and what percentage of eventual scorings would you be discarding?
Build the activation metric tree for institutional seats
Easy · activation · denominators · metric tree
An institutional licence shows seats_purchased 500 and seats_provisioned 540 on fct_subscription_period, and 312 learners in dim_learner whose first_activity_at falls within 30 days of term_start. Build the activation metric tree from purchased seats through provisioned accounts, activated learners and first scored submission, using dim_learner.first_activity_at, dim_learner.org_id and fct_assessment_response.submitted_at. Pick one primary metric, state its denominator and defend the choice, and explain both directions in which provisioned can differ from purchased.
Approach
- Lay the funnel out with one source per stage: contract seats from fct_subscription_period.seats_purchased, created accounts from seats_provisioned or a count of dim_learner rows on org_id, activation from first_activity_at, and the loop entry from the first fct_assessment_response row.
- Choose the denominator deliberately. Provisioned is the operational denominator because it is what the institution actually created and what rostering can fix; purchased is the commercial denominator because it is what was paid for. Report both, put provisioned on the primary, and never let a reader mistake one for the other.
- Anchor the window on term_start from the term dimension rather than on the subscription period_start, because licence dates and academic calendars do not line up and the 30-day clock is meant to track a rollout, not a billing cycle.
- Explain both divergence directions: provisioned above purchased comes from roster sync creating accounts for a whole school, duplicate accounts from a re-import, and staff test accounts; provisioned below purchased comes from seats bought for a rollout later in the year or an administrator who never ran the sync.
- Add one guardrail so activation cannot be satisfied by a single content open: share of activated learners with at least one scored submission inside the same window.
Follow-up
- An org provisions 540 accounts on 500 seats. Does that change what you tell the account team, and does it change the metric?
- How would you report activation for an org whose term starts six weeks after the subscription period begins?
- Which stage of this tree would you alert on, and what is the alert threshold set from?
Choose a success metric for autoplay lesson advance
Easy · gameable metrics · engagement · guardrails
A change autoplays the next lesson when a video ends. Week one: lessons opened per learner rose 33%, active minutes rose 8%, scored submissions per active learner fell from 2.1 to 2.0. You have fct_lesson_activity (active_seconds, wall_seconds, completion_status, is_assigned), dim_content_item (item_type, expected_minutes) and fct_assessment_response (attempt_no, is_correct, max_points). Name the primary metric you would have pre-registered, two guardrails, and state exactly how lessons opened and completion_status are moved by the mechanism rather than by learning.
Approach
- Sort every candidate metric into exposure or outcome. Autoplay decides what starts, so any metric whose numerator is a start, an open, or a video reaching its end is written by the feature itself and cannot be primary.
- Check whether active_seconds is also contaminated: it caps each inter-heartbeat gap at 120s and excludes backgrounded tabs, so a foreground autoplay with nobody watching still accrues time while a background one accrues none. Ask how the client emits heartbeats before quoting the 8%.
- Pick a primary metric that requires an action the feature does not perform for the learner: weekly learners with at least one scored submission, or verified mastery events per active learner where the delayed retention check is available for the grade band.
- Add guardrails that close the two obvious gaming routes: scored submissions per active learner reported alongside mean max_points per submission, and median active_seconds per completed (content_item_id, version_no) so click-through shows up as a drop.
- Decide against the pre-registered rule rather than against whichever number came back largest, and say that one week of data is a direction, not a result.
Worked solution (20 min)
- List the four reported numbers and label each exposure or outcome, with one sentence per exposure metric describing how autoplay moves it at zero learning.
- Compute the outcome change: 2.0 versus 2.1 scored submissions per active learner is -4.8% relative, the only number in the set the feature does not write directly.
- Write the primary metric definition with its numerator, denominator and window, then the two guardrail definitions.
- Write the ship rule: ship only on a non-negative primary with both guardrails flat or better, holding the exposure metrics out of the decision entirely.
Expected result: Primary: weekly learners with at least one scored submission (or verified mastery events per active learner). Guardrails: scored submissions per active learner paired with mean max_points, and median active_seconds per completed content item version. Lessons opened, completion_status='completed' and wall_seconds are explicitly disqualified as primary because the feature writes them.
Verify it yourself
- Every metric you kept requires a learner action that autoplay does not perform on their behalf.
- The -4.8% on scored submissions is stated as a one-week directional warning, not as a significant result.
- You said which of wall_seconds and active_seconds autoplay can inflate, and why the backgrounded-tab exclusion matters to that answer.
Follow-up
- What evidence would convince you the 8% active-minutes lift is attention rather than a foreground tab left open?
- Verified mastery is not calibrated for the youngest grade bands. What do you report there instead, and what do you lose?
- Autoplay may genuinely help learners who would have stopped at a natural break. How would you measure that group without slicing after seeing the results?
Overall seat activation fell while every grade band rose
Medium · simpsons-paradox · mix-shift · segmentation
Seat activation, computed at learner grain as the share of provisioned accounts with first_activity_at within 30 days of term start, fell from 0.61 to 0.54 term over term. Computed inside each value of dim_learner.grade_band it rose in all seven bands. You have dim_learner (learner_id, org_id, grade_band, created_at, first_activity_at, acquisition_channel, age_gated) and fct_subscription_period (org_id, plan_tier, seats_purchased, seats_provisioned, period_start). Quantify how many of the seven points are mix and how many are within-segment, and say which number belongs in the board deck.
Approach
- Confirm the arithmetic before reaching for a story: compute segment weights (share of provisioned accounts) and segment activation rates for both terms at grade_band grain, and verify the weighted segment rates reproduce each term's headline exactly.
- Run the decomposition with both terms written out: total delta equals sum of w_pre * (r_post - r_pre) for within-segment plus sum of (w_post - w_pre) * r_pre for mix, assigning the interaction term to one side explicitly so the pieces sum without residual. Report each in points, not percentages of each other.
- Trace the weight shift to its source. Cut newly created learners by acquisition_channel and by created_at hour; several thousand accounts created inside a single hour under district_deploy or roster_sync is a provisioning job, and provisioning is not learner behaviour.
- Check the denominator for over-provisioning: seats_provisioned can exceed seats_purchased, and an org that creates accounts it never intends to use drags its own activation down with no learner acting differently. Compare provisioned against purchased by org and quantify the affected share.
- Report the raw rate alongside a mix-adjusted rate holding prior-term band weights, and state the age_gated share of the population, since consent rules restrict behavioural logging for those learners and can bias which accounts appear active at all.
Follow-up
- Which of the two numbers goes on the institutional health score, and what does the other one still tell you that the first hides?
- How would you detect this kind of mix shift automatically next time, rather than after someone noticed the aggregate was wrong?
Suggested practice checklist
Instead of guessing where the week should go, day one measures it under a fixed rubric and allocates the remaining hours in proportion to the gaps. The method is deliberately rigid: the allocation is written down before any studying starts and is not renegotiated when a topic turns out to be unpleasant.
Day 1 — Diagnostic, scored before you study anything
- Sit a 100-minute timed diagnostic in four blocks: 30 minutes of SQL across three prompts, 25 minutes of short-answer statistics, 25 minutes on one modelling or case prompt, and 20 minutes delivering one behavioural story aloud.
- Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct, and 0 is stuck, grading the output rather than how the attempt felt.
- Allocate the hours for days two to five roughly in proportion to 3 minus the score in each block, write the allocation down, and commit to not revising it midweek.
Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.
Day 2 — Largest gap: find the boundary rather than the subject
- Break the weakest area into five named sub-skills (for query work: grain control, window frames, date arithmetic, set logic with NULLs, and reading a query plan) and rate each one, so the rest of the week targets a sub-skill instead of a subject.
- Solve three problems chosen to sit just above where the rating drops off, and for each write the first move you failed to make.
- Re-solve one of them from memory four hours later, on paper, with nothing open.
Deliverable: A five-item sub-skill map with the two blocking sub-skills circled.
Day 3 — Largest gap: drill the blocking sub-skill
- Do eight short repetitions of the same shape rather than eight different problems, so what you practise is the pattern and not the puzzle.
- Write the rule you now hold in one sentence, then test it against a case built to break it: a ranking function over a column with ties, or a two-sample test on observations that are obviously dependent.
- Have someone else read your one-sentence rule and find the precondition you left out.
Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.
Day 4 — Second gap, plus maintenance on your strongest area
- Run the same sub-skill map and boundary protocol on the second-largest gap, compressed into half the day.
- Spend 25 timed minutes on your strongest area to stop it decaying, choosing the hardest problem you can still finish rather than an easy warm-up.
- Compare how the two areas fail: whether you lose time on recall, on setup, or on arithmetic, because the fix differs for each.
Deliverable: A second sub-skill map plus a one-line diagnosis of how each area fails you.
Day 5 — The gap that is not a skill
- Record yourself answering one technical and one behavioural prompt, then count two things in the playback: how many seconds before your first clarifying question, and how many sentences you started without knowing where they ended.
- Rewrite your three most-used stock phrases into shorter versions, and practise saying "I do not know, here is how I would find out" without softening it into a guess.
- Deliver one answer again with a hard 90-second limit to force structure before detail.
Deliverable: Two recordings with a counted improvement in time-to-first-question.
Day 6 — Retest under day-one conditions
- Sit the same 100-minute diagnostic structure with new prompts of comparable difficulty and score it on the identical rubric.
- Compare block by block, and for any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
- Write which single block you would still lose the offer on.
Deliverable: A second scored rubric placed next to the first, with one named remaining risk.
Day 7 — Full loop under interview conditions
- Run a 60-minute mock covering the two blocks that moved least, with an interviewer instructed to interrupt and change direction.
- Write your recovery script for the moment you go blank: restate the question, state your assumption, name the first thing you would check.
- Reduce the week to the rule statements you wrote, each with its preconditions attached, then say every one of them out loud without reading it and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive being interrupted.
Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.
Explaining a method to someone who will not follow the maths
Half of this section is about translation. Be ready to describe how you explained a result to someone who did not want the method, only the implication, and what you did when the simplified version started being repeated in a way that overstated it. Correcting your own simplification is a strong beat.
Describe a project where you had to pivot your methodology based on stakeholder feedback.
Medium · behavioural and stakeholder questions
Approach
- Pick a story where you drove the decision, not one where you observed it.
- Name the disagreement or constraint, and how you resolved it with evidence.
- State the situation in two sentences and spend the rest on your reasoning.
Follow-up
- What would you do differently if you ran that project again?
- How did you know the outcome was caused by your change?
Walk me through your experience working with academic or research-focused departments.
Medium · behavioural and stakeholder questions
Approach
- Name the disagreement or constraint, and how you resolved it with evidence.
- Quantify the outcome, including what you would not claim credit for.
- Pick a story where you drove the decision, not one where you observed it.
Follow-up
- How did you know the outcome was caused by your change?
- What did you decide not to do, and why?
Tell me about a time you had to explain a complex technical finding to a non-technical stakeholder.
Medium · behavioural and stakeholder questions
Approach
- State the situation in two sentences and spend the rest on your reasoning.
- Close with what you would do differently, concretely.
- Quantify the outcome, including what you would not claim credit for.
Follow-up
- What did you decide not to do, and why?
- What would you do differently if you ran that project again?
How do you handle missing or noisy data in large-scale administrative datasets?
Medium · behavioural and stakeholder questions
Approach
- Quantify the outcome, including what you would not claim credit for.
- Close with what you would do differently, concretely.
- Name the disagreement or constraint, and how you resolved it with evidence.
Follow-up
- How did you know the outcome was caused by your change?
- What would you do differently if you ran that project again?