Python
Ordenar fácilmente un Pandas Dataframe: Guía para principiantes

Ordenar fácilmente un Pandas Dataframe: Guía para principiantes

MoeNagy Dev

Los conceptos básicos del ordenamiento

Comprender la importancia del ordenamiento en el análisis de datos

Ordenar datos es una operación fundamental en el análisis de datos y a menudo es un paso crucial en la preparación de datos para su posterior procesamiento, visualización y toma de decisiones. El ordenamiento puede ayudarte a:

  • Organizar los datos de manera lógica y significativa
  • Identificar patrones y tendencias más fácilmente
  • Realizar búsquedas y consultas eficientes de datos
  • Facilitar el análisis y la generación de informes de datos
  • Mejorar la calidad y usabilidad general de tus datos

Presentación del método sort_values() en Pandas

En Pandas, el método sort_values() es la forma principal de ordenar un DataFrame. Este método te permite ordenar el DataFrame según una o más columnas, en orden ascendente o descendente.

import pandas as pd
 
# Crear un DataFrame de ejemplo
df = pd.DataFrame({'Nombre': ['Alice', 'Bob', 'Charlie', 'David'],
                   'Edad': [25, 30, 35, 40],
                   'Puntuación': [85, 92, 78, 88]})
 
# Ordenar el DataFrame por la columna 'Edad'
df_ordenado = df.sort_values(by='Edad')
print(df_ordenado)

Salida:

     Nombre  Edad  Puntuación
0  Alice     25    85
1    Bob     30    92
2 Charlie   35    78
3  David     40    88

Ordenar por una sola columna

Para ordenar un DataFrame por una sola columna, simplemente pasa el nombre de la columna al parámetro by del método sort_values().

# Ordenar el DataFrame por la columna 'Puntuación' en orden ascendente
df_ordenado = df.sort_values(by='Puntuación')
print(df_ordenado)

Salida:

       Nombre  Edad  Puntuación
2 Charlie   35    78
0    Alice     25    85
3    David     40    88
1      Bob     30    92

Ordenar por varias columnas

Puedes ordenar un DataFrame por varias columnas pasando una lista de nombres de columnas al parámetro by.

# Ordenar el DataFrame por 'Edad' en orden ascendente y 'Puntuación' en orden descendente
df_ordenado = df.sort_values(by=['Edad', 'Puntuación'], ascending=[True, False])
print(df_ordenado)

Salida:

     Nombre  Edad  Puntuación
0  Alice     25    85
1    Bob     30    92
2 Charlie   35    78
3  David     40    88

Ordenamiento en Orden Ascendente y Descendente

Ordenamiento en orden ascendente

Por defecto, el método sort_values() ordena el DataFrame en orden ascendente. Puedes establecer explícitamente el parámetro ascending en True para ordenar en orden ascendente.

# Ordenar el DataFrame por 'Edad' en orden ascendente
df_ordenado = df.sort_values(by='Edad', ascending=True)
print(df_ordenado)

Salida:

     Nombre  Edad  Puntuación
0  Alice     25    85
1    Bob     30    92
2 Charlie   35    78
3  David     40    88

Ordenamiento en orden descendente

Para ordenar el DataFrame en orden descendente, establece el parámetro ascending en False.

# Ordenar el DataFrame por 'Edad' en orden descendente
df_ordenado = df.sort_values(by='Edad', ascending=False)
print(df_ordenado)

Salida:

     Nombre  Edad  Puntuación
3  David     40    88
2 Charlie   35    78
1    Bob     30    92
0  Alice     25    85

Manejo de valores faltantes durante el ordenamiento

Pandas maneja los valores faltantes (representados por NaN) durante el ordenamiento ubicándolos al principio o al final del DataFrame ordenado, según el parámetro na_position.

# Crear un DataFrame con valores faltantes
df_con_na = pd.DataFrame({'Nombre': ['Alice', 'Bob', 'Charlie', 'David', 'Emily'],
                           'Edad': [25, 30, None, 40, 35],
                           'Puntuación': [85, 92, 78, None, 88]})
 
# Ordenar el DataFrame por 'Edad', colocando los valores NaN al principio
df_ordenado = df_con_na.sort_values(by='Edad', na_position='first')
print(df_ordenado)

Salida:

       Nombre   Edad  Puntuación
2  Charlie   None     78
3   David    40.0     NaN
4   Emily    35.0     88
0   Alice    25.0     85
1     Bob    30.0     92

Ordenamiento con Orden Personalizado

Ordenamiento basado en un orden predefinido

