By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Hyper-practical, zero-fluff guide for real-world data wrangling
You’re handed a 10GB CSV with messy customer data: missing values, inconsistent formats, and nested JSON strings. Your boss says, “Clean this and give me a summary by tomorrow.” Pandas is great, but if you don’t know list slicing, chaining, and comprehensions, you’ll waste hours writing loops or crashing your notebook with MemoryError.
MemoryError
This guide teaches you Python’s built-in tools for fast, readable data munging—no external libraries required. These tricks: - Cut runtime from minutes to seconds (critical when processing large datasets).- Replace 10-line loops with 1-line expressions (your future self will thank you).- Avoid memory leaks (e.g., df.apply(lambda x: x[::2]) vs. a list comprehension).- Pass coding interviews (FAANG-style questions love testing these).
df.apply(lambda x: x[::2])
Real-world scenario:You’re preprocessing logs for a machine learning model. The raw data has: - Timestamps like "2023-01-01 12:00:00,123" (needs splitting).- User IDs with prefixes ("user_123" → 123).- Missing values encoded as "N/A" or "NULL".
"2023-01-01 12:00:00,123"
"user_123"
123
"N/A"
"NULL"
Without these tricks, you’d write nested loops. With them, you’ll clean the data in 5 lines of code.
[start:stop:step]
list[start:stop:step]
k
data[::2]
[-1]
[-2:]
-1
len(list) - 1
logs[-10:]
[x for x in iterable if condition]
for
[x*2 for x in range(10) if x % 2 == 0]
[0, 4, 8, 12, 16]
{k:v for k,v in iterable}
dict(zip(keys, values))
{x: x2 for x in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
{x for x in iterable}
{x.lower() for x in ["A", "a", "B"]}
{"a", "b"}
[x for y in iterable for x in y]
itertools.chain
[num for row in matrix for num in row]
x if condition else y
if-else
[x if x > 0 else 0 for x in [-1, 2, -3]]
[0, 2, 0]
enumerate()
for i, x in enumerate(list)
range(len(list))
[(i, x) for i, x in enumerate(["a", "b"])]
[(0, "a"), (1, "b")]
zip()
for x, y in zip(list1, list2)
[x + y for x, y in zip([1, 2], [3, 4])]
[4, 6]
Task: Process a list of user records with: - Inconsistent formats (e.g., "user_123" vs "123").- Missing values ("N/A", None, "").- Nested data (e.g., "address": {"city": "NY"}).
"123"
None
""
"address": {"city": "NY"}
:=
python raw_data = [ {"id": "user_123", "age": "25", "city": "NY", "tags": ["new", "active"]}, {"id": "456", "age": "N/A", "city": "", "tags": []}, {"id": "user_789", "age": "30", "city": "SF", "tags": ["premium"]}, {"id": "101", "age": None, "city": "LA", "tags": ["inactive"]}, ]
user_ids = [int(user["id"].replace("user_", "")) for user in raw_data] # Output: [123, 456, 789, 101]
Why it works: replace() strips "user_", int() converts to integer.
replace()
"user_"
int()
clean_ages = [ int(age) if age and age != "N/A" else None for user in raw_data for age in [user["age"]] ] # Output: [25, None, 30, None]
Why it works: Nested comprehension checks for None/"N/A" before converting.
all_tags = {tag for user in raw_data for tag in user["tags"]} # Output: {'new', 'active', 'premium', 'inactive'}
Why it works: Set comprehension deduplicates tags.
clean_data = [ { "id": int(user["id"].replace("user_", "")), "age": int(age) if (age := user["age"]) and age != "N/A" else None, "city": user["city"] if user["city"] else None, "is_active": "active" in user["tags"], } for user in raw_data ]
Output:
[ {"id": 123, "age": 25, "city": "NY", "is_active": True}, {"id": 456, "age": None, "city": None, "is_active": False}, {"id": 789, "age": 30, "city": "SF", "is_active": False}, {"id": 101, "age": None, "city": "LA", "is_active": False}, ]
Why it works:- Walrus operator := avoids repeating user["age"].- Ternary conditions handle missing values.
user["age"]
pandas
import pandas as pd df = pd.DataFrame(clean_data) print(df.head())
id age city is_active 0 123 25.0 NY True 1 456 NaN NaN False 2 789 30.0 SF False 3 101 NaN LA False
append()
O(1)
O(n)
[user["id"] for user in users]
[x["id"] for x in y]
# Convert "user_123" → 123
()
(x*2 for x in range(1_000_000))
sum(x for x in data)
sum([x for x in data])
try-except
python [int(x) if x.isdigit() else None for x in ["1", "a", "2"]]
filter(None, ...)
python list(filter(None, [1, None, 2, ""])) # [1, 2]
RuntimeError: list changed size during iteration
list.copy()
step
data[2]
itertools.zip_longest()
TypeError: int() argument must be a string
if x
list[1::3]
[x2 for sublist in list_of_lists for x in sublist]
{word: len(word) for word in ["hello", "world"]}
[::-1]
reversed()
set()
{}
zip_longest()
Task: Given a list of strings like ["2023-01-01", "2023-01-02", "invalid"], extract the year from valid dates and return None for invalid ones.
["2023-01-01", "2023-01-02", "invalid"]
Solution:
years = [ int(date.split("-")[0]) if "-" in date else None for date in ["2023-01-01", "2023-01-02", "invalid"] ] # Output: [2023, 2023, None]
Why it works:- split("-")[0] extracts the year.- if "-" in date checks for valid format.
split("-")[0]
if "-" in date
list[1:5:2]
list[-1]
[x*2 for x in range(5)]
{k: v*2 for k, v in {"a": 1}.items()}
{x.lower() for x in ["A", "a"]}
[x for row in matrix for x in row]
[x if x > 0 else 0 for x in [-1, 2]]
[(i, x) for i, x in enumerate(list)]
[x + y for x, y in zip(list1, list2)]
[y for x in data if (y := x*2) > 0]
(x*2 for x in range(10))
filter()
list(filter(None, [1, None, 2]))
⚠️ Exam Traps:- list[::-1] reverses a list (creates a new copy).- {} is an empty dictionary, not a set (use set()).- zip() stops at the shortest iterable.
list[::-1]
Final Tip:Next time you write a for loop, ask: “Can this be a comprehension?” If yes, do it—your future self (and your team) will thank you. ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.