Accessing a Series

There are multiple ways to get to the data stored in your Series. Let's explore the balances Series.

Remember, the Series is indexed by username. The label is the username, the value is that user's cash balance.

In [1]:
# Setup
import pandas as pd

from utils import render


# Standard Python dictionary
test_balance_data = {
    'pasan': 20.00,
    'treasure': 20.18,
    'ashley': 1.05,
    'craig': 42.42,
}

balances = pd.Series(test_balance_data)

Accessing by Index

A Series is ordered and indexable. It is zero based and you can access it by index, just like you would a list or array.

In [2]:
# Get the first user's balance
balances[0]
Out[2]:
20.0

Let's take a loook at the value returned.

In [3]:
type(balances[0])
Out[3]:
numpy.float64

The value is wrapped in a NumPy.Scalar so that it keeps it's data type and will play well with other data types and NumPy data structures.

The same positional indexing works just as it does with a standard list. The indices begin start with 0, and negative numbers can be used to access values from the end of the list.

In [4]:
# The last balance
balances[-1]
Out[4]:
42.42

Accessing by Label

Since a series is labelled, you can also access it much like you would a standard dict.

In [5]:
balances['pasan']
Out[5]:
20.0

Series behave like dictionaries

In [14]:
for label, value in balances.items():
    render("The label {} has a value of {}".format(label, value))

The label pasan has a value of 20.0

The label treasure has a value of 20.18

The label ashley has a value of 1.05

The label craig has a value of 42.42

In [6]:
try:
    balances['kermit']
except KeyError:
    render('Accessing a non-existent key raises a `KeyError`.')

Accessing a non-existent key raises a KeyError.

In [7]:
if balances.get('kermit') is None:
    render('Use `get` to safely access keys. `None` is returned if key not present.')

Use get to safely access keys. None is returned if key not present.

In [8]:
if 'kermit' not in balances:
    render('Use `in` to test the existence of a label.')

Use in to test the existence of a label.

Accessing by Property

As long as your label meets variable naming constraints, it will be available as a property via dot notation on the Series!

In [9]:
balances.ashley
Out[9]:
1.05

Accessing More Explicitly with loc and iloc

So far we have used a label and a positional index to access the value. This can get confusing as to what is being used, a label or a position. Because of this ambiguity, it is possible to be more explicit, which yes wise Pythonista, is always better than implicit.

A Series exposes a property named loc which can be used to explicitly lookup by label based indices only.

In [10]:
balances.loc['pasan']
Out[10]:
20.0

And to use the positional index explicitly, you can use the property iloc.

In [11]:
# Get the first value
balances.iloc[0]
Out[11]:
20.0

Accessing by Slice

Like a NumPy array, a Series also provides a way to use slices to get different portions of the data, returned as a Series.

WARNING: Slicing with indices vs. labels behaves differently. The latter is inclusive.

Slicing by Positional Index

When using positional indices, the slice is exclusive. The last item is not included.

In [12]:
# Includes values from zero
#  up until **and not** including 3
balances.iloc[0:3]
Out[12]:
pasan       20.00
treasure    20.18
ashley       1.05
dtype: float64

Slicing by Label

When using labels, the slice is inclusive. The last item is included.

In [13]:
# Include the values starting at 'pasan' 
#  up until **and** including 'ashley'
balances.loc['pasan':'ashley']
Out[13]:
pasan       20.00
treasure    20.18
ashley       1.05
dtype: float64