Puedes ordenar un DataFrame basado en un orden predefinido de valores en una columna. Esto es útil cuando deseas mantener un orden específico, como ordenar por una variable categórica.

# Crear un DataFrame con datos categóricos
df = pd.DataFrame({'Categoría': ['A', 'B', 'C', 'D', 'E']})
 
# Definir un orden personalizado para la columna 'Categoría'
orden_personalizado = ['C', 'A', 'E', 'B', 'D']
 
# Ordenar el DataFrame por la columna 'Categoría' usando el orden personalizado
df_ordenado = df.sort_values(by='Categoría', key=lambda x: pd.Categorical(x, categories=orden_personalizado, ordered=True))
print(df_ordenado)

Salida:

  Categoría
2       C
0       A
4       E
1       B
3       D

Aprovechar el parámetro key en sort_values()

El parámetro key en sort_values() te permite aplicar una función de ordenamiento personalizada a la(s) columna(s) por las que estás ordenando. Esto puede ser útil cuando necesitas realizar operaciones de ordenamiento complejas.

# Ordenar el DataFrame por la longitud de la columna 'Nombre'
df_ordenado = df.sort_values(by='Nombre', key=lambda x: x.str.len())
print(df_ordenado)

Salida:

     Nombre  Edad  Puntuación
0  Alice     25    85
1    Bob     30    92
2 Charlie   35    78
3  David     40    88

Ordenamiento de Datos Categóricos

Trabajo con datos categóricos en Pandas

Pandas proporciona soporte para trabajar con datos categóricos, lo cual puede ser útil al ordenar datos. Los datos categóricos se representan como un tipo de datos especial en Pandas, lo que te permite preservar el orden y el significado de las categorías.

# Crear un DataFrame con datos categóricos
df = pd.DataFrame({'Categoría': pd.Categorical(['Alto', 'Bajo', 'Medio', 'Alto', 'Bajo'], ordered=True)})
 
# Ordenar el DataFrame por la columna 'Categoría'
df_ordenado = df.sort_values(by='Categoría')
print(df_ordenado)

Salida:

Ordenando columnas categóricas

Cuando se ordena un DataFrame por una columna categórica, Pandas conservará el orden de las categorías, incluso si los valores subyacentes son cadenas de texto.

# Crear un DataFrame con datos categóricos
df = pd.DataFrame({'Category': pd.Categorical(['High', 'Low', 'Medium'], ordered=True)})
 
# Ordenar el DataFrame por la columna 'Category'
sorted_df = df.sort_values(by='Category')
print(sorted_df)

Salida:

    Category
1      Low
2    Medium
0     High

Conservando el orden de las categorías

Si deseas mantener un orden específico de las categorías durante la ordenación, puedes definir las categorías y su orden al crear los datos categóricos.

# Definir las categorías y su orden
categories = ['Low', 'Medium', 'High']
 
# Crear un DataFrame con datos categóricos y un orden predefinido
df = pd.DataFrame({'Category': pd.Categorical(['High', 'Low', 'Medium'], categories=categories, ordered=True)})
 
# Ordenar el DataFrame por la columna 'Category'
sorted_df = df.sort_values(by='Category')
print(sorted_df)

Salida:

    Category
1      Low
2    Medium
0     High

Ordenando columnas de fecha y hora

Manejo de datos de fecha y hora en Pandas

Pandas ofrece un excelente soporte para trabajar con datos de fecha y hora, incluida la ordenación por columnas de fecha y hora.

# Crear un DataFrame con datos de fecha y hora
import datetime
 
df = pd.DataFrame({'Date': [datetime.datetime(2022, 1, 1),
                           datetime.datetime(2022, 3, 15),
                           datetime.datetime(2021, 12, 31),
                           datetime.datetime(2022, 2, 28)]})
 
# Ordenar el DataFrame por la columna 'Date'
sorted_df = df.sort_values(by='Date')
print(sorted_df)

Salida:

           Date
2 2021-12-31 00:00:00
0 2022-01-01 00:00:00
3 2022-02-28 00:00:00
1 2022-03-15 00:00:00

Ordenando por columnas de fecha y hora

Puedes ordenar un DataFrame por una o más columnas de fecha y hora utilizando el método sort_values().

# Crear un DataFrame con varias columnas de fecha y hora
df = pd.DataFrame({'Date': [datetime.datetime(2022, 1, 1),
                           datetime.datetime(2022, 3, 15),
                           datetime.datetime(2021, 12, 31),
                           datetime.datetime(2022, 2, 28)],
                   'Time': [datetime.time(10, 30),
                           datetime.time(15, 45),
                           datetime.time(9, 0),
                           datetime.time(12, 0)]})
 
