Pandas vs NumPy in Python

Practice Python for data interviews
200+ pandas, numpy, and data-wrangling problems with explanations.
Join the waitlist

Why this comparison matters

You opened a Jupyter notebook, ran import pandas as pd and import numpy as np on autopilot, and now your manager is asking why your group-by takes eight minutes on a 12M-row file. The honest answer is usually that you reached for the wrong tool. NumPy is a numerical engine for homogeneous arrays. Pandas is a tabular toolkit built on top of NumPy — labeled axes, missing-value handling, groupby, joins, resampling. Confuse the two and you either pay a 10x performance tax or write loops that NumPy would have vectorized in one line.

This post is for analysts and interviewers who want a load-bearing mental model, not a wiki dump. We will compare data structures, benchmark a typical workload, walk through real interview questions, and flag the pitfalls that bite people in production.

If your day-to-day is mostly CSVs, joins, and aggregations, you live in Pandas. If it is matrix multiplies, image arrays, or simulation loops, you live in NumPy. Most analysts touch both in a single workflow.

What NumPy actually is

NumPy (short for Numerical Python) is the foundation of scientific computing in Python. Its core object is the ndarray — an n-dimensional, fixed-type, contiguous block of memory. That last phrase is doing all the work: contiguous memory plus a single dtype means CPU-level operations (SIMD, cache locality, no Python object overhead per cell).

import numpy as np

arr = np.array([1, 2, 3, 4, 5])
print(arr.mean())           # 3.0
print(arr * 2)              # [2 4 6 8 10]

matrix = np.array([[1, 2], [3, 4]])
print(matrix.sum(axis=0))   # [4 6] — column sums

A NumPy operation like arr * 2 does not loop in Python. It dispatches a single C call that walks the buffer. For a 10M-element float64 array, that is roughly 80 MB of contiguous RAM processed in a single tight loop — orders of magnitude faster than a Python for loop.

What Pandas actually is

Pandas gives you two main structures: the Series (a labeled 1-D array) and the DataFrame (a 2-D table where columns can have different dtypes). Unlike NumPy, you get named axes, missing-value semantics (NaN, NaT, pd.NA), and a huge surface area of methods: groupby, merge, pivot_table, resample, rolling, read_csv, read_parquet, to_sql.

import pandas as pd

df = pd.DataFrame({
    "name":   ["Anna", "Boris", "Vika"],
    "age":    [25, 30, 28],
    "salary": [80000, 120000, 95000],
})

print(df.groupby("age")["salary"].mean())
print(df[df["salary"] > 90000])

The price you pay for that ergonomics is overhead per row, per column, and per operation. A groupby().agg() on a billion rows in Pandas is possible but painful — you would push that to SQL or Spark.

Load-bearing mental model: NumPy is a fast numerical buffer. Pandas is an Excel-shaped analyst toolkit that happens to use NumPy buffers under the hood.

Key differences at a glance

Dimension NumPy Pandas
Core structure ndarray (n-dim array) DataFrame (table) and Series (column)
Dtype model Homogeneous — one dtype per array Heterogeneous — different dtype per column
Indexing Positional / integer-based Labeled rows and columns plus positional iloc
Missing values Limited (NaN floats only) First-class (NaN, NaT, pd.NA, fillna)
Group-by / pivot Not built-in groupby, pivot_table, crosstab
File I/O loadtxt, genfromtxt, save CSV, Excel, Parquet, JSON, SQL, Feather, HDF5
Time series Manual to_datetime, resample, rolling, offsets
Memory per cell One C-typed value One C-typed value plus index/column metadata
Typical speed Faster on pure math Slower per op, but expressive in one line
Common downstream scikit-learn, OpenCV, PyTorch, SciPy BI, reporting, SQL exports, dashboards

The honest summary: NumPy is faster, Pandas is more useful for analysts. Reach for NumPy when the data is numeric and uniform; reach for Pandas when the data is tabular and messy.

When to reach for NumPy

