Read First, Then Look Before You Filter

The fastest way to waste an afternoon is to write a fancy filter on a file you haven't inspected. Load the data, print its shape, print its columns, then filter. You avoid the classic trap of filtering on a column name that has a trailing space or mixed case.

A DataFrame is just a table in memory: rows are records, columns are fields like Sales or Region. Almost everything you did with Excel filters maps to a one-line pandas expression, and it runs on files far larger than Excel's row limit.

Step 1: Load a CSV File

1
Import the library

Type 'import pandas as pd'. Analysts almost always alias it as pd, so every example you find online will assume that name. Use it.

2
Read the file

Run 'df = pd.read_csv("orders.csv")'. This returns a DataFrame. If your file uses semicolons instead of commas, add 'sep=";"' or the whole row lands in one column.

3
Check the size

Run 'print(df.shape)'. On a 50,000-row Orders file this prints (50000, 6). The first number is rows, the second is columns. Use it to confirm the file read fully.

Step 2: Inspect With head() and info()

4
Preview rows

Run 'df.head()' to see the first five rows. For a wider view use 'df.head(10)'. This is your quick sanity check that Sales and Region look like numbers and text, not scrambled values.

5
List columns

Run 'print(df.columns)'. You might see Index(['OrderID', 'Region', 'Product', 'Sales', 'OrderDate'], dtype='object'). Note the exact spelling; filters are case-sensitive.

6
Check types and nulls

Run 'df.info()'. It shows each column's dtype and how many non-null values exist. If Sales is an 'object' instead of 'float64', a comma like '1,200' is blocking the conversion and your sums will break.

Pro Tip

I recommend running 'df.head()' and 'df.info()' on every new file before writing a single filter. A five-second look at dtypes catches the comma-in-number problem that otherwise ruins your totals an hour later.

Step 3: Filter on One Condition

7
Filter by Region

Run 'west = df[df['Region'] == 'West']'. The inner 'df['Region'] == 'West'' builds a True/False mask, and wrapping it in 'df[...]' keeps only the True rows. You now have every West order.

8
Filter by a number

Run 'big = df[df['Sales'] > 1000]'. This returns rows where Sales exceeds 1000. On the sample data that's about 12 percent of orders, a useful cut for a high-value report.

9
Count the result

Run 'print(len(west))' to see how many rows matched. If you expected 8,000 and got 0, your Region value is probably 'west' lowercase — masks are case-sensitive.

Step 4: Combine Multiple Conditions

10
Use AND logic

Run 'mask = (df['Region'] == 'West') & (df['Sales'] > 1000)'. Note the single '&' and the parentheses around each test. The double '&&' from other languages will break here and throw an error.

11
Use OR logic

Run 'mask = (df['Region'] == 'West') | (df['Region'] == 'East')'. The single '|' means OR. Wrap each condition in parentheses or Python evaluates it wrong and your filter returns everything.

12
Apply the combined mask

Run 'result = df[mask]'. result holds only rows meeting all (or any) of your tests. Print 'result.shape' to confirm the row count dropped the way you intended.

Pro Tip

A common mistake is forgetting parentheses around each condition in a combined mask. Without them, Python applies operator precedence you didn't intend and returns the full table instead of a filtered slice. Always wrap each test.

Step 5: Filter Text and Dates

13
Match a substring

Run 'df[df['Product'].str.contains('Pro')]'. This returns products whose name contains 'Pro'. Use 'case=False' to ignore upper and lower case in the match.

14
Parse dates first

Run 'df['OrderDate'] = pd.to_datetime(df['OrderDate'])'. After that, 'df[df['OrderDate'] > '2024-01-01']' filters by date. Skip the parse and the comparison treats dates as text and returns nothing useful.

15
Filter a date range

Run 'q1 = df[(df['OrderDate'] >= '2024-01-01') & (df['OrderDate'] < '2024-04-01)]'. This grabs the first quarter. Quarter cuts like this are how I build monthly sales decks from one raw export.

Jupyter notebook showing a pandas DataFrame filtered to West region rows with Sales over 1000

Step 6: Read Excel and SQL Too

16
Read Excel

Run 'df = pd.read_excel("orders.xlsx", sheet_name="2024")'. Name the sheet or pandas reads the first one, which may not be the tab you want.

