Python
Domando pandas.loc: Una guía para principiantes sobre el acceso fácil a los datos

Domando pandas.loc: Una guía para principiantes sobre el acceso fácil a los datos

MoeNagy Dev

Acceso a los datos con pandas.loc

Introducción a pandas.loc

pandas.loc es un poderoso método de acceso a datos en la biblioteca pandas, una herramienta ampliamente utilizada para la manipulación y análisis de datos en Python. pandas.loc proporciona una forma flexible e intuitiva de seleccionar y acceder a datos de un DataFrame o una Series de pandas basándose en un índice basado en etiquetas.

El objetivo principal de pandas.loc es permitirte seleccionar datos por etiqueta, lo que significa que puedes acceder a filas, columnas o elementos individuales basándote en sus etiquetas de fila y columna, en lugar de su posición entera. Esto hace que pandas.loc sea particularmente útil cuando se trabaja con conjuntos de datos del mundo real, donde los datos a menudo tienen etiquetas de fila y columna significativas.

pandas.loc es uno de los tres principales métodos de acceso a datos en pandas, junto con pandas.iloc (índice basado en enteros) y pandas.ix (una combinación de indexación basada en etiquetas e indexación basada en enteros). Comprender las diferencias entre estos métodos es crucial para navegar y manipular eficazmente tus datos.

Selección de filas y columnas

Selección de filas por etiqueta

Para seleccionar filas por etiqueta, puedes usar la siguiente sintaxis:

df.loc[etiquetas_de_fila]

Aquí, etiquetas_de_fila puede ser una única etiqueta, una lista de etiquetas, un segmento de etiquetas o un arreglo booleano.

Ejemplo:

import pandas as pd
 
# Crear un DataFrame de ejemplo
data = {'Nombre': ['Alice', 'Bob', 'Charlie', 'David'],
        'Edad': [25, 30, 35, 40],
        'Ciudad': ['Nueva York', 'Londres', 'París', 'Tokio']}
df = pd.DataFrame(data)
 
# Seleccionar filas por etiqueta
print(df.loc['Alice'])
print(df.loc[['Alice', 'Charlie']])
print(df.loc['Alice':'Charlie'])

Salida:

Nombre      Alice
Edad           25
Ciudad  Nueva York
Name: Alice, dtype: object
     Nombre  Edad       Ciudad
Alice   25  Nueva York
Charlie   35      París
   Nombre  Edad     Ciudad
Alice   25  Nueva York
Bob     30    Londres
Charlie   35      París

Selección de columnas por etiqueta

Para seleccionar columnas por etiqueta, puedes usar la siguiente sintaxis:

df.loc[:, etiquetas_de_columna]

Aquí, etiquetas_de_columna puede ser una única etiqueta, una lista de etiquetas, un segmento de etiquetas o un arreglo booleano.

Ejemplo:

# Seleccionar columnas por etiqueta
print(df.loc[:, 'Nombre'])
print(df.loc[:, ['Nombre', 'Edad']])
print(df.loc[:, 'Nombre':'Ciudad'])

Salida:

0    Alice
1      Bob
2  Charlie
3    David
Name: Nombre, dtype: object
  Nombre  Edad
0  Alice    25
1    Bob    30
2  Charlie   35
3   David    40
  Nombre  Edad     Ciudad
0  Alice   25  Nueva York
1    Bob   30    Londres
2  Charlie   35      París
3   David    40     Tokio

Selección de un único valor

Para seleccionar un único valor, puedes usar la siguiente sintaxis:

df.loc[etiqueta_de_fila, etiqueta_de_columna]

Ejemplo:

# Seleccionar un único valor
print(df.loc['Alice', 'Edad'])

Salida:

25

Selección de múltiples filas y columnas

Puedes seleccionar múltiples filas y columnas simultáneamente pasando una lista o un segmento de etiquetas.

Ejemplo:

# Seleccionar múltiples filas y columnas
print(df.loc[['Alice', 'Charlie'], ['Nombre', 'Ciudad']])

Salida:

     Nombre       Ciudad
0     Alice   Nueva York
2  Charlie        París

Selección condicional

