← Two Sigma Interview Insights

Two Sigma·Data Scientist·Technical Phone Screen·Senior

Senior
Sep 2025Remote

Summary

Two Sigma data scientist round, heavy on vectorized pandas and SQL. The whole thing was basically one long coding problem about NYC taxi data with a few sub-tasks layered inside it. More math-y than I expected for a DS role.

Questions Asked (4)

Q1

Given trips and zones datasets, join them on pickup zone, then compute median trip speed (mph) per borough and hour of day. Filter to trips where duration is between 1 and 120 minutes and speed is between 1 and 80 mph. Return the top 3 (borough, hour) pairs by median speed, breaking ties by borough then hour alphabetically.

Product Analytics & MetricsAlgorithms & Data StructuresData Modeling
Author's notes

The filtering part seemed easy but I almost forgot to convert duration to hours before computing speed.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the schema and join keys, then outline a step-by-step pipeline: join trips to zones on pickup location ID, compute speed as distance/duration with unit conversion, filter invalid trips, and aggregate median speed by borough and hour. Finally, sort and select the top 3 with the specified tie-breaking rules, and discuss how you would validate the results.

Pro tip: Mention that median is more robust to outliers than mean, and explicitly state your unit conversions (e.g., miles per hour from distance in miles and duration in minutes). Also, note that hour of day should be extracted from the pickup timestamp, not drop-off, to align with the pickup zone join.

1. Clarify schema and join keys

Confirm the column names and data types in both datasets, especially the pickup zone ID in trips and the zone ID in zones. Ensure the join is on pickup zone to get the borough for each trip.

2. Compute speed and apply filters

Calculate speed as trip_distance divided by (duration_minutes / 60) to get mph. Filter trips to duration between 1 and 120 minutes and speed between 1 and 80 mph, handling any nulls or invalid values.

3. Extract hour and aggregate median speed

Extract the hour of day from the pickup timestamp. Group by borough and hour, then compute the median speed for each group.

4. Sort and select top 3

Sort the aggregated results by median speed descending, then by borough ascending, then by hour ascending. Select the first 3 rows.

5. Validate and discuss edge cases

Check for missing boroughs, empty groups, or unexpected values. Discuss how you would handle ties beyond the top 3 and whether the results make sense.

Key Points to Mention

  • Join trips to zones on pickup location ID to map to borough.
  • Compute speed as distance / (duration / 60) to convert minutes to hours.
  • Filter duration between 1 and 120 minutes and speed between 1 and 80 mph.
  • Use median (not mean) for speed aggregation to reduce outlier impact.
  • Extract hour from pickup timestamp, not drop-off.
  • Sort by median speed descending, then borough ascending, then hour ascending for tie-breaking.

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

Q2

For Manhattan pickups between midnight and 5am, find the 3 taxi IDs with the highest 95th percentile trip duration in minutes. Break ties by taxi_id ascending. Define clearly how you compute the 95th percentile.

Product Analytics & MetricsAlgorithms & Data Structures
Author's notes

I said I'd use numpy's percentile with interpolation='linear' which is the pandas default for quantile(0.95).

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the definition of 95th percentile (e.g., linear interpolation) and confirm the time window and location. Then, filter trips to Manhattan pickups between midnight and 5am, group by taxi_id, compute the 95th percentile of trip duration for each taxi, and select the top 3 by percentile value, breaking ties by taxi_id ascending.

Pro tip: Mention that you would validate the percentile calculation with a small sample or use a built-in function to ensure consistency, and discuss how to handle taxis with very few trips (e.g., requiring a minimum number of trips to avoid noise).

1. Clarify requirements and definitions

