The Data Scientist role at Pacific Gas and Electric is a critical function that bridges the gap between complex utility infrastructure data and actionable business intelligence. As a Data Scientist, you are responsible for leveraging data to optimize operational efficiency, enhance grid reliability, and support the company's mission to provide safe, reliable, and affordable energy to millions of Californians. You will work on high-impact initiatives that require both technical rigor and a deep understanding of the unique challenges inherent in the energy sector.
In this position, you will move beyond simple descriptive analytics to build predictive models and experimentation frameworks that influence large-scale decision-making. Whether you are analyzing sensor data to predict maintenance needs or designing metrics to evaluate the impact of new energy programs, your work directly informs the strategies that power the region. You will collaborate with cross-functional teams, including engineering, operations, and product stakeholders, to translate complex technical findings into clear, strategic recommendations.
Initial Screening
reportedWhoever runs this call is usually not a practitioner. They take notes, and a hiring manager skims those notes later, so the real question is whether your work survives being written down by someone outside the field. Test every project sentence against that: could a non-specialist repeat it correctly without knowing what a propensity score is? Carry a plain-language version of each project and one reason you want this particular role that you could not copy onto another application. Vagueness at this stage reads as inexperience, even when the underlying work was genuinely deep.
What to demonstrate
- Whether a non-specialist can restate your projects accurately, since their paraphrase is what reaches the hiring manager
- Whether your reason for wanting the role points at the work itself rather than the company's reputation
- Whether your language signals the level being screened for: what you decided yourself versus what you were handed
How to prepare
- Write a two-sentence, jargon-free version of each major project: the question nobody could answer, and the decision your work changed. Read it to someone outside data and have them repeat it back
- Point your 'why this role' answer at something concrete in the job description or the product surface you would be working on, and keep it to two sentences
- Have two questions ready about measurement: which metric the team is held to, and who acts on an analysis once it lands
Technical Rounds
reportedThis round decides whether someone can hand you a schema and a question and trust the number that comes back. Correctness under a clock is the bar, not clever syntax. The habit that separates strong from weak answers is checking the grain: after every join, know how many rows you expect and whether the count moved. Most wrong answers in this format are not wrong logic, they are a fan-out from a key that turned out not to be unique, or a filter applied before an aggregate when it belonged after. Say what you expect before you run it.
What to demonstrate
- Whether your row counts survive each join, and whether you notice on your own when they do not
- Deliberate handling of rows that fail to match, including whether the question needs an inner join or a left join with the non-matches kept and counted
- Whether NULLs are treated on purpose, given that a NULL compares equal to nothing and that COUNT of a column skips it
- Reaching a defensible answer inside the window instead of a refined one after it
How to prepare
- Take a two-table schema, write a join that fans out on purpose, then fix it by collapsing the many-side to one row per key before joining. Repeat until the fix is reflex rather than recall.
- Write a funnel as one query and print the distinct user count at each stage, then confirm each stage is a subset of the one above it rather than assuming it
- Do a few timed runs in a plain text box with no autocomplete and no formatter, since assessment editors often have neither
Behavioral Rounds
reportedMost of the weight in this round sits on the disagreement questions. Data work routinely produces an answer someone senior did not want, and the interviewer is trying to learn what you do in that hour. Both failure modes are common: folding as soon as a director pushes back, and treating the pushback as ignorance to be corrected with a better chart. A strong answer usually contains a specific thing the other person knew that you did not, and describes how you found out whether it changed the conclusion.
What to demonstrate
- Whether you can state the other side's argument accurately before you explain why you disagreed
- What you treated as evidence during the disagreement, such as a rerun under their assumption or a holdout check, rather than persuasion technique
- Whether you distinguish being overruled from being wrong, and can give an example of each
How to prepare
- Write out one disagreement where you turned out to be wrong, and say what in the data misled you. Candidates prepare the story where they were right, and the follow-up asks for the other one.
- For your main disagreement story, be ready to say what result would have made you drop your position. If no such result exists, you were not arguing from the data.
- Practise stating the opposing position out loud in one sentence the stakeholder would accept, then continue the story.
Deep-Dive Interview
reportedAn extra round usually exists because something is still open after the standard loop: a skill the earlier interviews did not sample, a level decision, or two interviewers who disagreed. It is rarely a rerun of what you already did well. Ask the recruiter who you are meeting, what function they sit in, and how long the session runs. That is an ordinary scheduling question, and the answer changes what you should prepare. What separates a strong candidate here is treating the round as a fresh evaluation with its own bar, rather than assuming earlier performance carries you through or sinks you.
What to demonstrate
- Whether you can answer well on ground the earlier rounds did not cover, without leaning on what you already said to someone else
- Consistency of the facts in your stories: the same sample size, timeframe, team size and scope of your own role as in earlier conversations
- How you handle an unfamiliar format live, including whether you ask what kind of answer is wanted before producing one
How to prepare
- Ask the recruiter for the interviewer's function, the length, and whether to expect a coding surface, a discussion, or a presentation. Preparing for a 30 minute conversation with a partner team is not the same work as preparing for a 60 minute technical block.
- Write out what each earlier round actually covered, then list the two or three areas nobody probed. That gap is the most likely subject of the extra round.
- Re-read the numbers in the project stories you have already told, so a second telling does not quietly contradict the first.
PracHub editorial advice for the preparation topics above.
Comparing accounts that received a sales or customer-success touch against those that did not
Assignment of coverage is deliberate and pulls in both directions at once: the largest accounts get a named owner because they are valuable, and the accounts showing distress get one because they are at risk. The comparison therefore mixes a strong positive selection with a strong negative one, and the naive estimate can come out with either sign depending on which assignment rule dominated during the period examined. Nothing about matching on observed size fixes this, because the risk signal that triggered coverage is usually the same signal that predicts the outcome. It needs either an actual randomised or staggered rollout of coverage, or a design built on a capacity constraint or territory boundary that assigns coverage for reasons unrelated to account health.
Reading consumption metrics before the metering lag window has closed
Usage pipelines land late and correct themselves, which is exactly what is_restated and restated_at record. A dashboard queried on day T sees a partially populated tail for the last several days, so the most recent points always slope downward and always look like a regression. Analysts then explain the artefact, and sometimes ship a change to fix it. Establish the empirical settling time by measuring how much a given usage_date's total moves between first_written_at and its final value, exclude that many trailing days from every reportable figure, and never compare a fresh period against a settled one.
Ignoring interference between units in a marketplace experiment
Ask whether one unit's treatment can change another unit's outcome through shared inventory, a matching pool, a social graph or a common budget. Where it can, randomise at a level that contains the spillover, such as region or time slice, and say explicitly what that costs you in statistical power.
Reading an observational correlation as a causal effect
Name the confounder you are most worried about and the design that would remove it: an experiment, a difference-in-differences with a checked pre-period trend, an instrument, or a regression discontinuity. When none is available, state which direction the bias likely runs and bound the claim accordingly.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
How do you balance the trade-off between model accuracy and business i…
How do you balance the trade-off between model accuracy and business interpretability?
Approach
- Pick an evaluation metric that matches the cost of each error type, not a default.
- Set a baseline first, so any model has something honest to beat.
- Say how the offline result would be validated online before it is trusted.
Follow-up
- What would you monitor after launch to know the model is still valid?
- How would you choose the decision threshold, and who owns that choice?
Audit daily usage rows for grain and arithmetic violations
You are handed fct_usage_daily as a pandas DataFrame with account_id, workspace_id, sku_code, usage_date, billable_quantity, included_quantity_applied, overage_quantity, list_amount_cents, discount_amount_cents, net_amount_cents, cogs_cents, is_restated, first_written_at and restated_at. The declared grain is one row per (account_id, workspace_id, sku_code, usage_date). Write audit(df) returning a DataFrame with one row per failing check: check name, failing row count, and one example key. Cover at minimum grain duplication, negative quantities or amounts, the identity net = list - discount, billable = included + overage, and rows where is_restated is true but restated_at is null.
Approach
- Check the grain before anything else with df.duplicated(subset=key, keep=False), and count rows rather than groups so a key appearing twice contributes 2 — if the grain is broken every arithmetic count below it is uninterpretable.
- Express each invariant as a boolean Series over the whole frame. The cent columns are integers and compare exactly, so use !=; the numeric(18,6) quantity columns need np.isclose with atol=1e-6 because included + overage is a decimal sum.
- Handle null as its own failure mode. Comparisons against NaN return False, so a check written as rows_that_pass = (a == b - c) silently files every null-amount row wherever the negation happens to land; build each check as violations = ~condition | column.isna().
- Collect the checks as a list of (name, mask) pairs and assemble the output in one pass, so adding a check is one line and every check reports in the same shape.
- Order the output with structural failures (grain, null keys) above arithmetic failures, and report zero-count checks too — a check that silently disappears when it passes is indistinguishable from a check that was never run.
Worked solution 20 min
- key = ['account_id','workspace_id','sku_code','usage_date']; dup = df.duplicated(key, keep=False); record dup.sum() and df.loc[dup, key].iloc[0].to_dict() as the example.
- neg = (df[['billable_quantity','included_quantity_applied','overage_quantity','list_amount_cents','net_amount_cents','cogs_cents']] < 0).any(axis=1); net_bad = df.net_amount_cents.isna() | (df.net_amount_cents != df.list_amount_cents - df.discount_amount_cents).
- qty_bad = ~np.isclose(df.billable_quantity, df.included_quantity_applied + df.overage_quantity, atol=1e-6) | df.billable_quantity.isna(); restated_bad = df.is_restated & df.restated_at.isna().
- Assemble pd.DataFrame([{'check': n, 'failing_rows': int(m.sum()), 'example': first_key(m)} for n, m in checks]) with the grain and null checks listed first.
Follow-up
- Which of these should block a dashboard refresh and which should only warn?
- Rows with is_restated = true legitimately change value after first write. How do you make yesterday's audit result reproducible?
- How would you extend this to catch a partition that is missing entirely rather than wrong?
Implement seven-day activation rate from its written definition
Given dim_account (account_id, created_at, is_internal, is_current) and fct_api_request (account_id, request_at, http_status, api_key_id, traffic_class), implement activation_rate(accounts, requests, week_start). Definition: the numerator is accounts whose first request with http_status < 400, api_key_id not null and traffic_class != 'synthetic_monitor' occurs no later than 168 hours after created_at; the denominator is non-internal accounts created during the ISO week starting week_start. All timestamps are tz-aware UTC. Return the rate and both counts, and refuse to report a week until every account in it has had its full 168 hours.
Approach
- Reduce dim_account to one row per account_id before joining anything. It is a type 2 dimension, so several versions of the same account exist; joining the versioned table to requests multiplies the denominator by the number of plan changes an account happened to make.
- Build the denominator first and freeze it: is_internal == False and week_start <= created_at < week_start + 7 days. Everything after this is a filter on the numerator only, because an account that never sent a request must still sit in the bottom of the fraction.
- Filter requests to qualifying rows and only then take groupby('account_id').request_at.min(). The first qualifying request is not the same object as the global first request filtered afterwards, and the two answers differ for every account whose first call was a 4xx.
- Left-join the first qualifying timestamp onto the cohort and test (first_ok - created_at) <= Timedelta(hours=168). NaT propagates to False in that comparison, which is the behaviour you want, but assert it rather than assume it.
- Guard reportability explicitly: if week_start + 7 days + 168 hours exceeds the maximum request_at in the data, the week is censored and will read as a drop, so return None or raise rather than emit a number.
Follow-up
- Median time-to-first-call is more informative. What breaks if you take the median over activated accounts only, and what estimator fixes it?
- How would you decide whether 168 hours is the right window rather than 72 or 336?
- An account signs up, does nothing for 20 days, then integrates heavily. Where does it land in this metric, and is that what you want?
Describe your process for joining disparate datasets while ensuring da…
Describe your process for joining disparate datasets while ensuring data integrity.
Approach
- State the window function and its partition and ordering out loud before writing it.
- Check whether any join is one-to-many before aggregating, or the sums inflate.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How would you verify this result without re-running the same query?
- How does the query change if the join becomes one-to-many?
How would you handle missing or noisy data in a high-frequency sensor …
How would you handle missing or noisy data in a high-frequency sensor dataset?
Approach
- Check whether any join is one-to-many before aggregating, or the sums inflate.
- Say which table is the grain you start from, and join outward from it.
- State the window function and its partition and ordering out loud before writing it.
Follow-up
- What breaks if events arrive late or out of order?
- How would you verify this result without re-running the same query?
Running commitment burn-down and the date consumption crosses it
fct_subscription_period gives committed_amount_cents, term_start_date and term_end_date for each account's current version where pricing_model = 'committed_consumption'. fct_usage_daily gives account_id, workspace_id, sku_code, usage_date and net_amount_cents, at one row per workspace and SKU per day. Inside each account's current term, return the running total of net_amount_cents by usage_date, the first usage_date on which that running total reaches committed_amount_cents, and the fraction of the term elapsed at that point. Accounts that have not reached their commitment must still appear, with a null crossing date.
Approach
- Collapse usage to one row per (account_id, usage_date) first. The fact is grained by workspace and SKU, so a raw running total leaves several rows per date and the first-crossing date becomes dependent on the arbitrary order of rows inside that day.
- Restrict to the term with usage_date BETWEEN term_start_date AND term_end_date on the account's current row, so no prior term's consumption leaks into this term's burn-down.
- Compute SUM(net_cents) OVER (PARTITION BY account_id ORDER BY usage_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW). Name ROWS explicitly: the default frame is RANGE, which includes all peer rows at the same ORDER BY value and would hand back the whole day's total on each of that day's rows.
- Extract the crossing with MIN(usage_date) FILTER (WHERE running_cents >= committed_amount_cents) grouped per account, which returns NULL for accounts still under commitment instead of dropping them.
- Elapsed fraction is (crossing_date - term_start_date)::numeric / NULLIF(term_end_date - term_start_date, 0); Postgres date subtraction yields whole days, so the guard matters for same-day terms.
- Exclude the trailing days still inside the metering settling window, measured from first_written_at against restated_at, and say how many days you cut and why.
Worked solution 30 min
- Build terms: SELECT account_id, committed_amount_cents, term_start_date, term_end_date FROM fct_subscription_period WHERE is_current AND pricing_model = 'committed_consumption' AND committed_amount_cents IS NOT NULL.
- Build daily: join fct_usage_daily to terms on account_id with usage_date inside the term, then GROUP BY account_id, usage_date summing net_amount_cents.
- Add running_cents with SUM(...) OVER (PARTITION BY account_id ORDER BY usage_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW).
- Aggregate per account with MIN(usage_date) FILTER (WHERE running_cents >= committed_amount_cents) AS crossing_date, then compute the elapsed fraction with the NULLIF guard.
- LEFT JOIN that summary back onto terms so every committed account appears, and verify the last running_cents per account equals a plain SUM over the term.
Follow-up
- Turn this into an end-of-term overage forecast. What breaks if you extrapolate a linear run rate on a consumption product?
- An account crosses its commitment at 40 percent of the term. Is that an expansion signal or a billing-surprise risk, and what would you check to tell them apart?
What are the key performance indicators you would prioritize for a pro…
What are the key performance indicators you would prioritize for a project aimed at reducing operational downtime?
Approach
- Name one primary metric, then the guardrail that stops it being gamed.
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Fix the population and the time window before naming any metric.
Follow-up
- How would you detect that the metric is being gamed rather than genuinely improving?
- Which segment would you cut first, and what would that rule out?
How would you design a product metric to measure the success of a new …
How would you design a product metric to measure the success of a new grid-monitoring tool?
Approach
- Restate the decision this analysis has to support, and who acts on the answer.
- State what result would change your recommendation, so the answer is falsifiable.
- Fix the population and the time window before naming any metric.
Follow-up
- Which segment would you cut first, and what would that rule out?
- What would you do if the primary metric and the guardrail moved in opposite directions?
How do you prioritize tasks when working on multiple high-stakes proje…
How do you prioritize tasks when working on multiple high-stakes projects simultaneously?
Approach
- Fix the population and the time window before naming any metric.
- Restate the decision this analysis has to support, and who acts on the answer.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- How would you detect that the metric is being gamed rather than genuinely improving?
- What would you do if the primary metric and the guardrail moved in opposite directions?
If you notice a sudden metric drop in energy usage reporting, how woul…
If you notice a sudden metric drop in energy usage reporting, how would you go about diagnosing the root cause?
Approach
- Restate the decision this analysis has to support, and who acts on the answer.
- Fix the population and the time window before naming any metric.
- Decompose the metric into the rates that drive it, and say which one you would check first.
Follow-up
- Which segment would you cut first, and what would that rule out?
- What would you do if the primary metric and the guardrail moved in opposite directions?
How do you determine if your results have reached statistical signific…
How do you determine if your results have reached statistical significance?
Approach
- Decide the analysis before seeing data, including how long it runs and when you look.
- Name the randomisation unit first; it decides the variance and what the test can detect.
- Say whether units interfere with each other, and switch design if they do.
Follow-up
- What would you conclude if the result is positive but the test is underpowered?
- How would you handle interference between treated and control units?
What are the common experimentation pitfalls you look for when analyzi…
What are the common experimentation pitfalls you look for when analyzing test results?
Approach
- Name the randomisation unit first; it decides the variance and what the test can detect.
- Name the guardrails that would stop a launch even on a positive primary result.
- Say whether units interfere with each other, and switch design if they do.
Follow-up
- What would you do if you could not randomise at all?
- What would you conclude if the result is positive but the test is underpowered?
Set the operating point for a capacity-bound renewal-risk worklist
A customer-success team of six can contact at most 40 accounts a week. You have an account-level renewal-risk score and the tables behind it: fct_subscription_period (account_id, term_end_date, arr_cents, amendment_type, booked_at, is_current), fct_support_ticket (account_id, severity, reopened_count, breached_sla, linked_incident_id, opened_at) and fct_api_request. Define the metric that grades this worklist, set the operating point, and state what happens to accounts below the line. The team will not use a score they cannot explain, so say how that constrains what you build.
Approach
- Grade the list the way it is used. The team works 40 accounts a week, so the metric is precision at k = 40, not AUC. A global AUC over thousands of accounts rewards correct ordering among accounts nobody will ever call, which is ordering that cannot change an outcome.
- Restrict the candidate pool before ranking anything: accounts whose term_end_date falls within the next 90 days. An account eleven months from renewal cannot churn in the measurement window, so it can occupy a slot in the list while being structurally incapable of producing the outcome.
- Report two numbers because they disagree. Precision at 40 counts accounts; ARR captured at 40 counts money. A list that catches many small churns and misses one large one scores well on the first and badly on the second, so state which the team is optimising before the ranking is built.
- Audit leakage by timestamp, feature by feature. Every feature must carry a timestamp proving it existed before the scoring date: a downgrade amendment's booked_at, a ticket's opened_at, a churn reason code written at close. Drop anything you cannot date, and be specific that reason codes and cancellation amendments are written after the renewal conversation started.
- Attach a policy to the threshold, because a threshold without one is not a decision. Accounts ranked 41 and below get no contact this week; that is an accepted cost, and the weekly readout must include the churn that landed below the line so the operating point can be revisited rather than assumed. Favour a small inspectable model, because a stronger model the team ignores has an effect of zero.
Worked solution 30 min
- Build the weekly candidate set: accounts from the current fct_subscription_period version whose term_end_date falls within 90 days of the scoring date.
- Assemble features only from rows timestamped before the scoring date: trailing 28-day 5xx rate and successful production request volume from fct_api_request, sev1 and sev2 ticket counts plus reopened_count from fct_support_ticket filtered on opened_at, and seat utilisation from the contract version current at that date.
- Label the outcome as the absence of a successor fct_subscription_period row with amendment_type in ('renewal','upsell','downgrade') within 45 days of term_end_date.
- Backtest week by week: take the top 40, and report precision at 40, ARR captured at 40, and the churned ARR that landed below rank 40.
Follow-up
- Coverage is assigned by this list, so contacted and uncontacted accounts differ systematically in exactly the risk signal that drives the outcome. How would you ever measure whether the outreach worked?
- Annual contracts produce few churn events per quarter. At what point is the honest answer that there is not enough signal to model this, and what would you deliver instead?
Consumption per account always dips in the last four days
Your consumption dashboard reads billable units per paying account from fct_usage_daily (account_id, sku_code, usage_date, billable_quantity, net_amount_cents, is_restated, first_written_at, restated_at, updated_at). Every refresh shows the final three to five days declining, and a review is scheduled on that shape. Establish empirically how long a usage_date takes to settle, separately per sku_code, and specify the trailing exclusion window every reported figure should use. Derive the number from the data; do not adopt a convention.
Approach
- Treat settlement as a measurable curve rather than a belief: for each historical usage_date, compare the total captured as of age d days against that date's final settled total.
- Do it per sku_code, because metering paths differ. A per-request SKU lands within hours, while a storage-month SKU is produced by a daily sweep and lands later, so one global lag number is wrong for at least one of them.
- Pick the age at which a stated percentile of dates reaches a stated completeness threshold, for example the tenth percentile date reaching 99.5 percent of final, and take the slowest SKU's age as the dashboard's exclusion window.
- Separate late arrival from restatement. Late rows raise totals and are fixed by waiting; restatements can move either way and are not, so report the share of the gap from each.
- Encode the exclusion inside the query rather than in the chart, so anyone reusing the SQL inherits the rule, and never compare a fresh partial period against a settled one.
Follow-up
- Month-end invoicing needs a number before settlement completes. How would you publish an early estimate with an honest uncertainty band attached?
- What monitor would tell you the settling time has changed, without anyone remembering to re-run this analysis?
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.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Diagnostic, 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.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Largest 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.
Practice prompt ↗Practice prompt ↗Practice prompt ↗03Largest 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.
Practice prompt ↗Practice prompt ↗Practice prompt ↗04Second 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.
Practice prompt ↗Practice prompt ↗Worked solution ↗05The 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.
Practice prompt ↗Practice prompt ↗06Retest 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.
Practice prompt ↗Practice prompt ↗07Full 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.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Data people depend on systems owned by other teams, and much of the job is negotiating for instrumentation, access, or a fix to a broken pipeline. Prepare an example of getting something changed upstream that you did not control. Describe what you asked for, what you traded, and how you worked while you waited.
Tell me about a project where you faced a significant setback; how did…
Tell me about a project where you faced a significant setback; how did you adapt?
Approach
- Close with what you would do differently, concretely.
- 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
- How did you know the outcome was caused by your change?
- What would you do differently if you ran that project again?
Scope an open-ended request to predict account churn
A customer success director asks for a list of accounts about to churn. You know only that the team has six people and that contracts are annual. Available data is fct_subscription_period, fct_usage_daily, fct_api_request, fct_support_ticket and dim_account. Before writing any code, produce the questions you need answered, a proposed definition of about to churn, and the shape of the artefact you would hand back, including the operating point that turns a score into a decision.
Approach
- The interviewer is probing whether you convert a vague request into a decision with a capacity constraint attached. A candidate who starts talking about model families has already failed the exercise.
- Pin the event and the horizon first. Churn is only possible at term_end_date, so the population is accounts renewing in the next 60 to 90 days, not the whole base. Ask explicitly whether contraction and downgrade count as churn or only full non-renewal, because the three have different base rates and different interventions.
- Pin the action and the capacity. Six people times a realistic number of meaningful interventions per week gives k, and k is what the list is ranked to. Evaluate on precision at k rather than a global AUC over accounts that will never be contacted.
- Audit leakage before choosing features. Every feature needs a timestamp proving it existed before the prediction date. A downgrade amendment, a churn reason code, and a ticket opened after the renewal conversation started are all leaks that will make the offline number look excellent and the live list useless.
- Ask for the counterfactual now rather than later. Coverage is assigned deliberately, so without a held-out slice agreed at the start the intervention can never be evaluated, and you will be asked for its impact in nine months regardless.
- Propose the smallest artefact that closes the loop: a weekly ranked list sized to capacity with two or three inspectable reasons per row, plus a stated policy for accounts below the line.
Follow-up
- The director insists all accounts are in scope, not only those renewing soon. How do you answer without simply refusing?
- Historical non-renewals number about 30 a year. At what point do you tell them a model is the wrong tool and a rules list is better?
- Which candidate features would you drop purely because you cannot date them?
Walk through an analysis you later discovered was wrong
Six weeks ago you reported that consumption fell 9 percent in the last week of the month, and a team spent a sprint investigating the cause. The fall was an artefact: rows in fct_usage_daily land late and are restated in place, and you queried before the tail had settled. Describe how you found the error, what you told the people who acted on it, and the control you put in place so this class of mistake cannot reach a dashboard again. Be specific about how the settling window was measured.
Approach
- The interviewer is probing whether you self-report errors before someone else finds them, and whether your fix is structural rather than a promise to be more careful. Say plainly that the number was wrong and that a sprint was spent on it, before describing any diagnosis.
- Establish the artefact quantitatively instead of asserting that data lands late. For each usage_date, compare the total as of first_written_at against the settled total and read the settling time off that curve, for example 97 percent of final by day three and 99.5 percent by day five.
- Correct the record the same day, in the channel the original number went out in, to the same audience. The cost of the wasted sprint belongs in the correction, not in a footnote.
- Make the fix structural: exclude a trailing lag window from every reportable figure, and make the reporting view return no rows inside that window rather than returning partial ones. A dashboard that shades unsettled days still gets read as a decline.
- State what generalises. Any fact table restated in place has this failure mode, so the guard belongs at the source rather than on the one dashboard that embarrassed you. A strong answer ends with the class of error closed; a generic one ends with a lesson learned.
Follow-up
- How did you choose the completeness threshold behind the lag window, and what would make you recalibrate it?
- What did you say to the team that lost the sprint, and what did they say back?
- Is there a legitimate case for showing the unsettled tail at all, and to whom?
- 01
Tell me about a project where you faced a significant setback; how did you adapt?
- 02
A customer success director asks for a list of accounts about to churn. You know only that the team has six people and that contracts are annual. Available data is fct_subscription_period, fct_usage_daily, fct_api_request, fct_support_ticket and dim_account. Before writing any code, produce the questions you need answered, a proposed definition of about to churn, and the shape of the artefact you would hand back, including the operating point that turns a score into a decision.
- 03
Six weeks ago you reported that consumption fell 9 percent in the last week of the month, and a team spent a sprint investigating the cause. The fall was an artefact: rows in fct_usage_daily land late and are restated in place, and you queried before the tail had settled. Describe how you found the error, what you told the people who acted on it, and the control you put in place so this class of mistake cannot reach a dashboard again. Be specific about how the settling window was measured.
Is this an official Pacific Gas and Electric interview guide?
No. It is PracHub's own research and practice material for the Data Scientist role at Pacific Gas and Electric. Rounds and questions reflect what candidates have reported, not a process Pacific Gas and Electric has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How long does the typical interview process take?
The process timeline can vary, but generally, you can expect the cycle from initial screen to final decision to take several weeks. Stay in close contact with your recruiter regarding the specific timeline for the team you are interviewing with.
PracHub interview research ↗What is the most important thing to emphasize during my interview?
Focus on the impact of your work. Pacific Gas and Electric interviewers value candidates who can explain not just how they solved a technical problem, but why that solution was the best choice for the business and the end-user.
PracHub interview research ↗How technical are the interviews?
The technical bar is high, particularly for SQL and statistics. Expect to be tested on your ability to apply these concepts to practical, real-world data scenarios rather than just theoretical definitions.
PracHub interview research ↗Sources & methodology 3 sources ↗
No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
PracHub page · Accessed 2026-09-22 - 02PracHub Data Scientist practice ↗
Cross-company practice questions for this role.
PracHub page · Accessed 2026-09-22 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
PracHub page · Accessed 2026-09-22