Pandas Cheatsheet
Series/DataFrame selection, groupby, merge/concat, reshaping, time series, and MultiIndex.
Import & Creation
import pandas as pd
pd.Series([1, 2, 3]) # 1-D labeled array
pd.Series({"a": 1, "b": 2}) # from a dict -> keys become the index
pd.DataFrame({"a": [1, 2], "b": [3, 4]}) # from a dict of columns
pd.DataFrame([{"a": 1, "b": 2}, {"a": 3, "b": 4}]) # from a list of records
pd.read_csv("f.csv"); df.to_csv("f.csv", index=False)
Inspecting Data
df.head(); df.tail()
df.shape; df.columns; df.index; df.dtypes
df.info(); df.describe() # describe() -> count/mean/std/min/quartiles/max
df.isnull().sum() # missing-value count per column
Selection & Indexing
df["col"]; df[["col1", "col2"]] # select column(s) -> Series / DataFrame
df.loc[row_label, col_label] # label-based
df.iloc[row_pos, col_pos] # position-based (integer)
df.loc[df["age"] > 30] # boolean mask
df[df["animal"].isin(["cat", "dog"])] # membership filter
df.query("age > 30 and visits == 1") # string-expression filter
df.at[row, col]; df.iat[row_pos, col_pos] # fast scalar access
Adding / Transforming Columns
df["new"] = df["a"] + df["b"] # vectorized — prefer this over apply
df["new"] = df["a"].apply(lambda x: x * 2) # element-wise function (slower)
df.assign(new=lambda d: d["a"] * 2) # returns a new DataFrame (chainable)
df["a"].map({"cat": 1, "dog": 2}) # map values via a dict/function
df.replace({"yes": True, "no": False}) # replace matching VALUES anywhere in the df/column
df["a"].replace({"yes": True, "no": False}) # ...or scoped to a single column
df.replace({"yes": True, "no": False}, inplace=True) # mutate in place instead of returning a copy
df.astype({"age": int}) # cast specific columns
df.rename(columns={"old": "new"}, index={0: "first"})
df.drop(columns=["a"]); df.drop(index=[0, 1])
Missing Data
df.isnull(); df.notnull()
df.dropna() # drop rows with ANY missing value
df.dropna(thresh=2) # keep rows with at least 2 non-missing values
df.fillna(0) # fill with a constant
df["a"].fillna(df["a"].mean()) # fill with a computed value
df.interpolate() # linear interpolation of gaps
s1.add(s2, fill_value=0) # arithmetic that treats a missing side as 0
s.nunique(dropna=False) # count NaN as its own distinct value
String / Text / Regex (the .str accessor)
df["s"].str.lower(); .str.upper(); .str.strip()
df["s"].str.len() # length of each string
df["s"].str.contains(r"^Will\\b", regex=True) # regex filter
df["s"].str.replace("a", "b", regex=False)
df["s"].str.split("_", expand=True) # split into separate columns
df["s"].str.extract(r"(\\d+)") # regex capture group -> new column
df["a"].str.cat(df["b"], sep="_") # concatenate two string columns
df["s"].str.slice(start=-2) # last two characters
df["tags"].str.get_dummies(sep=":") # one-hot encode a multi-value column
GroupBy & Aggregation
df.groupby("animal")["age"].mean()
df.groupby("animal").agg({"age": "mean", "visits": "sum"})
df.groupby("animal").agg(avg_age=("age", "mean"), total_visits=("visits", "sum")) # named agg
df.groupby("animal").get_group("dog") # extract one group
df.groupby("animal").filter(lambda g: g["visits"].sum() > 5) # keep whole groups
df.groupby("animal")["age"].transform(lambda x: (x - x.mean()) / x.std()) # per-group, same shape as input
df.pivot_table(values="age", index="animal", columns="priority", aggfunc="mean")
pd.crosstab(df["animal"], df["priority"])
.agg/.apply return one row per group (shape shrinks); .transform returns
one row per original row (same shape as the input, values broadcast per group).
Merging, Joining, Concatenating
pd.concat([df1, df2]) # stack rows (union of columns)
pd.concat([df1, df2], ignore_index=True) # + reset to a fresh 0-based index
pd.concat([df1, df2], keys=["a", "b"]) # + hierarchical outer index label
pd.concat([df1, df2], axis=1, join="outer") # side by side, aligned on index
pd.merge(df1, df2, on="key", how="inner") # SQL-style join; how = inner/left/right/outer
pd.merge(df1, df2, left_on="a_id", right_on="id", how="left") # differently-named keys
df1.join(df2, how="left") # index-to-index join shorthand
Reshaping
df.pivot(index="date", columns="ticker", values="price") # long -> wide
df.melt(id_vars=["id"], value_vars=["a", "b"]) # wide -> long
df.set_index(["a", "b"]).unstack() # move an index level to columns
df.stack() # move columns into the index
pd.get_dummies(df["category"]) # one-hot encode a column
Time Series
pd.to_datetime(df["date"])
pd.date_range("2020-01-01", periods=10, freq="D") # D=day, "3D"=every 3 days, B=business day
s.resample("h").mean() # aggregate into fixed time buckets
s.asfreq("3D", method="ffill") # re-index onto a new frequency, forward-fill gaps
s.shift(1) # lag/lead by n periods
s.rolling(window=3).mean() # rolling/moving statistics
s.index.month; s.index.year; s.index.is_leap_year # via the .dt / DatetimeIndex accessor
np.busday_offset(dates, offsets=-10, roll="backward") # shift by business days
MultiIndex
df.set_index(["date", "ticker"])
df.xs("AAPL", level="ticker") # cross-section: fix one level
df.loc[("2020-01-01", "GOOGL"), "open":"close"] # tuple key + column slice
df.swaplevel(); df.sort_index()
Sorting, Ranking, Duplicates
df.sort_values("age", ascending=False)
df.sort_values(["a", "b"]) # multi-column sort
df["a"].rank()
df.nlargest(3, "age"); df.nsmallest(3, "age")
df.duplicated(subset=["a", "b"], keep="last") # flag dupes, keeping the last occurrence
df.drop_duplicates()
df["a"].value_counts() # frequency of each value
df["a"].unique()
Gotchas
- Chained indexing (
df[df.a > 0]["b"] = 1) can silently fail to write back — use.loc[row_selector, "b"] = 1instead. .equals()(used for grading here) requires matching shape, values, and index/column labels — not just "looks the same when printed".inplace=Truedoesn't always save memory and makes chaining harder; prefer reassigning the returned DataFrame.groupbysorts group keys by default (sort=True); passsort=Falseto preserve first-seen order.