Fetching Items from a Pandas Series
What is Series Indexing?
In a Pandas Series, we can fetch one item or multiple items using different types of indexing. The main idea is simple: we tell Pandas which item(s) we want, and Pandas returns them.
The main methods covered in this topic are:
Indexing using position
Fetching an item using a custom label
Negative indexing
Slicing
Negative slicing
Fancy indexing
Editing a Series using indexing
Note: in Pandas, position and label are not always the same thing. For clear and reliable code, use .iloc for position-based selection and .loc for label-based selection.
Series Used in the Examples
We will use the following Series for most examples:
my_series = pd.Series([10, 20, 30, 40, 50], index=["a", "b", "c", "d", "e"])
print(my_series)
Output:
a 10
b 20
c 30
d 40
e 50
Here, a, b, c, d and e are custom labels, while 0, 1, 2, 3 and 4 are the positions of the values.
Indexing Using Position
Position-based indexing means fetching an item according to its position inside the Series. The safest and clearest way to do this in Pandas is .iloc.
Example: Fetch the item at position 1
my_series.iloc[1]
# Output: 20
Easy explanation: Position 1 means the second item because Python uses zero-based indexing. Position 0 is the first item, position 1 is the second item, and so on.
Example: Fetch the item at position 3
my_series.iloc[3]
# Output: 40
Easy explanation: The item at position 3 is 40.
Fetching an Item Using a Custom Label
If a Series has custom labels, we can fetch an item using its label. The clearest method is .loc.
Example: Fetch using label
my_series.loc["c"]
# Output: 30
Easy explanation: The label "c" points to the value 30, so Pandas returns 30.
Example: Another label
my_series.loc["e"]
# Output: 50
Easy explanation: The label "e" points to the last value, 50.
Note: Do not confuse a label with a position. In this Series, label "c" is not the same concept as position 2, even though they happen to point to the same item.
Negative Indexing
Negative indexing means counting from the end. Position -1 means the last item, -2 means the second-last item, and so on.
Example: Last item using position
my_series.iloc[-1]
# Output: 50
Easy explanation: Using .iloc[-1], we clearly tell Pandas: give me the last item by position.
Example: Second-last item
my_series.iloc[-2]
# Output: 40
Easy explanation: The position -2 refers to the second-last item.
Note: For reliable position-based negative indexing, prefer .iloc[-1], .iloc[-2], etc. Writing my_series[-1] can behave differently depending on the Series index, especially when integer labels are involved.
Negative Number as a Custom Label
A negative number can also be an actual label. This is different from negative positional indexing.
Example: Series with a -1 label
s = pd.Series([100, 200, 300], index=["x", -1, "z"])
s.loc[-1]
# Output: 200
Easy explanation: Here, -1 is a real label in the index. So .loc[-1] means: find the label -1. It does NOT mean the last position.
Note: This distinction is important: .iloc[-1] means last position, while .loc[-1] means the label -1.
Slicing
Slicing is used when we want to fetch multiple consecutive items. It works like Python slicing: start, stop, step.
Example: Position-based slicing
my_series.iloc[1:4]
# Output: b 20
# c 30
# d 40
Easy explanation: The slice 1:4 starts at position 1 and stops before position 4. Therefore, positions 1, 2 and 3 are returned.
Example: Slice with a step
my_series.iloc[0:5:2]
# Output: a 10
# c 30
# e 50
Easy explanation: The step 2 means: take every second item.
Slicing Using Custom Labels
We can also slice using labels with .loc. This is useful when the Series has meaningful custom labels.
Example: Label-based slicing
my_series.loc["b":"d"]
# Output: b 20
# c 30
# d 40
Easy explanation: Here, Pandas starts at label "b" and includes the ending label "d". This is an important difference from normal Python-style stop-exclusive slicing.
Note: With .loc and label slicing, the ending label is generally included when the labels are present and sliceable.
Negative Slicing
Negative slicing uses negative positions to select items from the end of the Series.
Example: Last three items
my_series.iloc[-3:]
# Output: c 30
# d 40
# e 50
Easy explanation: The slice -3: means start from the third-last item and continue to the end.
Example: Reverse the Series
my_series.iloc[::-1]
# Output: e 50
# d 40
# c 30
# b 20
# a 10
Easy explanation: A step of -1 moves backwards, so the complete Series is returned in reverse order.
Fancy Indexing
Fancy indexing means selecting multiple specific items by providing a collection of positions or labels. There does not need to be a continuous pattern.
Example: Multiple positions
my_series.iloc[[1, 4, 2]]
# Output: b 20
# e 50
# c 30
Easy explanation: We specifically asked for positions 1, 4 and 2. Pandas returns exactly those items, in the same order.
Example: Multiple custom labels
my_series.loc[["a", "d", "e"]]
# Output: a 10
# d 40
# e 50
Easy explanation: We provide the exact labels we want. This is useful when the required items are not next to each other.
Note: For a Series with custom string labels, my_series[[...]] is label-based in common Pandas usage. If you mean positions, use .iloc[[...]]; if you mean labels, use .loc[[...]].
Editing (Writing) a Series Using Indexing
Indexing can also be used to change values. We select the item and assign a new value using =.
Example: Edit one value by position
my_series.iloc[1] = 999
print(my_series)
Easy explanation: Position 1 originally contained 20. After assignment, it becomes 999.
Example: Edit one value by label
my_series.loc["c"] = 500
print(my_series)
Easy explanation: The value belonging to label "c" is changed to 500.
Example: Edit multiple values
my_series.loc[["a", "e"]] = [111, 555]
print(my_series)
Easy explanation: Both selected labels are updated at the same time.
Note: In real-world data analysis, you will usually see indexing used more often for reading/selecting data than for directly writing individual values.
Difference Between All Types
Type | Purpose | Example | What it does |
Position indexing | Fetch one item by position | s.iloc[2] | Gets the 3rd item |
Label indexing | Fetch one item by label | s.loc["c"] | Gets the item labeled "c" |
Negative indexing | Fetch from the end by position | s.iloc[-1] | Gets the last item |
Slicing | Fetch consecutive items | s.iloc[1:4] | Gets positions 1, 2, 3 |
Label slicing | Fetch a label range | s.loc["b":"d"] | Gets labels b through d |
Negative slicing | Fetch/reverse using negative positions | s.iloc[-3:] | Gets last 3 items |
Fancy indexing | Fetch selected non-contiguous items | s.iloc[[1,4,2]] | Gets exactly those positions |
Writing | Change selected values | s.loc["c"] = 500 | Changes value at label c |
Easy Mental Model
.iloc → I = Integer position
.loc → L = Label
.iloc[-1] → Last item by position
.iloc[1:4] → Consecutive positions
.iloc[[1,4,2]] → Specific positions (fancy indexing)
.loc[["a","d"]] → Specific labels (fancy indexing)
.loc["b":"d"] → Label range
selection = value → Edit/write data
The biggest thing to remember is: use .iloc when you are thinking about position, and use .loc when you are thinking about labels.