NumPy is the right tool when you have a numeric, homogeneous workload and you care about microseconds per row. The classic cases:

  • Vectorized arithmetic on prices, returns, weights, probabilities.
  • Linear algebra — matrix multiply, eigenvalues, least squares.
  • Image and signal processing, where the input is already a (H, W, 3) uint8 array.
  • Monte Carlo simulation and any code path that generates millions of random draws via np.random.
  • Custom numerical kernels that you will hand to scikit-learn or PyTorch downstream — they expect arrays, not DataFrames.
# Vectorized discount across a price list
prices = np.array([100, 200, 150, 300])
discounted = prices * 0.9          # [ 90. 180. 135. 270.]

# Solve a small linear system Ax = b
A = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
x = np.linalg.solve(A, b)

If you ever find yourself writing a Python for i in range(len(df)): loop over a DataFrame column, stop and ask whether the column is numeric — if yes, that work belongs in NumPy or in a vectorized Pandas expression.

When to reach for Pandas

Pandas is the right tool when your data looks like a spreadsheet or a database table, and the operations you want are joins, group-bys, filters, sorts, and time-window aggregations.

  • Exploratory data analysis on a fresh CSV or Parquet pull.
  • Cleaning — type casting, deduplication, fillna, normalization.
  • Group-by + agg across user, cohort, country, channel.
  • Joins between an orders table and a users table.
  • Time-series resampling — daily orders rolled up to monthly revenue.
# A typical analyst pipeline
orders = pd.read_csv("orders.csv")
monthly = (
    orders
    .assign(month=pd.to_datetime(orders["date"]).dt.to_period("M"))
    .groupby("month")["revenue"]
    .agg(["sum", "count", "mean"])
)

The expressiveness is the value. The same logic in pure NumPy would be a multi-step ordeal involving sort keys and bin counts.

Practice Python for data interviews
200+ pandas, numpy, and data-wrangling problems with explanations.
Join the waitlist

Pandas is built on NumPy

Every Pandas column is backed by a NumPy array (or, increasingly, a PyArrow extension array). You can drop down to the raw buffer whenever you want:

df = pd.DataFrame({"a": [1, 2, 3]})
arr = df["a"].to_numpy()   # numpy.ndarray

This matters in two places. First, when a Pandas operation is slow, you can sometimes rewrite the hot path with to_numpy() and a vectorized NumPy expression to skip the per-row dispatch overhead. Second, when a downstream library (scikit-learn, PyTorch, SciPy) asks for an array, you do not need a converter — .to_numpy() is the bridge.

Sanity check: If you can express the operation as a single math formula over a numeric column, NumPy will be faster. If you need labels, joins, or mixed dtypes, stay in Pandas.

Common pitfalls

When analysts first switch between the two libraries, the most common mistake is using a Python for loop over df.iterrows() for arithmetic that NumPy could vectorize in one line. A row-wise loop over a million-row frame can take 30 seconds; the vectorized form runs in under 200 ms. The fix is to think in columns: every operation that touches a whole column should be a single expression, not a loop.

A second trap is object dtype creeping into a numeric column. The moment one cell contains "N/A" instead of a number, Pandas downgrades the entire column to object, and all numeric methods either fail or fall back to slow Python loops. Always check df.dtypes after a read_csv, coerce with pd.to_numeric(..., errors="coerce"), and confirm the column is float64 or int64 before you benchmark anything.

The third pitfall is chained assignmentdf[df.col == x]["other"] = y. This is the original sin that triggers the famous SettingWithCopyWarning and, more importantly, silently fails to modify the original frame. Use df.loc[df.col == x, "other"] = y instead. Anyone who has spent an afternoon debugging a "nothing changed" bug remembers this one.

Pitfall four is mixing index alignment with positional thinking. When you do series_a + series_b, Pandas aligns on the index, not on position. If series_a is indexed by user_id and series_b by integer row number, you will get a frame of NaN. NumPy never does this — it is strictly positional. The fix is to drop or reset indexes before arithmetic when alignment is not what you want, or to use .values / .to_numpy() to force positional behavior.

Finally, the inplace=True myth. Most users assume inplace=True is faster because it "skips the copy". In modern Pandas it often is not, and the keyword is being deprecated in many places. Prefer reassignment: df = df.dropna(). It is clearer and plays nicely with method chaining.