17
Read from SQL

With a connection 'conn', run 'df = pd.read_sql("SELECT * FROM Orders WHERE Region = 'West'", conn)'. This pulls straight from the database, so you filter at the source and move less data.

18
Read only some columns

Run 'df = pd.read_csv("orders.csv", usecols=['Region','Sales'])'. Skipping columns you won't use cuts memory on big files and speeds up every later step.

Worked Example: A 14 Percent High-Value Slice

Take the Orders table with 50,000 rows and columns Region and Sales. Filter to 'df[df['Sales'] > 1000]' and you get 7,020 rows. That's 14.04 percent of the file. Sum those with 'df[df['Sales'] > 1000]['Sales'].sum()' and you get 9,310,400 in revenue. One mask turned a 50,000-row blob into a single defensible number for the board.

19
Confirm the share

Run 'share = len(big) / len(df) * 100' and print it. Seeing 14.04 tells you the high-value segment is small but worth a chart.

20
Save the slice

Run 'big.to_csv("high_value_orders.csv", index=False)'. The 'index=False' keeps pandas from writing its row numbers as a stray first column you'd have to delete in Excel.

How This Compares to Excel Filters

Excel's filter button is great for a one-time look. But when you repeat the same Sales-over-1000 cut every Monday, a saved notebook reruns in one command while the manual clicks eat 20 minutes. If your data already lives in a database, our SQL for data analysis guide shows how to filter there before it ever reaches Python.

Step 7: Sort and Rank the Filtered Rows

A filter gives you a subset; sorting tells you which rows matter most. After narrowing to high-value orders, rank them so the biggest deal sits on top. This is the view a manager actually scrolls through, not the raw 50,000-row file.

21
Sort by Sales

Run 'df[df["Sales"] > 1000].sort_values("Sales", ascending=False)'. The biggest order now leads. On the sample data the top row might be a 9,800 deal that would have been row 41,234 in the unsorted file.

22
Take the top ten

Run 'top.head(10)'. This shows your ten largest orders, a list you can paste straight into a follow-up email. A common mistake is forgetting ascending=False and presenting the smallest deals as the highlights.

23
Reset the index

Run 'top = top.reset_index(drop=True)'. The drop=True throws away the old row numbers so your exported top-ten starts at 1 and reads like a clean leaderboard, not a slice of a bigger table.

Combine filter, sort, and head into one line once you are comfortable: 'df[df["Region"]=="West"]["Sales"].sort_values(ascending=False).head(5)'. Chaining reads top to bottom and removes the temporary variables that clutter a longer script. I reach for the chain on quick questions and keep the named steps for anything a teammate will maintain.

Watch out for chained assignment warnings. When you write 'df[df["Region"]=="West"]["Sales"] = 0' pandas may complain it cannot tell which copy to modify. Filter into a variable first, change it, then assign back, and the warning disappears.

Read the File Before You Trust It

Before any filter, confirm the file actually loaded the way you think. A CSV with a stray quote on row 9,000 can shift every column after it, so your Sales column holds text and your Region holds numbers. Print 'df.dtypes' and 'df.shape' on every new file; a two-second look saves an hour of chasing a filter that returns nothing because the types are wrong.

Watch the delimiter. European exports often use semicolons, and some systems pad fields with spaces, so 'West ' never equals 'West'. Read with 'sep=";"' when needed and run 'df['Region'] = df['Region'].str.strip()' to drop the padding. A filter that silently matches zero rows is the most common way a report ships with a hidden hole the reader never sees.

Save your cleaned view, and don't overwrite the raw one. Write the filtered result to a new CSV and keep the original untouched, so you can always rerun the steps from the source. When a manager asks why a number changed, you compare against the raw file instead of guessing what the script did to it, and that audit trail is worth more than the few seconds you save by writing in place.

Next Steps

Filtering gets you subsets; grouping turns those subsets into summaries. The next move is 'df.groupby('Region')['Sales'].sum()', which totals Sales per region in one line instead of dozens of filtered copies.

24
Practice on your own file

Take any CSV with a numeric column and a category column, load it, and write one AND mask plus one OR mask. Confirm each result's row count makes sense.

25
Chain into groupby

Move to the groupby guide below to learn aggregation that reads like SQL, turning filtered rows into Region-level totals.