Skip to content

    Chapter 4, Basic

    Series: the labeled column

    A `Series` is the simplest piece of Pandas: values plus a label for each one. Understanding it well avoids half the pitfalls with the `DataFrame`, which is made of them.

    Create a Series

    A Series can arise from a list, a dictionary, or a NumPy array. Without an explicit index, the labels are 0, 1, 2... With an index, the labels are whatever you want, and the keys of a dictionary become the index by themselves:

    basico/cap04_series.pylinhas 10 a 18
    import numpy as np
    import pandas as pd
    
    salarios = pd.Series([4500, 6500, 5000])
    print(salarios)
    
    com_nome = pd.Series([4500, 6500, 5000], index=["Ana", "Bruno", "Carla"], name="salario")
    print(com_nome)
    print(pd.Series({"Ana": 4500, "Bruno": 6500}))
    
    Output
    0    4500
    1    6500
    2    5000
    dtype: int64
    Ana      4500
    Bruno    6500
    Carla    5000
    Name: salario, dtype: int64
    Ana      4500
    Bruno    6500
    dtype: int64
    

    A Series has values (the data), index (the labels) and, optionally, a name, which becomes the name of the column when it enters a DataFrame:

    basico/cap04_series.pylinha 20
    print(com_nome.name, com_nome.index.tolist(), com_nome.to_numpy())
    
    Output
    salario ['Ana', 'Bruno', 'Carla'] [4500 6500 5000]
    

    By label or by position

    The index provides two ways to access a value: by label (.loc) and by position (.iloc). The two only coincide when the index is 0, 1, 2... and one should never rely on that:

    basico/cap04_series.pylinhas 25 a 26
    print(com_nome.loc["Bruno"], com_nome.iloc[1])
    print(com_nome.iloc[-1], com_nome.loc["Ana":"Bruno"].tolist())
    
    Output
    6500 6500
    5000 [4500, 6500]
    

    Note that the slice by label ("Ana":"Bruno") includes both extremes, unlike Python slices. In Pandas 3, accessing com_nome[1] with an integer in a text index no longer falls to the position, as it did in older versions:

    basico/cap04_series.pylinhas 28 a 31
    try:
        com_nome[1]
    except KeyError as erro:
        print("KeyError:", erro)
    
    Output
    KeyError: 1
    

    Always use .loc or .iloc, which indicate what you want.

    Vectorized operations, and alignment by label

    The operations apply to the Series entire, as in NumPy. What changes is that the sum of two Series aligns by labels, and labels that only exist on one side become NaN:

    basico/cap04_series.pylinhas 36 a 42
    print((com_nome * 1.1).round(0).tolist())
    print((com_nome > 4800).tolist())
    print(com_nome.mean())
    
    bonus = pd.Series({"Ana": 500, "Carla": 300, "Diego": 100})
    print(com_nome + bonus)
    print(com_nome.add(bonus, fill_value=0))
    
    Output
    [4950.0, 7150.0, 5500.0]
    [False, True, True]
    5333.333333333333
    Ana      5000.0
    Bruno       NaN
    Carla    5300.0
    Diego       NaN
    dtype: float64
    Ana      5000.0
    Bruno    6500.0
    Carla    5300.0
    Diego     100.0
    dtype: float64
    

    Bruno has no bonus, and Diego has no salary, so the common sum gives NaN on both. The method add with fill_value=0 treats the missing side as zero, and then no one sums. This is the difference that catches most people coming from NumPy: an array sums position with position, and the Series sums label with label.

    Text in a Series

    The accessor .str applies text operations to all the values at once, without a loop, and let the missing ones pass:

    basico/cap04_series.pylinhas 47 a 48
    nomes = pd.Series(["  ana souza ", "BRUNO LIMA", None])
    print(nomes.str.strip().str.title().tolist())
    
    Output
    ['Ana Souza', 'Bruno Lima', nan]
    

    An accessor is a set of tools

    The .str for text, the .dt for dates (chapter 18) and the .cat for categories (chapter 19). Each one only works on the right type of column, and that is what keeps the API organized.

    Exercise 1

    Net salary per employee

    Given the Series com_nome, create liquido, which deducts 10% from each salary, and check Carla's amount. Then add a bonus of 200 only for those who are in bonus (and leave the others as they were).