Lección 6 de 29Módulo 2: Pandas - Manipulación de Datos

06. Introducción a Pandas

Series, DataFrames y las estructuras fundamentales de Pandas

20 minutos

Bienvenido al Módulo 2. Pandas es la librería más importante para análisis de datos en Python. En esta lección dominarás sus estructuras fundamentales: Series y DataFrames.

¿Qué es Pandas?

Pandas es una librería de Python para manipulación y análisis de datos estructurados. Es como Excel con superpoderes:

  • 📊 Maneja datasets de millones de filas (Excel limita a ~1M)
  • ⚡ Operaciones ultra rápidas en datos
  • 🔄 Lee/escribe múltiples formatos (CSV, Excel, JSON, SQL, etc.)
  • 📈 Integración perfecta con visualización y machine learning

💡 Dato: El 95% de los analistas de datos profesionales usan Pandas diariamente. Es LA herramienta esencial para data analytics.

📅 Pandas 2.x (vigente en 2026) — qué cambió

En abril 2023 salió Pandas 2.0 con cambios estructurales importantes:

  • Backend PyArrow opcional: ahora podés usar dtype_backend="pyarrow" en read_csv/read_parquet/etc. para columnas Arrow-native — menos memoria, joins/groupbys más rápidos, mejor interop con DuckDB/Polars/Spark.
  • Nullable nativo: las columnas Arrow soportan nulos sin las gimnasias del viejo NaN en columnas int.
  • Compatibilidad: 2.x no obliga a usar Arrow; NumPy sigue siendo el backend default. Arrow es opt-in.
# Nuevo en Pandas 2.x — backend Arrow
df = pd.read_csv("ventas.csv", dtype_backend="pyarrow")
# df.dtypes ahora muestra int64[pyarrow], string[pyarrow], etc.

¿Cuándo elegir Polars en lugar de Pandas? Si tu dataset es >1GB o las operaciones son lentas, considerá Polars (en Rust, ~63% menos energía que Pandas en benchmarks TPC-H, hasta 8× más rápido en datasets sintéticos). Sintaxis muy parecida a Pandas pero con lazy evaluation.

Instalación y primera importación

# Verificar instalación (ya debería estar con Anaconda)
import pandas as pd
import numpy as np

print(f"Pandas version: {pd.__version__}")
print(f"NumPy version: {np.__version__}")

Convención de importación

# Siempre importa Pandas con el alias 'pd'
import pandas as pd  # ✅ Estándar universal

# No hagas esto:
import pandas        # ❌ Sin alias
import pandas as pnd # ❌ Alias no estándar

Series: Arrays unidimensionales

Una Serie es como una columna de Excel o una lista mejorada con etiquetas.

Crear Series

import pandas as pd

# Desde lista
ventas = pd.Series([1200, 1450, 1100, 1800, 1950])
print(ventas)

Resultado:

0    1200
1    1450
2    1100
3    1800
4    1950
dtype: int64

Series con índice personalizado

# Índice personalizado
ventas_diarias = pd.Series(
    [1200, 1450, 1100, 1800, 1950, 2100, 1750],
    index=['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom']
)
print(ventas_diarias)

# Acceder por índice
print(ventas_diarias['Lun'])    # 1200
print(ventas_diarias['Sáb'])    # 2100

# Acceder por posición (como lista)
print(ventas_diarias[0])        # 1200
print(ventas_diarias[-1])       # 1750

# Slice
print(ventas_diarias['Lun':'Mié'])  # Lun, Mar, Mié

Series desde diccionario

# Crear desde diccionario (la forma más común)
metricas = pd.Series({
    'usuarios': 15000,
    'conversiones': 750,
    'ingresos': 45000,
    'ctr': 3.5
})
print(metricas)

Resultado:

usuarios         15000.0
conversiones       750.0
ingresos         45000.0
ctr                  3.5
dtype: float64

Operaciones con Series

ventas = pd.Series([1200, 1450, 1100, 1800, 1950])

# Operaciones matemáticas
print(ventas + 100)        # Suma 100 a cada elemento
print(ventas * 1.10)       # Aplica 10% de aumento
print(ventas / 1000)       # Convierte a miles

# Estadísticas descriptivas
print(f"Suma: {ventas.sum()}")            # 8500
print(f"Promedio: {ventas.mean():.2f}")   # 1700.00
print(f"Mediana: {ventas.median()}")      # 1450.0
print(f"Máximo: {ventas.max()}")          # 1950
print(f"Mínimo: {ventas.min()}")          # 1100
print(f"Desv. estándar: {ventas.std():.2f}") # 344.82