Confirm the definition of 'Manhattan pickups' (e.g., using pickup location IDs or coordinates) and the exact time window (midnight to 5am, inclusive/exclusive). Explicitly state the method for computing the 95th percentile (e.g., linear interpolation as in numpy's default).

2. Filter and preprocess data

Filter the dataset to include only trips with Manhattan pickups and pickup times between 00:00 and 05:00. Ensure trip duration is in minutes and handle any missing or invalid values.

3. Group and compute percentile

Group the filtered data by taxi_id and compute the 95th percentile of trip duration for each taxi. Consider setting a minimum trip count threshold to ensure statistical reliability.

4. Rank and select top 3

Sort the taxis by their 95th percentile duration in descending order. For ties, sort by taxi_id ascending. Select the top 3 taxi IDs.

5. Validate and present results

Validate the results by checking for anomalies (e.g., extremely high percentiles due to outliers) and present the final list with the computed percentiles.

Key Points to Mention

  • Definition of 95th percentile: specify the method (e.g., linear interpolation) and why it matters for consistency.
  • Handling of small sample sizes: discuss whether to include taxis with few trips and potential impact on percentile stability.
  • Data filtering: how to identify Manhattan pickups (e.g., using location IDs or latitude/longitude boundaries).
  • Time window: clarify if midnight and 5am are inclusive or exclusive, and how to handle trips spanning the boundary.
  • Tie-breaking: explicitly state the tie-breaking rule (taxi_id ascending) and ensure it's applied after sorting by percentile.
  • Scalability: mention efficient computation for large datasets (e.g., using groupby and percentile functions in pandas or SQL).

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

Q3

Write the full pandas implementation for the above analyses in O(n log n) or better. Requirements: no row-level Python loops, parsed datetime dtypes, a single join performed once, categorical dtype for borough, and indexing on pickup_ts for time filtering.

Algorithms & Data StructuresTechnical Trade-offsData Modeling
Author's notes

The categorical dtype requirement caught me a bit flat-footed.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, restate the analyses and confirm the constraints (no row-level loops, parsed datetimes, single join, categorical borough, indexed pickup_ts). Then outline a vectorized pandas pipeline: load and parse, set index, join once, and compute aggregations using groupby/merge operations. Finally, write the code with comments explaining how each requirement is met and the time complexity.

Pro tip: Mention that setting the datetime index before filtering enables fast time-based slicing and that using categorical dtype for borough reduces memory and speeds up groupby operations. Also, note that a single join should be done after all necessary filtering to minimize data movement.

1. Clarify requirements and data schema

Confirm the analyses needed, the input data columns, and the constraints. Identify the join key and the time column for indexing.

2. Load and preprocess data

Read data with appropriate dtypes, parse datetime columns, convert borough to categorical, and set pickup_ts as the index.

3. Perform time-based filtering

Use the datetime index to filter rows for the required time period efficiently, avoiding row-wise operations.

4. Execute a single join

Merge the filtered data with the other dataset once, using an appropriate join type and ensuring the join key is optimized.

5. Compute analyses with vectorized operations

Use groupby, aggregation, and other vectorized pandas methods to compute the required metrics, ensuring no Python loops.

Key Points to Mention

  • Use pd.to_datetime with format specification for fast parsing and memory efficiency.
  • Set pickup_ts as index using set_index to enable fast time-based slicing (e.g., .loc['2023-01-01':'2023-01-31']).
  • Convert borough to categorical dtype to reduce memory and speed up groupby operations.
  • Perform a single merge/join after filtering to minimize the size of the joined dataset.
  • Avoid row-level loops by using vectorized operations like groupby, agg, and transform.
  • Ensure the overall time complexity is O(n log n) or better, often achieved by sorting (for joins) and vectorized computations.

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

Q4

Justify two specific memory or performance optimizations in your implementation, such as downcasting numeric columns or doing groupby-agg in a single pass instead of multiple passes.

Technical Trade-offsAlgorithms & Data Structures
Author's notes

I went with downcasting int64 columns to int32 where values were small, and doing the quantile aggregation in a single groupby pass rather than computing mean and median separately.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Choose two optimizations that you actually implemented, and for each, explain the problem, the optimization, and the measured impact. Focus on the trade-offs and why the optimization was worth it in your specific context.

Pro tip: Quantify the impact with concrete numbers (e.g., 'reduced memory by 60%' or 'sped up runtime by 3x') and mention any trade-offs you accepted, such as increased code complexity or reduced readability.

1. Set the context

Briefly describe the problem or dataset that motivated the optimization, including scale and performance bottlenecks.

2. Explain the optimization

Detail the specific optimization, such as downcasting numeric columns to smaller dtypes or combining multiple groupby-agg operations into a single pass.

3. Quantify the impact

Provide concrete metrics showing the improvement, such as memory reduction percentage or speedup factor.

4. Discuss trade-offs

Acknowledge any downsides, like potential precision loss from downcasting or increased code complexity, and why the trade-off was acceptable.

5. Generalize the lesson

Summarize when and why this optimization is applicable, showing broader understanding.

Key Points to Mention

  • Memory profiling tools (e.g., pandas .info(), memory_usage()) to identify optimization opportunities
  • Downcasting numeric columns (e.g., float64 to float32, int64 to int32) and its impact on memory and precision
  • Single-pass groupby-agg using .agg() with multiple functions or dictionary aggregation to avoid multiple passes over data
  • Performance measurement (e.g., timeit, cProfile) to validate optimizations
  • Trade-offs between memory usage, speed, and code maintainability
  • Scalability implications for larger datasets or production environments

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