Selecting rows and columns with loc and iloc in pandas extracts a precise subset from a DataFrame before analysis, cleanup, joining, or export. The two indexers make the selection rule explicit, so label-based row IDs and positional table coordinates do not get mixed.
Use loc when row labels, column labels, or a boolean condition identify the subset. Label slices include both the start and stop labels, and a boolean Series aligns by index before masking.
Use iloc when integer positions identify the subset independently of labels. Position slices use normal Python slice boundaries, so the stop position is excluded; check the resulting shape, labels, and key values before feeding the subset into later code.
Related: How to create a pandas DataFrame
Related: How to filter rows in a pandas DataFrame
Related: How to set an index in pandas
Steps to select pandas DataFrame rows and columns with loc and iloc:
- Save a short loc and iloc selection script.
- select_loc_iloc.py
import pandas as pd orders = pd.DataFrame( { "order_id": ["A101", "A102", "A103", "A104", "A105"], "customer": ["Ada", "Lin", "Maya", "Omar", "Nia"], "region": ["EMEA", "APAC", "AMER", "EMEA", "APAC"], "qty": [3, 12, 7, 2, 15], "total_usd": [150.0, 240.0, 875.0, 95.0, 360.0], "status": ["paid", "paid", "open", "paid", "open"], } ).set_index("order_id") print(f"pandas {pd.__version__}") print() print("BASE") print(orders.to_string()) print() label_rows = ["A101", "A104"] label_columns = ["customer", "total_usd"] label_list = orders.loc[label_rows, label_columns] print("LOC_LABEL_LIST") print(label_list.to_string()) print() label_slice = orders.loc["A102":"A104", ["region", "qty"]] print("LOC_LABEL_SLICE") print(label_slice.to_string()) print() position_rows = [0, 3] position_columns = [0, 3] position_list = orders.iloc[position_rows, position_columns] print("ILOC_POSITION_LIST") print(position_list.to_string()) print() position_slice = orders.iloc[1:4, 1:3] print("ILOC_POSITION_SLICE") print(position_slice.to_string()) print() print("VERIFY") print(f"label rows: {label_list.index.tolist()}") print(f"position shape: {position_list.shape}") print(f"label slice includes A104: {'A104' in label_slice.index}") print(f"iloc row labels: {position_slice.index.tolist()}") print(f"source shape unchanged: {orders.shape}") print(f"A104 total by loc: {orders.loc['A104', 'total_usd']}") print(f"A104 total by iloc: {orders.iloc[3, 3]}")
The order_id index makes row labels distinct from row positions. In a working script, replace the sample orders object with the DataFrame already loaded.
- Run the script and compare the label-based and position-based selections.
$ python3 select_loc_iloc.py pandas 3.0.3 BASE customer region qty total_usd status order_id A101 Ada EMEA 3 150.0 paid A102 Lin APAC 12 240.0 paid A103 Maya AMER 7 875.0 open A104 Omar EMEA 2 95.0 paid A105 Nia APAC 15 360.0 open LOC_LABEL_LIST customer total_usd order_id A101 Ada 150.0 A104 Omar 95.0 LOC_LABEL_SLICE region qty order_id A102 APAC 12 A103 AMER 7 A104 EMEA 2 ILOC_POSITION_LIST customer total_usd order_id A101 Ada 150.0 A104 Omar 95.0 ILOC_POSITION_SLICE region qty order_id A102 APAC 12 A103 AMER 7 A104 EMEA 2 VERIFY label rows: ['A101', 'A104'] position shape: (2, 2) label slice includes A104: True iloc row labels: ['A102', 'A103', 'A104'] source shape unchanged: (5, 5) A104 total by loc: 95.0 A104 total by iloc: 95.0LOC_LABEL_SLICE includes A104 because loc label slices include the stop label. ILOC_POSITION_SLICE stops before row position 4 but still carries the original row labels in the result.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.