Question

Delete a Column from a Pandas DataFrame in Python

pythonpandasdataframedel

Question

In Pandas, I can delete a column from a DataFrame successfully with:

del df['column_name']

But why does this not work?

del df.column_name

Since it is possible to access a column as a Series using df.column_name, I expected deleting it the same way to work as well.

Short Answer

By the end of this page, you will understand how Pandas column access works, why bracket-based access and dot-based access are not equivalent, and why del df['column_name'] is the correct way to remove a DataFrame column. You will also learn when dot notation is safe to use, when it is risky, and what patterns real Python codebases prefer.

Concept

In Pandas, a DataFrame column can often be read in two different ways:

df['column_name']

and sometimes:

df.column_name

These look similar, but they are not the same concept.

  • df['column_name'] is item access.
  • df.column_name is attribute access.

That difference matters.

Why del df['column_name'] works

When you write:

del df['column_name']

Python calls DataFrame behavior for deleting an item by key. In other words, Pandas knows you are asking to remove a column from the table.

This is the intended and supported way to delete a column with del.

Why del df.column_name does not work

When you write:

del df.column_name

Python treats this as deleting an object attribute, not deleting a DataFrame column. A DataFrame is a Python object with many real attributes and methods such as:

  • shape
  • columns
  • index
  • head
  • plot

Pandas allows df.column_name as a convenience for reading some columns, but that does not mean columns are true object attributes that can be safely set or deleted like normal attributes.

Dot access is mainly a shortcut for lookup, not a full replacement for bracket access.

Why this design matters

If Pandas treated all columns like normal Python attributes, there would be many problems:

  • Column names could conflict with real DataFrame methods like count or plot
  • Column names might contain spaces or special characters
  • Some column names are not valid Python identifiers
  • Object attribute deletion would become ambiguous and unsafe

Because of this, Pandas keeps column operations and attribute operations separate.

Key rule

Use:

df['name']

for reliable column access, and use:

del df['name']

or:

df = df.drop(columns=['name'])

for column deletion.

Mental Model

Think of a DataFrame like a cabinet.

  • Bracket access (df['salary']) means: “Open the drawer labeled salary.”
  • Dot access (df.salary) means: “Ask the cabinet object whether it has a property called salary.”

Sometimes the cabinet is helpful and says, “Yes, I can give you the salary drawer that way too.” But that does not mean salary is a real built-in property of the cabinet.

So reading through dot notation may work as a convenience, but deleting through dot notation is like trying to unscrew part of the cabinet itself rather than removing a drawer by label.

That is why bracket syntax is the safer and more precise tool for DataFrame columns.

Take Quiz

Syntax and Examples

Reading a column

import pandas as pd

df = pd.DataFrame({
    'name': ['Ana', 'Ben'],
    'age': [25, 30]
})

print(df['age'])
print(df.age)

Both may print the same Series:

0    25
1    30
Name: age, dtype: int64

However, df.age only works when the column name is a valid attribute name and does not conflict with existing DataFrame attributes.

Deleting a column correctly

import pandas as pd

df = pd.DataFrame({
    'name': ['Ana', 'Ben'],
    'age': [25, 30]
})

del df['age']
print(df)

Output:

  name
0  Ana
1  Ben

Another common deletion method

import pandas as pd

df = pd.DataFrame({
    'name': ['Ana', 'Ben'],
    'age': [25, 30]
})

df = df.drop(columns=['age'])
print(df)

This also removes the column, but returns a new DataFrame unless you use inplace=True.

Dot notation can fail even for reading

import pandas as pd

df = pd.DataFrame({
    'first name': ['Ana', 'Ben'],
    'class': ['A', 'B']
})

print(df['first name'])   # works
# print(df.first name)    # invalid syntax
# print(df.class)         # invalid syntax in Python

This is one reason bracket syntax is the standard approach.

Step by Step Execution

Consider this example:

import pandas as pd

df = pd.DataFrame({
    'city': ['Paris', 'Rome'],
    'population': [2.1, 2.8]
})

del df['population']
print(df)

Step by step

1. Create the DataFrame

df = pd.DataFrame({
    'city': ['Paris', 'Rome'],
    'population': [2.1, 2.8]
})

The DataFrame has two columns:

  • city
  • population

2. Delete one column by key

del df['population']

Python sees del used with [...], so it performs item deletion. Pandas interprets 'population' as a column label and removes that column from the DataFrame.

3. Print the result

print(df)

Now the DataFrame contains only:

    city
0  Paris
1   Rome

What if you try del df.population?

Python interprets this as attribute deletion. Pandas does not expose DataFrame columns as normal deletable attributes, so this does not act like column deletion.

The important idea is:

  • df['population'] targets column storage
  • df.population targets object attribute lookup

Real World Use Cases

Deleting DataFrame columns is common in data work.

1. Cleaning imported CSV data

You may load a file that contains unnecessary columns:

df = df.drop(columns=['unnamed: 0'])

Typical examples:

  • extra index columns
  • debug fields
  • export-only metadata

2. Removing sensitive information

Before sharing data, developers often remove columns such as:

  • email
  • phone number
  • address
  • internal user IDs
del df['email']

3. Preparing features for machine learning

Some columns should not be used for training:

  • target labels
  • free-text notes
  • high-cardinality IDs
X = df.drop(columns=['target'])

4. API response shaping

If a backend service reads tabular data before returning JSON, it may remove internal columns first.

df = df.drop(columns=['internal_flag', 'created_by'])

5. Reporting and dashboards

Analysts often trim raw datasets to keep only columns needed for charts or summaries.

Take Quiz

Real Codebase Usage

In real Python projects, developers usually prefer explicit column access with brackets.

Common pattern: explicit over convenient

Instead of:

df.total

many codebases prefer:

df['total']

Why:

  • clearer intent
  • safer with unusual column names
  • avoids collisions with DataFrame methods
  • easier for teammates to understand

Common pattern: dropping multiple columns

df = df.drop(columns=['temp_col', 'debug_col'])

This is common in data pipelines because it scales well when removing several columns.

Common pattern: guard before deleting

if 'age' in df.columns:
    del df['age']

This avoids errors if the schema changes.

Common pattern: validation in ETL scripts

required_columns = ['id', 'name', 'email']
missing = [col for col in required_columns if col not in df.columns]

if missing:
    raise ValueError(f"Missing columns: {missing}")

Then later:

df = df.drop(columns=['email'])

Common pattern: method chaining

drop fits nicely into transformation pipelines:

clean_df = (
    df
    .drop(columns=['unused'])
    .rename(columns={'fname': 'first_name'})
    .fillna({'score': 0})
)

This is one reason many developers choose drop() over del in production code, even though both are valid for deletion.

Common Mistakes

1. Assuming dot access and bracket access are identical

Broken expectation:

del df.age

Why it is wrong:

  • dot syntax is attribute-oriented
  • bracket syntax is column-oriented

Use this instead:

del df['age']

2. Using dot notation with invalid column names

Broken code:

print(df.first name)

This is invalid Python syntax.

Use:

print(df['first name'])

3. Using dot notation with names that clash with DataFrame methods

df = pd.DataFrame({'count': [1, 2, 3]})
print(df.count)  # this is a DataFrame method, not your column values

Use:

print(df['count'])

4. Forgetting that drop() returns a new DataFrame

Broken expectation:

df.drop(columns=['age'])
print(df)  # age is still there

Fix:

df = df.drop(columns=['age'])

or:

df.drop(columns=['age'], inplace=True)

5. Deleting a column that does not exist

del df['salary']

This raises an error if salary is missing.

Safer version:

if 'salary' in df.columns:
    del df['salary']

Or with drop:

df = df.drop(columns=['salary'], errors='ignore')

Comparisons

OperationSyntaxWorks for all column names?Deletes in place?Best use
Read column by labeldf['col']YesNot applicableStandard, reliable column access
Read column by attributedf.colNoNot applicableQuick interactive exploration only
Delete with deldel df['col']YesYesSimple in-place deletion of one column
Delete with drop()df.drop(columns=['col'])YesNo by defaultFlexible deletion, especially multiple columns

df['col'] vs df.col

Featuredf['col']df.col
Access styleItem lookupAttribute lookup
Safe for spaces/special charactersYesNo
Safe for conflicting namesYesNo
Recommended in production codeYesUsually no

del vs drop()

Featuredel df['col']df.drop(columns=['col'])
Removes one column easilyYesYes
Removes multiple columns easilyLess convenientYes
Supports method chainingNoYes
Can ignore missing columnsNoYes, with errors='ignore'
Modifies existing DataFrame directlyYesOnly with inplace=True
Take Quiz

Cheat Sheet

# Read a column safely
df['col']

# Read a column with shortcut syntax (not always safe)
df.col

# Delete one column in place
del df['col']

# Delete one or more columns
df = df.drop(columns=['col1', 'col2'])

# Delete and ignore missing columns
df = df.drop(columns=['col1'], errors='ignore')

# Check before deleting
if 'col' in df.columns:
    del df['col']

Rules to remember

  • df['col'] is the standard way to access a column.
  • df.col is only a convenience shortcut.
  • Not every column name works with dot notation.
  • del df['col'] deletes a column.
  • del df.col is attribute deletion, not proper column deletion.
  • drop() is often better when deleting multiple columns or building data pipelines.

Edge cases

  • Columns with spaces: use brackets
  • Columns named like methods (count, plot, mean): use brackets
  • Missing columns: use drop(..., errors='ignore') or check with in df.columns

FAQ

Why does df.column_name work for reading but not for deleting?

Because reading with dot notation is a convenience feature for attribute lookup. It is not the same as true column item access, which is what deletion uses.

Is df.column_name ever recommended in Pandas?

It is sometimes fine for quick exploration in a notebook, but bracket syntax is safer and more consistent in real code.

What is the best way to remove a Pandas column?

Use either:

del df['col']

or:

df = df.drop(columns=['col'])

Should I use del or drop() in Pandas?

Use del for simple in-place removal of one column. Use drop() when removing multiple columns, chaining operations, or handling missing columns gracefully.

Why is dot notation risky in Pandas?

It can fail if the column name has spaces, is not a valid Python identifier, or conflicts with a DataFrame method or attribute.

Can I delete multiple columns with del?

Not in a single clean operation. For multiple columns, drop(columns=[...]) is usually better.

Does drop() change the original DataFrame?

Not unless you assign the result back or use inplace=True. By default, it returns a new DataFrame.

Take Quiz

Mini Project

Description

Build a small data-cleaning script that removes unnecessary columns from a customer dataset. This demonstrates the difference between reading columns and deleting them, and gives practice using safe, production-style column operations in Pandas.

Goal

Create a script that loads a DataFrame, removes unwanted columns safely, and prints the cleaned result.

Requirements

  • Create a DataFrame with at least four columns, including one sensitive column such as email
  • Print one column using bracket syntax
  • Remove one column using del
  • Remove another column using drop(columns=[...])
  • Print the final cleaned DataFrame
Take Quiz

Keep learning

Related questions

View more