# Ordenar el DataFrame por 'Date' y 'Time'
sorted_df = df.sort_values(by=['Date', 'Time'])
print(sorted_df)

Salida:

           Date     Time
2 2021-12-31 00:00:00  09:00:00
0 2022-01-01 00:00:00  10:30:00
3 2022-02-28 00:00:00  12:00:00
1 2022-03-15 00:00:00  15:45:00

Ordenando por componentes de fecha y hora

También puedes ordenar un DataFrame por componentes individuales de fecha y hora, como año, mes, día, hora, minuto y segundo.

# Ordenar el DataFrame por el año de la columna 'Date'
sorted_df = df.sort_values(by=pd.to_datetime(df['Date']).dt.year)
print(sorted_df)

Salida:

           Date     Time
2 2021-12-31 00:00:00  09:00:00
0 2022-01-01 00:00:00  10:30:00
3 2022-02-28 00:00:00  12:00:00
1 2022-03-15 00:00:00  15:45:00

Técnicas eficientes de ordenación

Optimizando el rendimiento de la ordenación

La ordenación de DataFrames grandes puede ser computacionalmente intensiva, por lo que es importante considerar el rendimiento al ordenar los datos. Pandas ofrece varias opciones para optimizar el rendimiento de la ordenación.

# Ordenar el DataFrame en su lugar para evitar crear un nuevo DataFrame
df.sort_values(by='Age', inplace=True)

Aprovechando el parámetro inplace

El parámetro inplace en sort_values() te permite modificar directamente el DataFrame original, en lugar de crear un nuevo DataFrame. Esto puede ser más eficiente en términos de memoria, especialmente cuando se trabaja con conjuntos de datos grandes.

# Ordenar el DataFrame en su lugar para evitar crear un nuevo DataFrame
df.sort_values(by='Age', inplace=True)

Utilizando el parámetro ignore_index

El parámetro ignore_index en sort_values() se puede utilizar para descartar el índice original del DataFrame después de la ordenación. Esto puede ser útil si no necesitas mantener el índice original y quieres ahorrar memoria.

# Ordenar el DataFrame y descartar el índice original
sorted_df = df.sort_values(by='Age', ignore_index=True)

Ordenando con índices multinivel

Trabajando con índices multinivel en Pandas

Pandas admite índices multinivel (jerárquicos), que pueden ser útiles al ordenar datos. Los índices multinivel te permiten organizar los datos en una estructura más compleja.

Tutorial de Python (Parte 2)

Funciones

Las funciones son un concepto fundamental en Python. Te permiten encapsular un conjunto de instrucciones y reutilizarlas a lo largo de tu código. Aquí tienes un ejemplo de una función simple que calcula el área de un rectángulo:

def calculate_area(length, width):
    area = length * width
    return area
 
# Llamando a la función
rectangle_area = calculate_area(5, 10)
print(rectangle_area)  # Salida: 50

En este ejemplo, la función calculate_area toma dos parámetros, length y width, y devuelve el área calculada. Luego puedes llamar a esta función con diferentes valores para obtener el área de diferentes rectángulos.

Las funciones también pueden tener valores predeterminados para los parámetros y un número variable de argumentos:

def greet(name, message="Hello"):
    print(f"{message}, {name}!")
 
greet("Alice")  # Salida: Hello, Alice!
greet("Bob", "Hi")  # Salida: Hi, Bob!
 
def sum_numbers(*args):
    total = 0
    for num in args:
        total += num
    return total
 
print(sum_numbers(1, 2, 3))  # Salida: 6
print(sum_numbers(4, 5, 6, 7, 8))  # Salida: 30

En el primer ejemplo, la función greet tiene un valor predeterminado para el parámetro message. En el segundo ejemplo, la función sum_numbers puede aceptar cualquier cantidad de argumentos, que luego se suman.

Módulos y Paquetes

La biblioteca estándar de Python proporciona una amplia gama de módulos incorporados que puedes utilizar en tus programas. También puedes crear tus propios módulos y paquetes para organizar tu código.

Aquí tienes un ejemplo de uso del módulo math:

import math
 
print(math.pi)  # Salida: 3.141592653589793
print(math.sqrt(16))  # Salida: 4.0

También puedes importar funciones o atributos específicos de un módulo:

from math import pi, sqrt
 
print(pi)  # Salida: 3.141592653589793
print(sqrt(16))  # Salida: 4.0

Para crear tu propio módulo, simplemente guarda un archivo Python con extensión .py. Por ejemplo, creemos un módulo llamado mi_modulo.py:

