← Amazon Interview Insights

Amazon·Data Scientist·Technical Phone Screen·Intermediate

Intermediate
Jun 2026

Summary

Amazon Data Scientist technical screen, heavy pandas focus with four interconnected sub-problems on the same small dataset. No behavioral stuff at all, just code and complexity analysis the whole time.

Questions Asked (4)

Q1

Using only pandas (groupby, agg, merge, concat, no for-loops), compute Daily Active Users per device from an events table, then calculate a 2-day rolling unique user count per device aligned to day end. How do you guarantee uniqueness across days in the rolling window?

Product Analytics & MetricsTechnical Trade-offs
Author's notes

The rolling uniqueness part tripped me up.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, compute daily active users per device by grouping events by date and device, then aggregating unique user IDs. Next, for the rolling 2-day unique user count, use a self-merge on consecutive dates (or a rolling window with a set-based aggregation) to combine user sets, then count distinct users. Emphasize that uniqueness across days requires set union, not sum, and that pandas' nunique on concatenated groups ensures deduplication.

Pro tip: Mention that while pandas' rolling().apply() can work, it's slow for large data; a self-merge on date and date-1 followed by groupby nunique is more efficient and scalable. Also, clarify that 'aligned to day end' means the window includes the current day and the previous day, so the rolling count for day D is the unique users from D-1 and D.

1. Compute Daily Active Users (DAU) per device

Group the events DataFrame by date and device, then aggregate unique user IDs using nunique. This yields a DataFrame with one row per date-device pair and the DAU count.

2. Prepare for rolling unique count

To compute a 2-day rolling unique user count, you need the actual sets of users per day, not just counts. Create a DataFrame where each row contains the date, device, and a set (or list) of unique user IDs for that day.

3. Merge consecutive days

Perform a self-merge on device where the right date equals the left date minus one day (or use a rolling window). This pairs each day with its previous day for the same device.

4. Compute unique users across the window

For each merged pair, combine the user sets (e.g., using set union) and count the distinct users. This gives the 2-day rolling unique user count aligned to the current day (day end).

5. Handle edge cases and finalize

For the first day, the rolling count is just the DAU of that day. Ensure the output is sorted by device and date, and that the rolling count is correctly aligned to day end.

Key Points to Mention

  • Uniqueness across days requires set union (or nunique on concatenated user IDs), not summing daily counts.
  • Use groupby with nunique to compute DAU per device per day.
  • For rolling unique count, avoid for-loops by using merge or rolling with a custom function that returns the size of the union of user sets.
  • Align the rolling window to day end: the 2-day window for day D includes D-1 and D.
  • Edge case: the first day has no previous day, so the rolling count equals the DAU of that day.
  • Scalability: consider memory usage when storing user sets; for large data, a self-merge and groupby nunique on user IDs may be more efficient.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Left-join the users table to each user's first order, producing a first_order_ts column and a days_to_first_order column as a float. Users with no orders should show NaN. How do you handle users who signed up and placed their first order on the same day?

Data ModelingTechnical Trade-offs
Author's notes

Pretty clean once you get the first-order aggregation right.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining the SQL logic: use a LEFT JOIN from users to orders, then filter to each user's first order using a window function or subquery. Address the same-day edge case by clarifying that days_to_first_order should be 0.0 (not NaN) when signup and first order occur on the same date, and explain how to compute the difference in days as a float.

Pro tip: Mention that you would validate the join by checking for duplicate first orders per user and confirm that users with no orders correctly show NaN, as this demonstrates attention to data quality and edge cases.

1. Clarify requirements and edge cases

Confirm that days_to_first_order is the difference in days between signup and first order, and that same-day signup and order should yield 0.0 days, not NaN. Also confirm that users with no orders should have NaN for both first_order_ts and days_to_first_order.

2. Identify each user's first order

Use a subquery with ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_ts) = 1, or a correlated subquery with MIN(order_ts), to select the earliest order per user.

3. Perform the LEFT JOIN

LEFT JOIN the users table to the first-order subquery on user_id, ensuring all users are retained. Users without orders will have NULL for first_order_ts.

4. Compute days_to_first_order as float

Calculate the difference in days between first_order_ts and signup_ts, casting to float. For same-day signup and order, the difference is 0.0; for users with no orders, it remains NaN (NULL).

5. Validate and handle edge cases

