Concepts / Loading and Filtering Data With pandas

Loading and Filtering Data With pandas

A pandas DataFrame is a table of named columns and labeled rows, similar to an Excel spreadsheet, created with pd.DataFrame from a dictionary.

  • Programming

Why a Table Needs Its Own Structure

A spreadsheet holds information in rows and columns, and you can sort and filter it by hand. pandas is a Python library for data wrangling and analysis, and it brings a comparable table into code. The central structure in pandas is the DataFrame. In plain terms, a DataFrame is a table, similar to an Excel spreadsheet, and pandas provides methods for modifying and operating on that table.

This article follows one small working example. You will build a table from a dictionary, trace how that table is organized, see why its columns can hold different kinds of data, and then filter it with a condition. Along the way you will follow the steps of a query so that you can explain its output, and you will learn where an unexpected result is most likely to come from.

Building a Table From a Dictionary

Each key in the dictionary is a column name, and each key points to a list of values, one value per person or record. The last line passes that dictionary to pd.DataFrame, which builds the table. The example below uses a small generated table with the same shape as the source's four-person example: three columns named Name, Location, and Age, and four rows.

python
Output (expected)
   Name Location  Age
0   Ana   Lisbon   25
1   Ben     Oslo   28
2 Peter   Denver   34
3 Linda   Austin   41
Notes on the code
  • The dictionary keys Name, Location, and Age become the column headers.
  • Each list supplies the cell values for its column, in order from top to bottom.
  • pd.DataFrame(people) builds the table; the final line displays it.
NameAna, Ben, Peter,LindaRow labels 0 to 3LocationLisbon, Oslo, Denver,AustinAge25, 28, 34, 41list of valueslist of valueslist of valuesone position per row
Which parts of the dictionary become column headers, which become cell values, and where do the row labels come from?

Trace the construction step by step. The dictionary keys became the three column names. The first item in each list lands in the first row, the second item in the second row, and so on. Row labels 0 through 3 were not written in the dictionary at all; they are assigned to the rows and appear at the left edge of the table. Because each list is read position by position, the values in a row line up across columns, so every row describes one person.

Reading Columns, Rows, and Labels

A DataFrame has columns, and each column has a name. Each column holds a sequence of values, and the rows line up across the columns. The row labels on the left identify each row. A row is therefore one person's record, spread across all the columns. When you read the table, you read it in two directions at once: down a column to see every value of one attribute, and across a row to see every attribute of one record.

Definition

A pandas DataFrame is a table of named columns and labeled rows, similar to an Excel spreadsheet, created with pd.DataFrame from a dictionary.

Column Types in a DataFrame Versus a NumPy Array

The source contrasts pandas with NumPy. NumPy requires that all entries in an array be of the same type. pandas relaxes that rule by allowing each column to have a separate type. A column can hold integers, dates, floating-point numbers, or strings. In the table built above, the Age column holds whole numbers, while Name and Location hold text. This is the feature that distinguishes a DataFrame from a grid where every entry must match.

One type for everyentryName column: textInts, floats, stringsshare one typeLocation column: textAge column: wholenumbersforces a shared typeeach column chooses its own typeeach column chooses its own type
What happens to mixed int, float, and string values when they are stored in one NumPy array versus in separate DataFrame columns?

Use the picture of a spreadsheet as a starting point. In a spreadsheet, each column can contain numbers or text, and the program keeps track of that. A NumPy array is closer to a grid where every cell must match the others, while a DataFrame keeps each column as its own typed sequence inside one labeled table. The consequence matters later: when a column's type is different from what you expect, a condition on that column will compare values of that type.

Filtering Rows With a Condition

pandas makes it possible to query a table with conditions. Here is a query on the same DataFrame. It asks for every row whose Age is greater than 30. Before you read the result, make a prediction about which rows the query will return.

What do you think happens?

Which rows does data_pandas[data_pandas.Age > 30] return?

  • Every row in the table

  • Only Peter and Linda, keeping labels 2 and 3

  • Only Linda, keeping label 3

  • No rows, because the table has no matches

Reveal answer
Answer:

Only Peter and Linda, keeping labels 2 and 3

