The Data Science Stack at a Glance

This cheat sheet condenses the most-used patterns of the Python data science stack into copy-ready snippets. NumPy provides fast n-dimensional arrays and vectorized math; pandas adds labeled tabular data structures for loading, cleaning, and transforming; matplotlib and seaborn handle visualization; scipy and statsmodels cover statistics; and scikit-learn standardizes machine learning. Every snippet below uses real, runnable syntax — scan to the section you need and copy.

Python data science code on screen

Imports & Setup

The conventional aliases used throughout every snippet below

Standard import aliases. Stick to these names — most documentation, Stack Overflow answers, and notebooks assume them.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Optional display tweaks for notebooks
pd.set_option("display.max_columns", 50)
pd.set_option("display.width", 120)
sns.set_theme(style="whitegrid")   # applies seaborn styling to matplotlib
%matplotlib inline                 # in Jupyter only

Check versions with np.__version__ and pd.__version__. Use a virtual environment and install with pip install numpy pandas matplotlib seaborn scikit-learn scipy statsmodels.

NumPy: Arrays & Vectorized Math

Fast n-dimensional arrays, indexing, broadcasting, and aggregations

Creating Arrays

a = np.array([1, 2, 3])             # 1-D from list
M = np.array([[1, 2], [3, 4]])      # 2-D from nested list
np.zeros((2, 3))                    # 2x3 of 0.0
np.ones((3,))                       # 1-D of 1.0
np.full((2, 2), 7)                  # filled with 7
np.eye(3)                           # 3x3 identity
np.arange(0, 10, 2)                 # [0 2 4 6 8]
np.linspace(0, 1, 5)                # 5 evenly spaced 0..1
np.random.default_rng(42).normal(0, 1, size=(2, 3))  # random normals

Shape & Reshape

a.shape        # (3,)        tuple of dimensions
a.ndim         # 1           number of axes
a.size         # 3           total elements
a.dtype        # dtype('int64')
M.reshape(4, 1)        # to 4x1; -1 infers a dimension: M.reshape(-1)
M.ravel()              # flatten to 1-D (view if possible)
M.T                    # transpose
np.expand_dims(a, 0)   # add a new axis -> shape (1, 3)

Indexing & Slicing

a[0]            # first element
a[-1]           # last element
a[1:3]          # slice (stop exclusive)
M[0, 1]         # row 0, col 1
M[:, 0]         # all rows, column 0
M[1, :]         # row 1, all columns
a[a > 1]        # boolean mask filtering
M[[0, 1], [0, 1]]   # fancy indexing -> [M[0,0], M[1,1]]

Vectorized Operations & Broadcasting

a + 10          # element-wise scalar add (broadcasts)
a * 2           # element-wise multiply
a ** 2          # element-wise power
np.sqrt(a)      # ufunc applied element-wise
M.dot(a[:2])    # matrix-vector product (or M @ a[:2])
# Broadcasting: shapes align from the trailing axis
M + np.array([10, 20])   # adds row vector to each row

Prefer vectorized ops over Python loops — they run in compiled C and are often 10-100x faster.

Aggregations

a.sum()             # total
a.mean()            # average
a.std()             # standard deviation (ddof=0 by default)
a.min(), a.max()    # extremes
a.argmax()          # index of max
M.sum(axis=0)       # column sums (collapse rows)
M.sum(axis=1)       # row sums (collapse columns)
np.median(a)        # median
np.percentile(a, 75)   # 75th percentile

np.where & Conditionals

np.where(a > 1, "big", "small")     # vectorized if/else
np.where(a > 1)                     # indices where condition is True
np.clip(a, 0, 2)                    # bound values into [0, 2]
np.unique(a, return_counts=True)    # distinct values + counts
np.isnan(M)                         # element-wise NaN mask

pandas: Creating & Loading Data

Building DataFrames and reading files

# From a dict of columns
df = pd.DataFrame({
    "name": ["Ana", "Ben", "Cara"],
    "age": [23, 35, 29],
    "city": ["NY", "LA", "NY"],
})

# From a list of records (rows)
df = pd.DataFrame([{"a": 1, "b": 2}, {"a": 3, "b": 4}])

# Read from files
df = pd.read_csv("data.csv")                       # CSV
df = pd.read_csv("data.csv", parse_dates=["date"]) # parse a date column
df = pd.read_excel("data.xlsx", sheet_name="Sheet1")
df = pd.read_json("data.json")

# Write back out
df.to_csv("out.csv", index=False)
df.to_excel("out.xlsx", index=False)

