Pandas at: Read and Update One Cell by Label

Use at with square brackets to read or update one cell by its row and column labels. Validate labels before changing a business record.

Create the student table 🔝

at is an indexer, not a function: use square brackets. The first label identifies a row and the second identifies a column. This small embedded table makes the examples runnable without uploading a workbook.

import pandas as pd
from io import BytesIO

def student_data():
    return pd.DataFrame({
        "id": [1, 2, 3, 4],
        "name": ["John Deo", "Max Ruin", "Arnold", "Krish Star"],
        "class": ["Four", "Three", "Three", "Four"],
        "mark": [75, 85, 55, 60],
        "sex": ["female", "male", "male", "female"]
    })

df = student_data()
print(df)

Expected output

   id        name  class  mark     sex
0   1    John Deo   Four    75  female
1   2    Max Ruin  Three    85    male
2   3      Arnold  Three    55    male
3   4  Krish Star   Four    60  female

Read a cell with at 🔝

With the default index, row label 1 happens to identify the second row. That relationship changes when labels are replaced or rows are reordered.

df = student_data()
print(df.at[1, "name"])
assert df.at[1, "name"] == "Max Ruin"

Expected output

Max Ruin

Read from a row Series 🔝

A row selected with loc is a Series, so its at indexer accepts one label. For a direct cell lookup, use DataFrame.at with both labels. Use the direct form for updates to the original DataFrame.

df = student_data()
print(df.loc[2].at["name"])
print(df.at[2, "name"])
assert df.loc[2].at["name"] == df.at[2, "name"] == "Arnold"

Expected output

Arnold
Arnold

Update one cell directly 🔝

Assign through the DataFrame indexer. Avoid chained selection when changing the table. Start each student example from a fresh source to make its result independent.

df = student_data()
df.at[2, "name"] = "Arnold2"
print(df.at[2, "name"])
print(df)
assert df.at[2, "name"] == "Arnold2"

Expected output

Arnold2
   id        name  class  mark     sex
0   1    John Deo   Four    75  female
1   2    Max Ruin  Three    85    male
2   3     Arnold2  Three    55    male
3   4  Krish Star   Four    60  female

Use business labels instead of positions 🔝

Create row labels with set_index(). Label 2 now identifies Max Ruin. iat uses integer positions; it is also an indexer and takes square brackets.

indexed = student_data().set_index("id")
print("Label 2:", indexed.at[2, "name"])
print("Position 2:", indexed.iat[2, 0])
assert indexed.at[2, "name"] == "Max Ruin"
assert indexed.iat[2, 0] == "Arnold"

Expected output

Label 2: Max Ruin
Position 2: Arnold

Choose at for one cell and loc for groups 🔝

loc selects labels, lists and masks. Use at for a single label pair on a table with unique row and column labels. iloc selects by position.

indexed = student_data().set_index("id")
print("One cell:", indexed.at[3, "mark"])
print("A small table:")
print(indexed.loc[[2, 3], ["name", "mark"]])
assert indexed.at[3, "mark"] == indexed.loc[3, "mark"] == 55

Expected output

One cell: 55
A small table:
        name  mark
id                
2   Max Ruin    85
3     Arnold    55

Handle a missing label when reading 🔝

Reading a nonexistent row or column label raises KeyError. Check the labels or handle the error according to the application rule.

indexed = student_data().set_index("id")
try:
    print(indexed.at[99, "name"])
except KeyError:
    print("Student ID 99 does not exist")
print("Known IDs:", indexed.index.tolist())

Expected output

Student ID 99 does not exist
Known IDs: [1, 2, 3, 4]

Prevent accidental new rows or columns 🔝

Assignment to a missing label can enlarge the DataFrame. For an update-only operation, validate uniqueness and both labels before assigning. Blank or missing business keys need separate validation.

def update_cell(frame, row_label, column_label, value):
    if not frame.index.is_unique or not frame.columns.is_unique:
        raise ValueError("Cell updates require unique row and column labels")
    if row_label not in frame.index or column_label not in frame.columns:
        raise KeyError("Unknown row or column label")
    frame.at[row_label, column_label] = value

indexed = student_data().set_index("id")
try:
    update_cell(indexed, 99, "mark", 70)
except KeyError:
    print("Unknown update rejected")
update_cell(indexed, 3, "mark", 58)
print(indexed.loc[[3]])
assert len(indexed) == 4 and indexed.at[3, "mark"] == 58

Expected output

Unknown update rejected
      name  class  mark   sex
id                           
3   Arnold  Three    58  male

Check duplicate labels before a scalar lookup 🔝

Duplicate labels make a supposedly single-cell selection ambiguous. Inspect all conflicting rows with duplicated() and loc rather than assuming one scalar result.

df = student_data()
df.loc[3, "id"] = 3
indexed = df.set_index("id")
print("Unique row labels:", indexed.index.is_unique)
print("Conflicting ID 3 rows:")
print(indexed.loc[[3]])
try:
    update_cell(indexed, 3, "mark", 80)
except ValueError as error:
    print(error)
assert not indexed.index.is_unique

Expected output

Unique row labels: False
Conflicting ID 3 rows:
          name  class  mark     sex
id                                 
3       Arnold  Three    55    male
3   Krish Star   Four    60  female
Cell updates require unique row and column labels