def saludar(nombre):
    print(f"Hola, {nombre}!")
 
def calcular_area(longitud, ancho):
    return longitud * ancho

Luego puedes importar y utilizar las funciones de este módulo en tu script principal:

import mi_modulo
 
mi_modulo.saludar("Alice")  # Salida: Hola, Alice!
area = mi_modulo.calcular_area(5, 10)
print(area)  # Salida: 50

Los paquetes son una forma de organizar tus módulos en una estructura jerárquica. Para crear un paquete, debes crear un directorio con un archivo __init__.py. Aquí tienes un ejemplo:

mi_paquete/
    __init__.py
    utils/
        __init__.py
        funciones_matematicas.py
        funciones_cadena.py
    data/
        __init__.py
        base_datos.py

En este ejemplo, mi_paquete es el paquete y contiene dos subpaquetes: utils y data. Cada subpaquete tiene un archivo __init__.py, que se puede utilizar para definir funcionalidad a nivel de paquete.

Luego puedes importar y utilizar las funciones de los submódulos de esta manera:

from mi_paquete.utils.funciones_matematicas import calcular_area
from mi_paquete.data.base_datos import conectar_a_bd
 
area = calcular_area(5, 10)
conexion_bd = conectar_a_bd()

Programación Orientada a Objetos (POO)

Python admite la programación orientada a objetos, lo que te permite crear clases y objetos personalizados. Aquí tienes un ejemplo de una clase Perro simple:

class Perro:
    def __init__(self, nombre, raza):
        self.nombre = nombre
        self.raza = raza
 
    def ladrar(self):
        print("¡Guau!")
 
# Creación de objetos
mi_perro = Perro("Buddy", "Labrador")
print(mi_perro.nombre)  # Salida: Buddy
print(mi_perro.raza)  # Salida: Labrador
mi_perro.ladrar()  # Salida: ¡Guau!

En este ejemplo, la clase Perro tiene un método __init__, que es un método especial utilizado para inicializar los atributos del objeto. El método ladrar es un método personalizado que se puede llamar en un objeto Perro.

También puedes crear relaciones de herencia entre clases:

class PerroGuia(Perro):
    def __init__(self, nombre, raza, nivel_entrenamiento):
        super().__init__(nombre, raza)
        self.nivel_entrenamiento = nivel_entrenamiento
 
    def guiar(self):
        print("¡Estoy guiando a mi dueño!")
 
perro_guia = PerroGuia("Buddy", "Labrador", "avanzado")
perro_guia.ladrar()  # Salida: ¡Guau!
perro_guia.guiar()  # Salida: ¡Estoy guiando a mi dueño!

En este ejemplo, la clase PerroGuia hereda de la clase Perro y agrega un atributo nivel_entrenamiento y un método guiar.

Excepciones y Manejo de Errores

Python proporciona un mecanismo robusto de manejo de excepciones para lidiar con errores en tiempo de ejecución. Aquí tienes un ejemplo de cómo manejar un ZeroDivisionError:

def dividir(a, b):
    try:
        resultado = a / b
        return resultado
    except ZeroDivisionError:
        print("Error: División por cero.")
        return None
 
print(dividir(10, 2))  # Salida: 5.0
print(dividir(10, 0))  # Salida: Error: División por cero.

En este ejemplo, la función dividir utiliza un bloque try-except para capturar el ZeroDivisionError y manejarlo adecuadamente.

También puedes crear tus propias excepciones personalizadas:

class ErrorEntradaInvalida(Exception):
    pass
 
def calcular_area(longitud, ancho):
    if longitud <= 0 or ancho <= 0:
        raise ErrorEntradaInvalida("La longitud y el ancho deben ser números positivos.")
    return longitud * ancho
 
try:
    area = calcular_area(5, 10)
    print(area)  # Salida: 50
    area = calcular_area(-5, 10)
except ErrorEntradaInvalida as e:
    print(e)  # Salida: La longitud y el ancho deben ser números positivos.

En este ejemplo, la función calcular_area genera una excepción personalizada ErrorEntradaInvalida si los valores de entrada no son válidos. El bloque try-except captura y maneja esta excepción.

Conclusión

En este tutorial, has aprendido sobre varios conceptos importantes en Python, incluyendo funciones, módulos y paquetes, programación orientada a objetos y manejo de excepciones. Estos temas son esenciales para construir aplicaciones Python más complejas y robustas. Recuerda practicar y experimentar con los ejemplos de código proporcionados para consolidar tu comprensión. ¡Feliz codificación!

MoeNagy Dev