Home › Python

SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame — how to fix

SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Quick fix: Assign in one step with .loc: df.loc[df['age'] > 30, 'group'] = 'senior'. When you want an independent subset, make it explicit: sub = df[df['age'] > 30].copy() and then modify sub. Since pandas 2.x you can also enable copy-on-write: pd.options.mode.copy_on_write = True.

What it means

Indexing a DataFrame sometimes returns a view (shares memory with the original) and sometimes a copy. pandas can't always tell which you got, so when you assign into the result it warns: your assignment may silently do nothing to the original df. Treat it as a bug signal, not noise.

Cause 1: chained indexing

Two indexing operations in a row, then an assignment:

# Wrong: df[df.age > 30] creates a new object; ['group'] = ... modifies that object
df[df['age'] > 30]['group'] = 'senior'

Use a single .loc call with row and column selectors:

df.loc[df['age'] > 30, 'group'] = 'senior'

Same for single cells: df.loc[5, 'price'] = 9.99 (or df.at[5, 'price'] = 9.99) instead of df['price'][5] = 9.99.

Cause 2: modifying a filtered subset

adults = df[df['age'] >= 18]
adults['score'] = adults['score'] * 2      # warning

If adults should be a separate table, say so:

adults = df[df['age'] >= 18].copy()
adults['score'] = adults['score'] * 2      # fine, df is untouched

If you meant to change df itself, use .loc on df:

mask = df['age'] >= 18
df.loc[mask, 'score'] = df.loc[mask, 'score'] * 2

Cause 3: column subsets and functions

sub = df[['name', 'price']]
sub['price'] = sub['price'].round(2)       # warning

Fix with .copy() or by building new columns with assign, which always returns a new DataFrame:

sub = df[['name', 'price']].assign(price=lambda d: d['price'].round(2))

Functions that receive a slice and modify it in place trigger it too; return a new frame from the function instead.

Fix 4: enable copy-on-write (pandas 2.x)

Copy-on-write makes every indexing result behave like a copy, so the rules become simple and the warning goes away. Chained assignment then never modifies the original (it raises ChainedAssignmentError warnings instead), so you must use .loc.

import pandas as pd
pd.options.mode.copy_on_write = True

Copy-on-write is the default behaviour in pandas 3.0.

Don't just silence it

pd.options.mode.chained_assignment = None   # hides the warning

This hides it, but your assignments may still be lost. Only do this after you've verified the code is correct.

Check your pandas version

python -c "import pandas; print(pandas.__version__)"

Last updated 2026-10-31.