Ages 34 and 41 are greater than 30, and those are the rows for Peter (label 2) and Linda (label 3). Ana and Ben, with ages 25 and 28, do not satisfy the condition.

python
Output (expected)
   Name Location  Age
2 Peter   Denver   34
3 Linda   Austin   41
Notes on the code
  • data_pandas.Age > 30 produces one True or False answer for each row.
  • The outer brackets keep only the rows that answered True.
  • The result keeps the original row labels 2 and 3.
0Ana, Age 252Peter, Denver, 341Ben, Age 283Linda, Austin, 412Peter, Age 343Linda, Age 41Age > 30 is TrueAge > 30 is True
How does each row's True or False result from the condition decide which rows survive the filter, and how do the original row labels carry through?
Worked example

Tracing the age-above-30 query

Starting from the four-row table with labels 0 to 3, determine which rows data_pandas[data_pandas.Age > 30] returns and which labels they keep.

  1. 1
    Stage 1: evaluate the condition

    The expression data_pandas.Age > 30 is checked against each row's Age value. Row 0 has 25, which is not greater than 30, so the answer is False. Row 1 has 28, also False. Row 2 has 34, which is True. Row 3 has 41, which is True.

  2. 2
    Stage 2: keep the True rows

    The rows that answered True are kept. Rows 0 and 1 are dropped. Rows 2 and 3 survive.

  3. 3
    Stage 3: preserve the labels

    The surviving rows keep the labels 2 and 3 they had in the original table. The values in each row are unchanged; only the rows were selected.

Result

The result contains two rows: Peter with label 2 and Linda with label 3.

The query reads in two stages. First, the expression is checked against every row's Age, producing a yes or no answer per row. Second, the rows that answered yes are kept in the result. Because the query is a filter, its output is a subset of the original table, and the source shows the filtered table keeping the original row labels. That detail is the one to watch when you trace results.

Mistakes That Produce Unexpected Results

When a result differs from what you expected, the source recommends a fixed order of checks: look at the table first, then the condition, then the output. The goal is to find the stage where the divergence begins, rather than changing the code at random. The mistakes below are the most common places where that divergence starts.

  • Common mistake

    Assuming the output row numbers are positions in the filtered table

    What it looks like

    After the age query, the rows are labeled 2 and 3, not 0 and 1.

    Why it fails

    A filter keeps the original index labels, so the label of a surviving row can differ from its position in the new, smaller result.

    Do this instead

    Read the label shown at the left edge as the row's identity in the original table, and do not assume it counts from zero after filtering.

  • Common mistake

    Expecting a numeric comparison from a column that holds text

    What it looks like

    A column of ages that was loaded as text would be compared as text, not as numbers, so a check against 30 may not behave as the number comparison you intended.

    Why it fails

    A condition compares values using the column's type, so the type of the column determines what the condition actually compares.

    Do this instead

    Check the table first to see what each column holds, then confirm the condition is comparing values of the type you intend.

  • Common mistake

    Treating a row's label as proof of which values it contains

    What it looks like

    Label 2 is Peter in the original table; the label alone does not tell you his age without reading the Age column in that row.

    Why it fails

    Labels identify rows, but the values in the row are what the condition examines.

    Do this instead

    Read across the row to confirm the values that the condition used.

Practicing a Filter Trace

EASY

Using the four-row table from this article (Ana 25, Ben 28, Peter 34, Linda 41), predict the result of data_pandas[data_pandas.Age < 30]. State which rows are returned and which labels they keep. Then explain which stage of the query each answer depends on.

Hints
  • Evaluate the condition Age < 30 for each row before deciding which rows to keep.
  • Remember that the surviving rows keep their original labels.
  • Compare your answer with the condition-then-output order of checks.

Key Takeaways

  • A pandas DataFrame is a table of named columns and labeled rows, created with pd.DataFrame from a dictionary whose keys become column names.
  • Unlike a NumPy array, which requires one type for all entries, a DataFrame lets each column have its own type, such as integers or strings.
  • A condition like data_pandas[data_pandas.Age > 30] first produces a True or False answer for each row, then keeps only the True rows along with their original index labels.
  • When a result differs from expectation, check the table, then the condition, then the output to find the stage where the divergence begins.

Related concepts

More concepts starting with L