A Series is a single labeled column: pd.Series([1, 2, 3], name="x"). A DataFrame is a dict-like collection of aligned Series.

pandas: Inspecting Data

Get a feel for shape, types, and distributions

df.head()           # first 5 rows (df.head(10) for 10)
df.tail(3)          # last 3 rows
df.shape            # (n_rows, n_cols)
df.info()           # dtypes, non-null counts, memory usage
df.describe()       # summary stats for numeric columns
df.describe(include="all")   # include object/categorical columns
df.dtypes           # type of each column
df.columns          # column labels
df.index            # row labels
df["city"].value_counts()         # frequency of each value
df["city"].value_counts(normalize=True)   # as proportions
df["city"].nunique()              # number of distinct values

pandas: Selecting & Filtering

Pick rows and columns by label, position, or condition

Column & Label Selection

df["age"]               # single column -> Series
df[["name", "age"]]     # multiple columns -> DataFrame
df.loc[0]               # row by label
df.loc[0, "name"]       # value at label row 0, column "name"
df.loc[0:2, ["name", "age"]]   # label slice (inclusive of 2)
df.loc[:, "age"]        # all rows, one column

Positional Selection (iloc)

df.iloc[0]              # first row by position
df.iloc[0, 1]           # row 0, column 1
df.iloc[0:2]            # first two rows (stop exclusive)
df.iloc[:, 0:2]         # first two columns
df.iloc[-1]             # last row

Boolean Filtering & query

df[df["age"] > 28]                       # rows where age > 28
df[(df["age"] > 28) & (df["city"] == "NY")]   # AND (use | for OR)
df[df["city"].isin(["NY", "LA"])]        # membership filter
df[df["name"].str.startswith("A")]       # string methods via .str
df.query("age > 28 and city == 'NY'")    # expression-based filter

Combine conditions with &, |, ~ and wrap each in parentheses — Python's and/or do not work element-wise.

pandas: Cleaning Data

Handle missing values, types, names, and duplicates

Missing Values

df.isna()                  # element-wise True where missing
df.isna().sum()            # count of NaNs per column
df.dropna()                # drop any row with a NaN
df.dropna(subset=["age"])  # drop rows missing "age" only
df.fillna(0)               # replace NaN with 0
df["age"].fillna(df["age"].mean())   # impute with column mean
df.ffill()                 # forward-fill last valid value

Types, Names & Dropping

df["age"] = df["age"].astype(float)        # cast dtype
df["city"] = df["city"].astype("category") # memory-efficient category
df.rename(columns={"name": "full_name"})   # rename columns
df.drop(columns=["city"])                  # drop a column
df.drop(index=[0, 1])                      # drop rows by label
df.columns = df.columns.str.lower()        # normalize column names

Duplicates, apply & map

df.duplicated()                # True for repeated rows
df.drop_duplicates()           # remove duplicate rows
df.drop_duplicates(subset=["name"], keep="first")
df["age"].apply(lambda x: x * 2)        # element-wise on a Series
df.apply(lambda row: row["age"] + 1, axis=1)   # row-wise on a DataFrame
df["city"].map({"NY": "New York", "LA": "Los Angeles"})  # value mapping

Most cleaning methods return a new object; pass inplace=True or reassign (df = df.dropna()) to persist changes.

pandas: Transforming & Combining

Group, aggregate, pivot, sort, merge, and concatenate

groupby & Aggregation

df.groupby("city")["age"].mean()           # mean age per city
df.groupby("city").size()                  # row count per group
df.groupby("city").agg(
    avg_age=("age", "mean"),
    n=("age", "count"),
)                                          # named aggregations
df.groupby(["city", "name"])["age"].sum()  # multi-key grouping

pivot_table & Sorting

df.pivot_table(
    index="city", columns="name",
    values="age", aggfunc="mean",
)                                          # spreadsheet-style pivot
df.sort_values("age", ascending=False)     # sort by column
df.sort_values(["city", "age"])            # multi-column sort
df.sort_index()                            # sort by row label

merge / join & concat

# SQL-style join on a key column
pd.merge(df_left, df_right, on="id", how="inner")  # inner/left/right/outer
pd.merge(df_left, df_right, left_on="uid", right_on="id")

# Join on the index
df_left.join(df_right, how="left")

# Stack DataFrames
pd.concat([df1, df2], axis=0)    # vertically (more rows)
pd.concat([df1, df2], axis=1)    # horizontally (more columns)