# Método describe() (resumen completo)
print(ventas.describe())

Resultado de describe():

count     5.000000
mean   1700.000000
std     356.789190
min    1100.000000
25%    1200.000000
50%    1450.000000
75%    1800.000000
max    1950.000000
dtype: float64

DataFrames: Tablas completas

Un DataFrame es una tabla bidimensional (filas y columnas). Es la estructura principal de Pandas.

Crear DataFrames

# Desde diccionario (cada key es una columna)
ventas_df = pd.DataFrame({
    'producto': ['Laptop', 'Mouse', 'Teclado', 'Monitor'],
    'cantidad': [2, 10, 5, 3],
    'precio': [800, 25, 60, 300]
})

print(ventas_df)

Resultado:

   producto  cantidad  precio
0    Laptop         2     800
1     Mouse        10      25
2  Teclado         5      60
3   Monitor         3     300

Desde lista de diccionarios

# Cada diccionario es una fila
transacciones = pd.DataFrame([
    {'fecha': '2024-01-15', 'producto': 'Laptop', 'cantidad': 2, 'precio': 800},
    {'fecha': '2024-01-16', 'producto': 'Mouse', 'cantidad': 10, 'precio': 25},
    {'fecha': '2024-01-16', 'producto': 'Teclado', 'cantidad': 5, 'precio': 60},
    {'fecha': '2024-01-17', 'producto': 'Monitor', 'cantidad': 3, 'precio': 300}
])

print(transacciones)

Propiedades básicas del DataFrame

# Ver primeras filas
print(transacciones.head())      # Primeras 5 filas (default)
print(transacciones.head(2))     # Primeras 2 filas

# Ver últimas filas
print(transacciones.tail())      # Últimas 5 filas
print(transacciones.tail(2))     # Últimas 2 filas

# Información del DataFrame
print(transacciones.info())

# Dimensiones
print(f"Filas: {transacciones.shape[0]}")
print(f"Columnas: {transacciones.shape[1]}")
print(f"Shape: {transacciones.shape}")     # (4, 4)

# Nombres de columnas
print(transacciones.columns)
# Index(['fecha', 'producto', 'cantidad', 'precio'], dtype='object')

# Tipos de datos
print(transacciones.dtypes)

Acceder a columnas

# Forma 1: Como atributo (solo si nombre sin espacios)
productos = transacciones.producto
print(productos)

# Forma 2: Como diccionario (recomendado)
productos = transacciones['producto']
print(productos)

# Múltiples columnas
subset = transacciones[['producto', 'precio']]
print(subset)

Acceder a filas

# Por posición con iloc
primera_fila = transacciones.iloc[0]
print(primera_fila)

# Rango de filas
primeras_dos = transacciones.iloc[0:2]
print(primeras_dos)

# Por índice con loc (más adelante veremos índices personalizados)
# Por ahora, iloc es suficiente

Operaciones con columnas

Crear nuevas columnas

# Calcular total por transacción
transacciones['total'] = transacciones['cantidad'] * transacciones['precio']
print(transacciones)

Resultado:

        fecha producto  cantidad  precio  total
0  2024-01-15   Laptop         2     800   1600
1  2024-01-16    Mouse        10      25    250
2  2024-01-16  Teclado         5      60    300
3  2024-01-17  Monitor         3     300    900

Operaciones matemáticas en columnas

# Aplicar descuento del 10%
transacciones['precio_descuento'] = transacciones['precio'] * 0.9

# Calcular IVA (21%)
transacciones['iva'] = transacciones['total'] * 0.21

# Total con IVA
transacciones['total_con_iva'] = transacciones['total'] + transacciones['iva']

print(transacciones[['producto', 'total', 'iva', 'total_con_iva']])

Eliminar columnas

# Eliminar columna (no modifica el original)
df_sin_iva = transacciones.drop('iva', axis=1)

# Eliminar columna (modifica el original)
transacciones.drop('precio_descuento', axis=1, inplace=True)

# Eliminar múltiples columnas
# transacciones.drop(['col1', 'col2'], axis=1, inplace=True)

Proyecto práctico: Análisis de campaña digital

import pandas as pd

# Dataset de campaña de marketing
campañas = pd.DataFrame({
    'campaña': [
        'Black Friday Email',
        'Google Ads - Search',
        'Facebook Ads',
        'Instagram Stories',
        'LinkedIn Sponsored'
    ],
    'impresiones': [50000, 120000, 200000, 180000, 45000],
    'clics': [2500, 4800, 6000, 7200, 1350],
    'conversiones': [125, 192, 240, 288, 54],
    'costo': [500, 2400, 3000, 2700, 900]
})

print("="*60)
print("ANÁLISIS DE CAMPAÑAS DIGITALES")
print("="*60)
print(campañas)
print()

# Calcular métricas
campañas['ctr'] = (campañas['clics'] / campañas['impresiones']) * 100
campañas['conversion_rate'] = (campañas['conversiones'] / campañas['clics']) * 100
campañas['cpc'] = campañas['costo'] / campañas['clics']
campañas['cpa'] = campañas['costo'] / campañas['conversiones']

# Asumiendo valor de conversión de $100
valor_conversion = 100
campañas['ingresos'] = campañas['conversiones'] * valor_conversion
campañas['roi'] = ((campañas['ingresos'] - campañas['costo']) / campañas['costo']) * 100

# Mostrar métricas principales
print("MÉTRICAS CALCULADAS:")
print(campañas[['campaña', 'ctr', 'conversion_rate', 'roi']].round(2))
print()

# Estadísticas generales
print("RESUMEN GENERAL:")
print(f"Total invertido: ${campañas['costo'].sum():,}")
print(f"Total conversiones: {campañas['conversiones'].sum()}")
print(f"Ingresos generados: ${campañas['ingresos'].sum():,}")
print(f"CTR promedio: {campañas['ctr'].mean():.2f}%")
print(f"Conversion rate promedio: {campañas['conversion_rate'].mean():.2f}%")
print(f"ROI promedio: {campañas['roi'].mean():.1f}%")
print()

# Mejor campaña por ROI
mejor_roi_idx = campañas['roi'].idxmax()
mejor_campaña = campañas.loc[mejor_roi_idx]
print("🏆 MEJOR CAMPAÑA (ROI):")
print(f"  {mejor_campaña['campaña']}")
print(f"  ROI: {mejor_campaña['roi']:.1f}%")
print(f"  Conversiones: {mejor_campaña['conversiones']}")
print(f"  CPA: ${mejor_campaña['cpa']:.2f}")

Resultado:

============================================================
ANÁLISIS DE CAMPAÑAS DIGITALES
============================================================
                 campaña  impresiones  clics  conversiones  costo
0   Black Friday Email         50000   2500           125    500
1  Google Ads - Search        120000   4800           192   2400
2         Facebook Ads        200000   6000           240   3000
3     Instagram Stories        180000   7200           288   2700
4   LinkedIn Sponsored         45000   1350            54    900

MÉTRICAS CALCULADAS:
                 campaña   ctr  conversion_rate    roi
0   Black Friday Email  5.00             5.00  2400.0
1  Google Ads - Search  4.00             4.00   700.0
2         Facebook Ads  3.00             4.00   700.0
3     Instagram Stories  4.00             4.00   966.7
4   LinkedIn Sponsored  3.00             4.00   500.0

RESUMEN GENERAL:
Total invertido: $9,500
Total conversiones: 899
Ingresos generados: $89,900
CTR promedio: 3.80%
Conversion rate promedio: 4.20%
ROI promedio: 1053.3%

🏆 MEJOR CAMPAÑA (ROI):
  Black Friday Email
  ROI: 2400.0%
  Conversiones: 125
  CPA: $4.00

Métodos esenciales de DataFrames

Información y estadísticas

# Resumen estadístico de columnas numéricas
print(campañas.describe())

# Información del DataFrame
print(campañas.info())

# Contar valores únicos
print(campañas['campaña'].nunique())  # Número de campañas únicas

# Ver valores únicos
print(campañas['campaña'].unique())

# Contar frecuencia de cada valor
print(campañas['conversiones'].value_counts())

Ordenar datos

# Ordenar por ROI descendente
campañas_ordenadas = campañas.sort_values('roi', ascending=False)
print(campañas_ordenadas[['campaña', 'roi']].head())

# Ordenar por múltiples columnas
campañas_ordenadas = campañas.sort_values(
    ['conversion_rate', 'ctr'],
    ascending=[False, False]
)