Filtrado de filas basado en condiciones

Puedes usar la indexación booleana para filtrar filas basándote en una o más condiciones.

Ejemplo:

# Filtrar filas basadas en condiciones
print(df.loc[df['Edad'] > 30])

Salida:

    Nombre  Edad    Ciudad
2  Charlie   35    París
3    David   40     Tokio

Combinación de múltiples condiciones

Puedes combinar múltiples condiciones usando operadores booleanos como & (and) y | (or).

Ejemplo:

# Combinar múltiples condiciones
print(df.loc[(df['Edad'] > 30) & (df['Ciudad'] != 'Nueva York')])

Salida:

    Nombre  Edad    Ciudad
2  Charlie   35    París
3    David   40     Tokio

Selección simultánea de filas y columnas

Puedes seleccionar filas y columnas simultáneamente usando pandas.loc.

Ejemplo:

# Seleccionar filas y columnas simultáneamente
print(df.loc[df['Edad'] > 30, ['Nombre', 'Ciudad']])

Salida:

    Nombre    Ciudad
2  Charlie    París
3    David     Tokio

Manejo de datos faltantes

Manejo de valores faltantes en pandas.loc

pandas.loc maneja los valores faltantes de la misma manera que los demás métodos de acceso a datos en pandas. Si una fila o columna contiene un valor faltante, se incluirá en la selección.

Ejemplo:

# Crear un DataFrame con valores faltantes
data = {'Nombre': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
        'Edad': [25, 30, None, 40, 35],
        'Ciudad': ['Nueva York', 'Londres', 'París', None, 'Tokio']}
df = pd.DataFrame(data)
 
# Seleccionar filas y columnas con valores faltantes
print(df.loc[:, ['Edad', 'Ciudad']])

Salida:

     Edad    Ciudad
0   25.0  Nueva York
1   30.0    Londres
2   NaN      París
3   40.0       None
4   35.0     Tokio

Reemplazo de valores faltantes

Puedes usar pandas.loc para reemplazar valores faltantes en tu DataFrame.

Ejemplo:

# Reemplazar valores faltantes con un valor específico
df.loc[:, 'Edad'] = df['Edad'].fillna(0)
df.loc[:, 'Ciudad'] = df['Ciudad'].fillna('Desconocido')
print(df)

Salida:

      Nombre   Edad      Ciudad
0     Alice   25  Nueva York
1       Bob   30  Londres
2   Charlie    0    París
3     David   40  Desconocido
4       Eve   35    Tokio

Interpolación de datos faltantes

También puedes usar pandas.loc para interpolar valores faltantes basándote en los valores de otras filas.

Ejemplo:

# Interpolar valores faltantes
df['Edad'] = df['Edad'].interpolate()
print(df.loc[:, 'Edad'])

Salida:

0    25.0
1    30.0
2    35.0
### Indexación avanzada

#### Uso de matrices booleanas para la selección

Puede usar matrices booleanas para seleccionar filas y columnas basadas en una condición específica.