Update a missing numeric cell 🔝

A compatible nullable dtype allows numeric values and missing markers in the same column. Replacing a value must respect the column dtype. Do not force unrelated text into a numeric measure.

df = student_data().set_index("id")
df["mark"] = df["mark"].astype("Int64")
df.at[3, "mark"] = pd.NA
print("Missing:", pd.isna(df.at[3, "mark"]))
df.at[3, "mark"] = 58
print("Updated mark:", df.at[3, "mark"])
assert df["mark"].dtype == "Int64"

Expected output

Missing: True
Updated mark: 58

Read a student workbook before using at 🔝

For your workbook, pass its path to read_excel(). Here an in-memory workbook demonstrates the same process. Excel needs openpyxl; the rest of the notebook can continue if it is missing. See read_excel() and sample student files.

try:
    import openpyxl
except ImportError:
    print("Excel example requires openpyxl; continue with embedded tables.")
else:
    workbook = BytesIO()
    student_data().to_excel(workbook, index=False, engine="openpyxl")
    workbook.seek(0)
    imported = pd.read_excel(workbook, engine="openpyxl")
    print(imported.at[1, "name"])
    assert imported.at[1, "name"] == "Max Ruin"

Expected output

Max Ruin

Practical example: correct a verified order 🔝

This synthetic example has a known correction: order 102 should have quantity 3. Validate the ID and value, keep a source copy and record the change. This demonstrates the mechanics; real corrections need evidence from the source record.

raw = pd.DataFrame({
    "order_id": [101, 102, 103],
    "product": ["Pen", "Book", "Pencil"],
    "quantity": pd.Series([2, 1, 4], dtype="Int64"),
    "unit_price": [5, 20, 2]
})
orders = raw.set_index("order_id").copy()
order_id, corrected_quantity = 102, 3
if not isinstance(corrected_quantity, int) or corrected_quantity < 1:
    raise ValueError("Quantity must be a positive integer")
old_quantity = orders.at[order_id, "quantity"]
update_cell(orders, order_id, "quantity", corrected_quantity)
audit = pd.DataFrame({"order_id": [order_id], "field": ["quantity"],
    "old_value": [old_quantity], "new_value": [corrected_quantity]})
print(orders)
print("Change record:")
print(audit)
assert raw.loc[raw["order_id"].eq(102), "quantity"].iloc[0] == 1
assert orders.at[102, "quantity"] == 3

Expected output

         product  quantity  unit_price
order_id                              
101          Pen         2           5
102         Book         3          20
103       Pencil         4           2
Change record:
   order_id     field  old_value  new_value
0       102  quantity          1          3

Recalculate dependent values after an edit 🔝

Changing quantity does not automatically update a previously calculated revenue column. Recalculate from the current values and check the affected record. Use vectorized operations for whole columns rather than a cell-by-cell loop.

orders["revenue"] = orders["quantity"] * orders["unit_price"]
print(orders)
print("Corrected order revenue:", orders.at[102, "revenue"])
print("Total revenue:", orders["revenue"].sum())
assert orders.at[102, "revenue"] == 60
assert orders["revenue"].sum() == 78

Expected output

         product  quantity  unit_price  revenue
order_id                                       
101          Pen         2           5       10
102         Book         3          20       60
103       Pencil         4           2        8
Corrected order revenue: 60
Total revenue: 78

Restore the identifier before export 🔝

Use reset_index() to restore order_id as a column. Export that table with index=False to retain the business key without an extra row-number column. See Input and Output.

export_table = orders.reset_index()
print(export_table.to_csv(index=False).rstrip())
assert export_table["order_id"].tolist() == [101, 102, 103]
# Optional Colab exports:
# export_table.to_csv("corrected_orders.csv", index=False)
# audit.to_csv("order_change_record.csv", index=False)

Expected output

order_id,product,quantity,unit_price,revenue

101,Pen,2,5,10

102,Book,3,20,60

103,Pencil,4,2,8

Common questions 🔝

Is at a function? No; use square brackets. Does an integer always mean a row position? No; at treats it as a label. Can at select a list? Use loc for lists, masks and ranges. Can an update create a row? Assignment can enlarge the table; validate labels for update-only operations. Will editing a selected Series update the source? Assign directly through the DataFrame. Is at always faster? Choose it for scalar access and measure important workloads. Continue with mask(), where(), query() and Data Cleaning.

Exercise: update one student by ID 🔝

Set id as the index of a fresh student table, change ID 4 to mark 65 and confirm that the original source table still has mark 60 for that student.

Exercise solution 🔝

Update the copy through its label pair. ID 4 is Krish Star.

source = student_data()
answer = source.set_index("id").copy()
update_cell(answer, 4, "mark", 65)
print(answer.loc[[4]])
assert answer.at[4, "mark"] == 65
assert source.loc[source["id"].eq(4), "mark"].iloc[0] == 60

Expected output

          name class  mark     sex
id                                
4   Krish Star  Four    65  female

Practice in Google Colab 🔝

Open in Google Colab View on GitHub
Run the examples in order, change IDs and corrected quantities, then inspect the affected cell and recalculated totals. Save your own copy to keep edits. All sample tables are included in the notebook.

Reference: Pandas DataFrame.at documentation.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer