Data Auditing in Pandas

Context: FIT1043_MOC · first pass over a new dataset · surfaces Data Quality Problems before wrangling · pandas on a DataFrame df Problem it solves: given a freshly loaded DataFrame, profile its shape, types, distributions, and relationships to spot quality issues.

Quick Revision

  • 🎯 Trigger: just read data into a DataFrame ➔ run the audit sequence: shape → head/tail → info → describe → corr.
  • ⚡ Key Constraint: describe() defaults to numeric columns only; audit object/categorical columns separately, and remember df.shape is an attribute (no parentheses).

🔧 Minimal Working Example

df.shape            # (N, D) — rows, columns   (attribute, NOT df.shape())
df.head(); df.tail()  # eyeball first / last rows
df.info()           # dtypes, non-null counts (spot nulls), memory
df.describe()       # numeric summary: count, mean, std, min, quartiles, max

Expected output: (N, D) dimensions; a per-column dtype/null table from info(); numeric statistics from describe().

  • Shapedf.shape(N, D); row count and column count in one attribute.
  • Peekhead() / tail() to see real values and obvious formatting issues.
  • Types & nullsinfo() reveals dtypes and non-null counts (which columns have missing data).
  • Distributionsdescribe() for numeric (ranges expose outliers); describe(include=['O']) for object columns (count, unique, top = most common, freq = its frequency).
  • Relationshipsdf.corr() = pairwise Pearson correlation (feeds regression-based imputation).

🔀 Variations

  • Categorical auditdf.describe(include=['O']); per-column df["suburb"].unique() and df["suburb"].value_counts() to find inconsistent/misspelled values.
  • Numeric vs categorical split ➔ use info() dtypes to decide which columns get describe() vs describe(include=['O']).

✍️ Practice

⚠️ Common Mistakes

  • 💡 df.shape has no parentheses ➔ it is an attribute; df.shape() raises TypeError.
  • 💡 describe() hides text columns ➔ by default it profiles numeric only; add include=['O'] to audit object/categorical columns.
  • 💡 View-vs-copy / chained indexing ➔ fixing values via df[df.a>0]["b"] = x may hit a SettingWithCopyWarning and silently fail; assign with a single df.loc[mask, "b"] = x.