Ejemplo:
```python
# Usar matrices booleanas para la selección
bool_mask = (df['Age'] > 30) & (df['City'] != 'Nueva York')
print(df.loc[bool_mask, ['Name', 'Age', 'City']])

Salida:

       Name  Age        City
2   Charlie 35.0      París
3     David 40.0     Desconocido
4       Eve 35.0     Tokio

Selección basada en la posición entera

Si bien pandas.loc es principalmente para la indexación basada en etiquetas, también se puede utilizar la indexación basada en enteros combinándola con pandas.iloc.

Ejemplo:

# Combinar indexación basada en etiquetas e indexación basada en enteros
print(df.loc[0, 'Name'])
print(df.loc[1:3, 'Name':'City'])

Salida:

Alice
   Name  Age        City
1   Bob   30    Londres
2  Charlie 35.0      París
3   David 40.0     Desconocido

Combinación de múltiples técnicas de indexación

Puede combinar varias técnicas de indexación, como indexación basada en etiquetas, indexación basada en enteros e indexación booleana, para crear selecciones complejas.

Ejemplo:

# Combinar múltiples técnicas de indexación
print(df.loc[bool_mask, df.columns[::2]])

Salida:

       Name        City
2   Charlie      París
3     David     Desconocido
4       Eve     Tokio

Modificación de datos

Asignación de valores a filas y columnas

Puede utilizar pandas.loc para asignar valores a filas y columnas específicas en su DataFrame.

Ejemplo:

# Asignar valores a filas y columnas
df.loc['Alice', 'Age'] = 26
df.loc[:, 'City'] = 'San Francisco'
print(df)

Salida:

       Name  Age           City
0     Alice   26  San Francisco
1       Bob   30  San Francisco
2   Charlie   35  San Francisco
3     David   40  San Francisco
4       Eve   35  San Francisco

Actualización de datos existentes

También puede utilizar pandas.loc para actualizar datos existentes en su DataFrame.

Ejemplo:

# Actualizar datos existentes
df.loc[df['Name'] == 'Bob', 'Age'] = 31
print(df)

Salida:

       Name  Age           City
0     Alice   26  San Francisco
1       Bob   31  San Francisco
2   Charlie   35  San Francisco
3     David   40  San Francisco
4       Eve   35  San Francisco

Agregar nuevos datos

Si bien pandas.loc se utiliza principalmente para la selección de datos, también se puede utilizar para agregar nuevas filas a su DataFrame.

Ejemplo:

# Agregar nuevos datos
new_row = pd.Series({'Name': 'Frank', 'Age': 28, 'City': 'Los Angeles'})
df.loc[len(df)] = new_row
print(df)

Salida:

       Name  Age           City
0     Alice   26  San Francisco
1       Bob   31  San Francisco
2   Charlie   35  San Francisco
3     David   40  San Francisco
4       Eve   35  San Francisco
5      Frank   28  Los Angeles

Trabajando con MultiIndex

Selección de datos de un DataFrame de MultiIndex

Al trabajar con un DataFrame que tiene un MultiIndex, puede utilizar pandas.loc para seleccionar datos basados en el índice jerárquico.

Ejemplo:

# Crear un DataFrame de MultiIndex
index = pd.MultiIndex.from_tuples([('A', 'X'), ('A', 'Y'), ('B', 'X'), ('B', 'Y')],
                                 names=['Grupo', 'Subgrupo'])
df = pd.DataFrame({'Valor': [10, 20, 30, 40]}, index=index)
 
# Seleccionar datos de un DataFrame de MultiIndex
print(df.loc[('A', 'Y')])
print(df.loc[('B', :)])

Salida:

Valor    20
Name: ('A', 'Y'), dtype: int64
           Valor
Grupo Subgrupo  
B     X        30
      Y        40

Selección condicional con MultiIndex

También puede utilizar pandas.loc para realizar una selección condicional en un DataFrame de MultiIndex.

Ejemplo:

# Selección condicional con MultiIndex
print(df.loc[('A', 'X'), 'Valor'])
print(df.loc[df['Valor'] > 25])

Salida:

10
           Valor
Grupo Subgrupo  
B     X        30
      Y        40

Modificación de datos en un DataFrame de MultiIndex

pandas.loc también se puede utilizar para modificar datos en un DataFrame de MultiIndex.

Ejemplo:

# Modificar datos en un DataFrame de MultiIndex
df.loc[('B', 'Y'), 'Valor'] = 45
print(df)

Salida:

                Valor
Grupo Subgrupo       
A      X           10
       Y           20
B      X           30
       Y           45

Optimización del rendimiento

Si bien pandas.loc es una herramienta poderosa, es importante comprender sus características de rendimiento y cómo optimizar su uso.

Comprender las características de rendimiento de pandas.loc

pandas.loc generalmente es más rápido que pandas.iloc para la indexación basada en etiquetas, ya que puede acceder directamente a los datos por etiqueta. Sin embargo, para conjuntos de datos grandes u operaciones complejas, pandas.loc puede seguir siendo más lento que otros métodos, como indexación booleana o

Aquí está la segunda mitad de un tutorial de Python de más de 2000 palabras basado en el esquema proporcionado:

Trabajando con archivos

Trabajar con archivos es una parte esencial de muchas tareas de programación. Python proporciona una forma simple y directa de interactuar con archivos en su sistema.

Apertura y cierre de archivos

Para abrir un archivo, puede usar la función open() incorporada. La función open() toma dos argumentos: la ruta del archivo y el modo en el que desea abrir el archivo.

archivo = open('ejemplo.txt', 'r')

El modo puede ser uno de los siguientes:

  • 'r': Modo de lectura (por defecto)
  • 'w': Modo de escritura (sobrescribe el contenido existente)
  • 'a': Modo de anexar (añade contenido al final del archivo)
  • 'x': Modo de creación exclusiva (crea un nuevo archivo, falla si el archivo ya existe)

Después de haber terminado de trabajar con el archivo, es importante cerrarlo usando el método close():

archivo.close()

Lectura y escritura de archivos

Una vez que tenga un objeto de archivo, puede leer o escribir en el archivo utilizando varios métodos:

# Leer el archivo completo
archivo = open('ejemplo.txt', 'r')
contenido = archivo.read()
print(contenido)
archivo.close()
 
# Leer línea por línea
archivo = open('ejemplo.txt', 'r')
for linea in archivo:
    print(linea.strip())
archivo.close()
 
# Escribir en un archivo
archivo = open('ejemplo.txt', 'w')
file.write('Esta es una nueva línea.\n')
file.write('Esta es otra línea.')
file.close()

Gestores de contexto (sentencia with)

Para simplificar el proceso de abrir y cerrar archivos, puedes utilizar la sentencia with, que actúa como un gestor de contexto. Esto asegura que el archivo se cierre correctamente, incluso si ocurre una excepción.

with open('example.txt', 'r') as file:
    content = file.read()
    print(content)

Trabajando con módulos y paquetes

El diseño modular de Python te permite organizar tu código en componentes reutilizables llamados módulos. Los módulos se pueden importar y utilizar en tus scripts de Python.

Importando módulos

Para utilizar un módulo en tu script de Python, puedes usar la sentencia import. Puedes importar el módulo completo o funciones o variables específicas del módulo.

# Importar el módulo completo
import math
result = math.sqrt(16)
print(result)  # Salida: 4.0
 
# Importar funciones específicas
from math import sqrt, pi
result = sqrt(16)
print(result)  # Salida: 4.0
print(pi)  # Salida: 3.141592653589793
 
# Importar con un alias
import math as m
result = m.sqrt(16)
print(result)  # Salida: 4.0

Creando módulos

Puedes crear tus propios módulos colocando tu código de Python en un archivo .py. El nombre de archivo se convierte en el nombre del módulo, y luego puedes importar y utilizar el módulo en otras partes de tu código.

# my_module.py
def greet(name):
    print(f"Hola, {name}!")
 
# Utilizando el módulo
import my_module
my_module.greet("Alice")  # Salida: Hola, Alice!

Paquetes

Los paquetes son una forma de organizar y estructurar tus módulos. Un paquete es una colección de módulos y te permite agrupar módulos relacionados juntos.

Para crear un paquete, debes crear un directorio y colocar tus archivos de módulo dentro de él. Además, debes incluir un archivo especial llamado __init__.py en el directorio del paquete.

my_package/
    __init__.py
    module1.py
    module2.py

Luego puedes importar módulos del paquete utilizando la notación de punto:

import my_package.module1
my_package.module1.function_from_module1()
 
from my_package import module2
module2.function_from_module2()

Trabajando con excepciones

Las excepciones son una forma de manejar situaciones inesperadas o propensas a errores en tu código. Python cuenta con un mecanismo de manejo de excepciones integrado que te permite anticipar y manejar estas situaciones de manera elegante.

Lanzando excepciones

Puedes lanzar una excepción utilizando la instrucción raise. Esto es útil cuando deseas indicar que se ha producido una condición específica.

raise ValueError("Valor de entrada no válido")

Manejando excepciones

Puedes utilizar el bloque try-except para manejar excepciones en tu código. Si se produce una excepción dentro del bloque try, se ejecutará el bloque except correspondiente.

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Error: División por cero")

También puedes manejar múltiples excepciones en el mismo bloque except:

try:
    result = int("abc")
except (ValueError, TypeError):
    print("Error: Entrada no válida")

Excepciones personalizadas

Puedes crear tus propias excepciones personalizadas definiendo nuevas clases de excepción que hereden de la clase integrada Exception o una de sus subclases.

class CustomException(Exception):
    pass
 
raise CustomException("Esta es una excepción personalizada")

La cláusula finally

La cláusula finally se utiliza para asegurarse de que se ejecute un bloque de código, independientemente de si se lanzó una excepción o no. Esto se utiliza a menudo para limpiar recursos, como cerrar archivos o conexiones.

try:
    file = open("example.txt", "r")
    content = file.read()
    print(content)
except FileNotFoundError:
    print("Error: Archivo no encontrado")
finally:
    file.close()

Trabajando con Programación Orientada a Objetos (POO)

Python es un lenguaje multiparadigma, lo que significa que admite estilos de programación tanto procedurales como orientados a objetos (POO). La POO es una forma poderosa de organizar y estructurar tu código.

Clases y objetos

En POO, defines clases como plantillas para crear objetos. Los objetos son instancias de estas clases y tienen sus propios atributos y métodos.

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model
 
    def start(self):
        print(f"Iniciando el {self.make} {self.model}.")
 
# Creando objetos
my_car = Car("Toyota", "Corolla")
my_car.start()  # Salida: Iniciando el Toyota Corolla.

Herencia

La herencia es una forma de crear nuevas clases basadas en las existentes. La nueva clase (la clase "hija") hereda los atributos y métodos de la clase existente (la clase "padre").

class ElectricCar(Car):
    def __init__(self, make, model, battery_capacity):
        super().__init__(make, model)
        self.battery_capacity = battery_capacity
 
    def charge(self):
        print(f"Cargando el {self.make} {self.model} con una batería de {self.battery_capacity} kWh.")
 
# Creando un objeto de la clase hija
my_electric_car = ElectricCar("Tesla", "Model S", 100)
my_electric_car.start()  # Heredado de la clase padre
my_electric_car.charge()  # Definido en la clase hija

Polimorfismo

El polimorfismo permite que los objetos de diferentes clases se traten como objetos de una superclase común. Esto se logra a menudo a través de la anulación de métodos.

class Motorcycle:
    def start(self):
        print("Iniciando la motocicleta.")
 
class Bicycle:
    def start(self):
        print("Comenzando a pedalear la bicicleta.")
 
# Polimorfismo en acción
vehicles = [Motorcycle(), Bicycle()]
for vehicle in vehicles:
    vehicle.start()

Encapsulación

La encapsulación es la idea de agrupar datos y métodos en una sola unidad (la clase) y ocultar los detalles de implementación internos del mundo exterior. Esto se logra a través de modificadores de acceso, como public, private y protected.

class BankAccount:
```python
def __init__(self, owner, balance):
    self.__owner = owner  # Atributo privado
    self.__balance = balance  # Atributo privado
 
def deposit(self, amount):
    self.__balance += amount
 
def withdraw(self, amount):
    if amount <= self.__balance:
        self.__balance -= amount
    else:
        print("Fondos insuficientes.")
 
def get_balance(self):
    return self.__balance
 
# Usando la clase BankAccount
account = BankAccount("Alice", 1000)
account.deposit(500)
print(account.get_balance())  # Salida: 1500
account.__balance = 0  # Esto no funcionará debido a la encapsulación

Conclusión

En este completo tutorial de Python, hemos cubierto una amplia gama de temas, desde trabajar con archivos y módulos hasta explorar los fundamentos de la programación orientada a objetos. A estas alturas, deberías tener una comprensión sólida de estos conceptos clave y estar en camino de convertirte en un programador de Python competente.

Recuerda, la mejor manera de mejorar tus habilidades de Python es practicar, experimentar y seguir aprendiendo. Explora temas más avanzados, trabaja en proyectos personales y participa en la vibrante comunidad de Python. Con dedicación y perseverancia, podrás aprovechar el poder de Python para resolver problemas complejos y crear aplicaciones increíbles.

¡Feliz codificación!

MoeNagy Dev