Check that each user has at most one first order, and that same-day cases produce 0.0. Ensure NaN is represented correctly (e.g., NULL in SQL, NaN in pandas) and consider timezone consistency.

Key Points to Mention

  • Use of LEFT JOIN to retain all users, including those with no orders.
  • Window function (ROW_NUMBER) or MIN aggregation to identify the first order per user.
  • Same-day signup and first order should yield days_to_first_order = 0.0, not NaN.
  • Users with no orders should have NaN for first_order_ts and days_to_first_order.
  • Casting the day difference to float to match the required output type.
  • Potential timezone or timestamp precision issues when computing day differences.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

For each user, find their top 2 spending categories by total amount. Ties should be broken alphabetically. Return columns top_cat_1 and top_cat_2, with NaN for users who have fewer than 2 distinct categories.

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

This one took me the longest.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the problem: we need to aggregate spending per user and category, rank categories by total amount descending with alphabetical tie-breaking, and pivot to get the top two. Then outline an efficient solution using window functions or groupby with rank, and handle edge cases like users with fewer than two categories by filling with NaN.

Pro tip: Mention that you would verify the solution on edge cases such as users with exactly two categories, ties in spending, and users with only one category, and discuss how to scale the approach for large datasets using distributed computing if needed.

1. Clarify requirements and edge cases

Confirm the definition of 'top categories' (by total spending), tie-breaking rule (alphabetical), and output format (NaN for missing). Ask about data size and distribution to guide implementation choices.

2. Aggregate spending per user and category

Group the data by user and category, summing the spending amounts to get total per user-category pair.

3. Rank categories within each user

For each user, rank categories by total spending descending, with alphabetical order as tie-breaker. Use window functions (e.g., ROW_NUMBER or RANK) or sort and enumerate.

4. Extract top 2 and pivot to wide format

Filter to ranks 1 and 2, then pivot so each user has one row with columns top_cat_1 and top_cat_2. Ensure users with fewer than 2 categories get NaN in the missing column.

5. Validate and discuss scalability

Test on edge cases (ties, single category, no spending). Discuss how the approach can be adapted for large-scale data using tools like Spark or by optimizing with window functions.

Key Points to Mention

  • Use of GROUP BY for aggregation and window functions (e.g., ROW_NUMBER) for ranking within groups.
  • Handling ties correctly by ordering by total spending descending and category name ascending.
  • Pivoting or conditional aggregation to transform ranked results into top_cat_1 and top_cat_2 columns.
  • Ensuring users with fewer than 2 distinct categories receive NaN in the missing column.
  • Considering performance implications for large datasets and potential distributed solutions.
  • Validating the solution with edge cases such as ties, single category, and users with no spending.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

You have a per-device daily revenue table with columns day, device, and revenue. Add a summary row labeled 'ALL' that shows total revenue across all devices for each day, then concat it back to the original table. How do you make sure column types stay consistent after the concat?

Data ModelingTechnical Trade-offs
Author's notes

Straightforward groupby-agg to get the ALL rows, set device to the string 'ALL', then pd.concat.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining the SQL steps: compute daily totals with GROUP BY, label them as 'ALL', then UNION ALL with the original table. Emphasize that column types must match exactly, so explicitly cast the device column to string and ensure revenue is numeric in both parts.

Pro tip: Mention that using UNION ALL instead of UNION avoids unnecessary deduplication and preserves performance, and always verify types with a DESCRIBE or information_schema query after the operation.

1. Aggregate daily totals

Use a GROUP BY on day to sum revenue across all devices, and add a literal 'ALL' as the device value.

2. Ensure type consistency

Explicitly cast the device column in the original table to STRING (or VARCHAR) and confirm revenue is the same numeric type in both parts.

3. Combine with UNION ALL

Use UNION ALL to concatenate the original table with the summary rows, preserving all rows and avoiding deduplication overhead.

4. Validate output

Check the resulting schema and sample rows to confirm column types and that the 'ALL' rows are correctly placed.

Key Points to Mention

  • Use UNION ALL instead of UNION to avoid deduplication and improve performance.
  • Explicitly cast the device column to string to match the 'ALL' literal.
  • Ensure revenue is numeric (e.g., DECIMAL or DOUBLE) in both parts of the union.
  • Consider using a subquery or CTE for clarity and maintainability.
  • Validate column types after the operation using DESCRIBE or information_schema.
  • Be aware of potential NULLs or type mismatches that could cause errors.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.