Performance: a small benchmark

A concrete picture beats hand-waving. Below is a typical analyst workload — computing the mean of a numeric column with 10M float64 values — across three approaches on a modern laptop.

Approach Time (approx) Memory
Python sum(x) / len(x) over a list ~1,200 ms high
df["x"].mean() in Pandas ~45 ms medium
arr.mean() in NumPy ~25 ms lowest

NumPy wins on pure math by roughly 1.5–2x over Pandas and by 40x over a pure-Python loop. The Pandas overhead comes from index handling and dispatch through the block manager. For most analyst work that overhead is irrelevant; the ergonomic gain dominates. For tight inner loops in production code, it matters a lot.

The shape of the result also matters: if you need the answer grouped by a key, Pandas wins because NumPy has no built-in groupby and you would otherwise reach for np.unique + np.bincount gymnastics.

Interview questions you will hear

These are the three questions that come up almost every time the topic appears on a data analyst loop.

"When do you choose NumPy over Pandas?" When the data is homogeneous, numeric, and the operation is math-heavy — vectorized arithmetic, linear algebra, simulation. For tabular analysis with labels and mixed types, Pandas wins on readability and built-in methods.

"Why is NumPy faster?" Three reasons. The data is stored in a single contiguous C array with a fixed dtype, so the CPU can stream it through cache. Operations are dispatched as one C call instead of a Python interpreter loop. And vectorized math hits SIMD instructions on modern CPUs.

"Can you convert a DataFrame to a NumPy array?" Yes — df.to_numpy() (preferred) or the legacy df.values. The result loses column labels and is forced into a common dtype. If columns have mixed dtypes, NumPy will upcast to object, which kills performance — so usually you convert one numeric column at a time.

If you want to drill questions like these every day with feedback, the NAILDD app is launching with a structured library of Python and SQL problems built around exactly this kind of interview pattern.

FAQ

Do I need NumPy if I only use Pandas?

In practice, yes. Pandas is built on NumPy, and the moment you do anything non-trivial — custom math on a column, working with scikit-learn, handling images, or optimizing a slow hot path — you end up calling NumPy functions directly. You do not need to memorize the whole API, but you should be comfortable with array creation, dtypes, broadcasting, and a handful of functions like np.where, np.clip, np.log1p, and np.percentile.

Is SQL faster than Pandas for group-by?

On large data, almost always yes. A modern columnar warehouse like BigQuery, Snowflake, or ClickHouse will outperform single-machine Pandas on multi-million-row group-bys by a wide margin, because the work is parallelized across many cores and the data is already columnar on disk. Pandas wins for interactive exploration on local data and for the parts of a pipeline that need fancy Python logic between aggregations.

Should I just learn Polars and skip Pandas?

Polars is fast, has a cleaner API, and is genuinely worth learning for new projects. But interviewers still ask about Pandas because that is the library in most existing codebases — every analyst notebook, every legacy ETL, every Kaggle solution. Learn Pandas as the baseline, then add Polars as a performance upgrade.

How do I handle missing values in NumPy vs Pandas?

NumPy supports NaN only for float arrays — integer arrays cannot hold missing values without being upcast. Pandas handles missing values across all dtypes via NaN, NaT, and the newer nullable extension dtypes plus pd.NA. For analyst work, prefer Pandas semantics; for pure numeric work, filter or impute missing values before the data hits NumPy.

What is the memory difference for a million-row column?

A float64 NumPy array of 1M values is exactly 8 MB. The same column inside a Pandas DataFrame adds index overhead, typically landing around 8–9 MB. The difference is small until you have hundreds of columns or non-numeric dtypes. object columns (strings as Python objects) are the real memory hogs — switch them to category or string[pyarrow] when memory is tight.

Which one should I list on my resume?

Both, but be specific. "Pandas" alone is generic — "Pandas for cohort retention on 50M-row event tables with groupby and Parquet I/O" is what hiring managers want to see. Mention NumPy only if you used it for something concrete (vectorized feature engineering, simulation, image work).