Python for Data Science Cheat Sheet
A dense, scannable reference for NumPy, pandas, visualization, statistics, and scikit-learn
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.
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)anddf.set_index("id"). - Sample rows:
df.sample(n=100, random_state=42)orfrac=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
forloop.
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 CoursePython Data Analysis eBook
A downloadable reference that expands on every topic in this cheat sheet with worked examples and explanations.
Get the eBookPython Practice Tests
Test your knowledge with practice questions on Python syntax, data structures, and the data science stack.
Take a TestGit Commands Cheat Sheet
Version-control your notebooks and projects with this quick-reference guide to the most-used Git commands.
View Cheat SheetFrequently Asked Questions
Common questions about the Python data science stack
loc selects by label (the row index and column names) and is inclusive of the stop value in a slice. iloc selects by integer position (0-based) and is exclusive of the stop value, just like normal Python slicing. Use loc when you know the names and iloc when you know the positions.
Python's and/or operate on single truth values, but pandas filters work element-wise across whole arrays. Use the bitwise operators & (and), | (or), and ~ (not), and wrap each condition in parentheses: df[(df["age"] > 28) & (df["city"] == "NY")].
Use NumPy for homogeneous numeric arrays and heavy mathematical or matrix computation where speed matters. Use pandas for labeled, heterogeneous tabular data — loading files, cleaning, grouping, and joining. pandas is built on top of NumPy, so you can always drop down to the underlying array with df.to_numpy() when you need raw NumPy operations.
They work together. seaborn gives you concise, attractive statistical charts directly from a tidy DataFrame with one line of code, while matplotlib provides fine-grained control over every element. A common workflow is to draw the plot with seaborn and then customize titles, labels, and limits with matplotlib's ax methods.
random_state seeds the random number generator so the split (and any stochastic step) is reproducible. Passing a fixed integer like 42 ensures you get the same train/test partition every run, which is essential for comparing models fairly and debugging.