how="inner" keeps only matching keys; "left" keeps all left rows; "outer" keeps everything and fills gaps with NaN.

Working with Dates & Time

Parsing, the dt accessor, and resampling

df["date"] = pd.to_datetime(df["date"])      # parse strings to datetime64
pd.to_datetime("2026-05-29", format="%Y-%m-%d")

# .dt accessor exposes datetime components
df["date"].dt.year
df["date"].dt.month
df["date"].dt.day_name()        # e.g. "Friday"
df["date"].dt.dayofweek         # Monday=0 .. Sunday=6

# Resample a time-indexed DataFrame (downsample to monthly mean)
ts = df.set_index("date")
ts["value"].resample("M").mean()    # "D" daily, "W" weekly, "M" month-end
ts["value"].rolling(7).mean()       # 7-period rolling average

Visualization: matplotlib & seaborn

Quick plots for distributions, relationships, and comparisons

matplotlib Basics

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, y, label="series")        # line plot
ax.scatter(x, y)                     # scatter plot
ax.bar(categories, heights)          # bar chart
ax.hist(values, bins=30)             # histogram
ax.set_xlabel("X"); ax.set_ylabel("Y")
ax.set_title("My Chart"); ax.legend()
plt.tight_layout()
plt.savefig("chart.png", dpi=150)    # or plt.show()

seaborn Statistical Plots

sns.lineplot(data=df, x="date", y="value")
sns.barplot(data=df, x="city", y="age")
sns.histplot(data=df, x="age", bins=20, kde=True)
sns.scatterplot(data=df, x="age", y="income", hue="city")
sns.boxplot(data=df, x="city", y="age")
sns.heatmap(df.corr(numeric_only=True), annot=True, cmap="coolwarm")
sns.pairplot(df, hue="city")         # pairwise scatter matrix

seaborn takes a tidy DataFrame plus column names; it draws onto matplotlib axes, so you can still call plt.title() afterwards.

Statistics & Machine Learning

scipy and statsmodels for stats; scikit-learn for modeling

scipy & statsmodels

from scipy import stats
stats.ttest_ind(group_a, group_b)     # two-sample t-test -> (stat, pvalue)
stats.pearsonr(x, y)                   # correlation + p-value
stats.norm.cdf(1.96)                   # standard-normal CDF

import statsmodels.formula.api as smf
model = smf.ols("income ~ age + C(city)", data=df).fit()
print(model.summary())                 # coefficients, R^2, p-values
model.predict(new_df)

scikit-learn Skeleton

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

X = df[["age"]]            # features (2-D)
y = df["income"]          # target (1-D)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

model = LinearRegression()
model.fit(X_train, y_train)            # train
preds = model.predict(X_test)          # predict

mean_squared_error(y_test, preds)
r2_score(y_test, preds)

The fit / predict pattern is identical across estimators — swap LinearRegression() for RandomForestClassifier(), LogisticRegression(), etc. Use a Pipeline to chain preprocessing with the model.

Handy One-Liners & Tips

Small patterns that save time every day

  • Chained assignment safely: df = df.assign(age_x2=df["age"] * 2) adds a column without mutating in place.
  • Quick correlation matrix: df.corr(numeric_only=True).
  • Top-N rows: df.nlargest(5, "age") / df.nsmallest(5, "age").
  • Bin continuous values: pd.cut(df["age"], bins=[0, 18, 65, 120], labels=["minor", "adult", "senior"]).
  • One-hot encode: pd.get_dummies(df, columns=["city"]).
  • Memory usage: df.memory_usage(deep=True).sum().
  • Reset / set index: df.reset_index(drop=True) and df.set_index("id").
  • Sample rows: df.sample(n=100, random_state=42) or frac=0.1.
  • Apply across groups: df.groupby("city")["age"].transform("mean") broadcasts the group mean back to each row.
  • Vectorize over NumPy, not loops: reach for array operations and pandas methods before writing a for loop.

Related Resources

Keep building your Python data science skills

Python Data Analysis Course

A structured course covering pandas, NumPy, and visualization with hands-on projects and guided exercises.

Start Course

Python Data Analysis eBook

A downloadable reference that expands on every topic in this cheat sheet with worked examples and explanations.

Get the eBook

Python Practice Tests

Test your knowledge with practice questions on Python syntax, data structures, and the data science stack.

Take a Test

Git Commands Cheat Sheet

Version-control your notebooks and projects with this quick-reference guide to the most-used Git commands.

View Cheat Sheet

Frequently Asked Questions

Common questions about the Python data science stack