Q&A library Python

What is the difference between at, iat, loc and iloc in pandas?

Python Intermediate atiatindexing

Short answer

at and iat fetch a single cell and are faster than loc and iloc, which handle ranges and slices. Use at for a label lookup of one value and iat for a positional one.

The short version

loc and iloc select rows, columns, ranges and slices. at and iat fetch exactly one cell, and are faster because they skip all the machinery for handling ranges. Use at for a single value by label and iat for a single value by position.

The four together

import pandas as pd

df = pd.DataFrame({"city": ["Leeds", "Bath"], "amount": [5, 7]})

df.at[0, "amount"]     # 5  , one cell, by label
df.iat[0, 1]           # 5  , one cell, by position
df.loc[0, "amount"]    # 5  , also works, but more general
df.iloc[0, 1]          # 5  , also works, but more general

For a single cell, all four give the same answer. The difference is speed and intent.

Why at and iat are faster

loc and iloc must handle the possibility of a slice, a list, a boolean mask or a range, so they carry overhead even when you only want one value. at and iat accept nothing but a single row and column, so they take a much shorter path. Inside a loop over many individual lookups, the difference is noticeable.

When it actually matters

For a handful of lookups, use whatever reads best; the speed difference is irrelevant. at and iat earn their place inside a loop that touches individual cells many times, which is exactly the situation where you should first ask whether you can vectorise instead. If you can, do that: even the fastest cell access is far slower than an operation on a whole column.

Setting a single value

Both work for assignment as well as reading, and are the fastest way to poke one value.

df.at[0, "amount"] = 10

This writes to the frame directly, and being a single-cell operation it avoids the chained-assignment ambiguity that causes SettingWithCopyWarning.

The strictness of at

at only accepts a label that exists and a single column name. Passing a list, a slice or a missing label raises, which is a feature: it catches at once the mistake of thinking you are fetching one thing when you are actually fetching several.

The mnemonic

The i prefix means integer position, in both iloc and iat, exactly as it does elsewhere in pandas. So at is to loc what iat is to iloc: the same addressing scheme, restricted to a single cell.

The advice in one line

Reach for loc by default, because it is the most readable and general. Use at or iat when you are fetching or setting one cell and the speed matters. And if you find yourself using them in a big loop, stop and ask whether a vectorised expression would replace the loop entirely.

Need this solved on your own data?

The library is free and always will be. When the problem is bigger than an answer, we take on the work.

Start a project