# Reiniciar índice después de ordenar
campañas_ordenadas = campañas_ordenadas.reset_index(drop=True)

Comparación: Pandas vs Python puro

Python puro (trabajoso)

ventas = [
    {'producto': 'Laptop', 'precio': 800, 'cantidad': 2},
    {'producto': 'Mouse', 'precio': 25, 'cantidad': 10},
    {'producto': 'Teclado', 'precio': 60, 'cantidad': 5}
]

# Calcular total de cada venta
total_general = 0
for venta in ventas:
    total_venta = venta['precio'] * venta['cantidad']
    total_general += total_venta
    print(f"{venta['producto']}: ${total_venta}")

print(f"Total: ${total_general}")

Con Pandas (simple y rápido)

ventas_df = pd.DataFrame(ventas)
ventas_df['total'] = ventas_df['precio'] * ventas_df['cantidad']
print(ventas_df)
print(f"\nTotal: ${ventas_df['total'].sum()}")

Buenas prácticas

1. Explorar siempre primero

# Al recibir un DataFrame nuevo:
print(df.head())           # Ver primeros datos
print(df.info())           # Ver tipos y nulos
print(df.describe())       # Ver estadísticas
print(df.shape)            # Ver dimensiones

2. Usar nombres descriptivos

# ❌ Mal
df1 = pd.DataFrame(...)
df2 = df1[df1['col'] > 10]

# ✅ Bien
ventas_totales = pd.DataFrame(...)
ventas_altas = ventas_totales[ventas_totales['monto'] > 10000]

3. Evitar modificar DataFrames en bucles

# ❌ Mal (muy lento)
for i in range(len(df)):
    df.loc[i, 'total'] = df.loc[i, 'precio'] * df.loc[i, 'cantidad']

# ✅ Bien (operación vectorizada, ultra rápida)
df['total'] = df['precio'] * df['cantidad']

Ejercicio práctico

Crea un DataFrame con datos de redes sociales y analiza el engagement:

# Datos de posts en redes sociales
posts_df = pd.DataFrame({
    'fecha': ['2024-01-15', '2024-01-16', '2024-01-17', '2024-01-18', '2024-01-19'],
    'plataforma': ['Instagram', 'Facebook', 'LinkedIn', 'Instagram', 'Twitter'],
    'impresiones': [5000, 3000, 1500, 6000, 4000],
    'likes': [250, 180, 120, 400, 200],
    'comentarios': [25, 15, 30, 40, 18],
    'shares': [10, 8, 15, 20, 12]
})

# Tareas:
# 1. Calcular engagement rate: (likes + comentarios + shares) / impresiones * 100
# 2. Calcular engagement total por post
# 3. Encontrar el post con mejor engagement rate
# 4. Calcular promedio de engagement por plataforma

# Solución:
posts_df['engagement_total'] = posts_df['likes'] + posts_df['comentarios'] + posts_df['shares']
posts_df['engagement_rate'] = (posts_df['engagement_total'] / posts_df['impresiones']) * 100

print("Análisis de Engagement:")
print(posts_df[['plataforma', 'engagement_rate']].round(2))

mejor_post = posts_df.loc[posts_df['engagement_rate'].idxmax()]
print(f"\n🏆 Mejor post: {mejor_post['plataforma']} ({mejor_post['engagement_rate']:.2f}%)")

Resumen de la lección

Pandas es la librería esencial para análisis de datos en Python ✅ Series son arrays unidimensionales con índice (como columnas) ✅ DataFrames son tablas completas con filas y columnas ✅ Puedes crear DataFrames desde diccionarios, listas, CSV, Excel, SQL ✅ Operaciones matemáticas son vectorizadas (muy rápidas) ✅ Métodos como .describe(), .info(), .head() son esenciales para explorar datos


🎯 Próxima lección: 07. Carga y Exploración de Datos

En la siguiente lección aprenderás a cargar datos desde CSV, Excel, JSON y bases de datos. 🚀

Checkpoint de comprensión

3 preguntas para verificar lo aprendido. No afecta tu nota del examen final.

1¿Cuáles son las dos estructuras principales de Pandas?
2En Pandas 2.x (2026), ¿qué backend opcional ofrece mejor performance que NumPy?
3¿Cuándo elegirías Polars en lugar de Pandas?

¿Completaste esta lección?

Marca esta lección como completada. Tu progreso se guardará en tu navegador.