Ir al contenido principal

Introducción a Pandas: análisis de datos

Introducción

Pandas es una biblioteca de Python diseñada específicamente para el análisis y manipulación de datos estructurados. Construida sobre NumPy, Pandas proporciona estructuras de datos flexibles y potentes herramientas que facilitan el trabajo con datos tabulares y series temporales. Es una herramienta imprescindible para científicos de datos, analistas y cualquier persona que necesite procesar, limpiar y analizar conjuntos de datos. En este artículo, exploraremos las estructuras de datos fundamentales de Pandas, así como las operaciones básicas para el análisis de datos.

Instalación de Pandas

Para comenzar a utilizar Pandas, primero debemos instalarlo:

pip install pandas

Importación de Pandas

Por convención, Pandas se importa con el alias pd:

import pandas as pd
import numpy as np  # También importamos NumPy, ya que suelen usarse juntos

Estructuras de datos principales

Pandas tiene dos estructuras de datos fundamentales:

Series

Una Series es un array unidimensional etiquetado, similar a una columna en una hoja de cálculo:

# Crear una Series desde una lista
s = pd.Series([10, 20, 30, 40])
print(s)
# 0    10
# 1    20
# 2    30
# 3    40
# dtype: int64

# Crear una Series con índices personalizados
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s)
# a    10
# b    20
# c    30
# d    40
# dtype: int64

# Crear una Series desde un diccionario
d = {'a': 10, 'b': 20, 'c': 30, 'd': 40}
s = pd.Series(d)
print(s)
# a    10
# b    20
# c    30
# d    40
# dtype: int64

Acceso a elementos de una Series

# Acceder por posición
print(s[0])  # 10

# Acceder por etiqueta
print(s['a'])  # 10

# Acceder a múltiples elementos
print(s[['a', 'c']])
# a    10
# c    30
# dtype: int64

# Rebanado
print(s['a':'c'])
# a    10
# b    20
# c    30
# dtype: int64

DataFrame

Un DataFrame es una estructura de datos bidimensional etiquetada, similar a una tabla de base de datos o una hoja de cálculo:

# Crear un DataFrame desde un diccionario de listas
datos = {
    'Nombre': ['Ana', 'Juan', 'María', 'Pedro'],
    'Edad': [25, 30, 22, 40],
    'Ciudad': ['Madrid', 'Barcelona', 'Sevilla', 'Valencia']
}

df = pd.DataFrame(datos)
print(df)
#   Nombre  Edad     Ciudad
# 0    Ana    25     Madrid
# 1   Juan    30  Barcelona
# 2  María    22    Sevilla
# 3  Pedro    40   Valencia

# Crear un DataFrame desde una lista de diccionarios
personas = [
    {'Nombre': 'Ana', 'Edad': 25, 'Ciudad': 'Madrid'},
    {'Nombre': 'Juan', 'Edad': 30, 'Ciudad': 'Barcelona'},
    {'Nombre': 'María', 'Edad': 22, 'Ciudad': 'Sevilla'},
    {'Nombre': 'Pedro', 'Edad': 40, 'Ciudad': 'Valencia'}
]

df = pd.DataFrame(personas)
print(df)  # Mismo resultado que el anterior

# Crear un DataFrame desde un array NumPy
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
df = pd.DataFrame(array, columns=['A', 'B', 'C'])
print(df)
#    A  B  C
# 0  1  2  3
# 1  4  5  6
# 2  7  8  9

Propiedades del DataFrame

# Dimensiones (filas, columnas)
print(f"Forma: {df.shape}")  # (3, 3)

# Nombres de columnas
print(f"Columnas: {df.columns}")  # Index(['A', 'B', 'C'], dtype='object')

# Índices de filas
print(f"Índices: {df.index}")  # RangeIndex(start=0, stop=3, step=1)

# Tipos de datos
print(f"Tipos de datos:\n{df.dtypes}")
# A    int64
# B    int64
# C    int64
# dtype: object

# Información general
print(df.info())
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 3 columns):
#  #   Column  Non-Null Count  Dtype
# ---  ------  --------------  -----
#  0   A       3 non-null      int64
#  1   B       3 non-null      int64
#  2   C       3 non-null      int64
# dtypes: int64(3)
# memory usage: 200.0 bytes

# Resumen estadístico
print(df.describe())
#               A         B         C
# count  3.000000  3.000000  3.000000
# mean   4.000000  5.000000  6.000000
# std    3.000000  3.000000  3.000000
# min    1.000000  2.000000  3.000000
# 25%    2.500000  3.500000  4.500000
# 50%    4.000000  5.000000  6.000000
# 75%    5.500000  6.500000  7.500000
# max    7.000000  8.000000  9.000000

Acceso a datos en un DataFrame

Hay varias formas de acceder a los datos en un DataFrame:

Selección de columnas

# Volvamos a nuestro DataFrame de personas
df = pd.DataFrame(datos)

# Seleccionar una columna (devuelve una Series)
nombres = df['Nombre']
print(nombres)
# 0      Ana
# 1     Juan
# 2    María
# 3    Pedro
# Name: Nombre, dtype: object

# Seleccionar múltiples columnas (devuelve un DataFrame)
info_personal = df[['Nombre', 'Edad']]
print(info_personal)
#   Nombre  Edad
# 0    Ana    25
# 1   Juan    30
# 2  María    22
# 3  Pedro    40

Selección de filas

# Usando .loc[] para seleccionar por etiqueta
fila_2 = df.loc[2]
print(fila_2)
# Nombre     María
# Edad          22
# Ciudad    Sevilla
# Name: 2, dtype: object

# Usando .iloc[] para seleccionar por posición
primera_fila = df.iloc[0]
print(primera_fila)
# Nombre       Ana
# Edad          25
# Ciudad    Madrid
# Name: 0, dtype: object

# Seleccionar múltiples filas
filas_1_3 = df.iloc[[0, 2]]
print(filas_1_3)
#   Nombre  Edad  Ciudad
# 0    Ana    25  Madrid
# 2  María    22 Sevilla

# Rebanado de filas
filas_0_a_2 = df.iloc[0:2]
print(filas_0_a_2)
#   Nombre  Edad     Ciudad
# 0    Ana    25     Madrid
# 1   Juan    30  Barcelona

Selección condicional

# Filtrar personas mayores de 25 años
mayores_25 = df[df['Edad'] > 25]
print(mayores_25)
#   Nombre  Edad     Ciudad
# 1   Juan    30  Barcelona
# 3  Pedro    40   Valencia

# Filtrar personas de Madrid
de_madrid = df[df['Ciudad'] == 'Madrid']
print(de_madrid)
#   Nombre  Edad  Ciudad
# 0    Ana    25  Madrid

# Combinar condiciones
filtro = (df['Edad'] > 25) & (df['Ciudad'] != 'Valencia')
print(df[filtro])
#   Nombre  Edad     Ciudad
# 1   Juan    30  Barcelona

Operaciones básicas con DataFrames

Añadir y eliminar columnas

# Añadir una nueva columna
df['Profesión'] = ['Ingeniera', 'Médico', 'Profesora', 'Arquitecto']
print(df)
#   Nombre  Edad     Ciudad  Profesión
# 0    Ana    25     Madrid  Ingeniera
# 1   Juan    30  Barcelona     Médico
# 2  María    22    Sevilla  Profesora
# 3  Pedro    40   Valencia Arquitecto

# Añadir una columna calculada
df['Año_Nacimiento'] = 2023 - df['Edad']
print(df)
#   Nombre  Edad     Ciudad  Profesión  Año_Nacimiento
# 0    Ana    25     Madrid  Ingeniera            1998
# 1   Juan    30  Barcelona     Médico            1993
# 2  María    22    Sevilla  Profesora            2001
# 3  Pedro    40   Valencia Arquitecto            1983

# Eliminar columnas
df_sin_profesion = df.drop('Profesión', axis=1)
print(df_sin_profesion)
#   Nombre  Edad     Ciudad  Año_Nacimiento
# 0    Ana    25     Madrid            1998
# 1   Juan    30  Barcelona            1993
# 2  María    22    Sevilla            2001
# 3  Pedro    40   Valencia            1983

# Eliminar múltiples columnas
df_basico = df.drop(['Profesión', 'Año_Nacimiento'], axis=1)
print(df_basico)
#   Nombre  Edad     Ciudad
# 0    Ana    25     Madrid
# 1   Juan    30  Barcelona
# 2  María    22    Sevilla
# 3  Pedro    40   Valencia

Añadir y eliminar filas

# Añadir una fila usando .loc[]
df.loc[4] = ['Carlos', 35, 'Bilbao', 'Abogado', 1988]
print(df)
#   Nombre  Edad     Ciudad  Profesión  Año_Nacimiento
# 0    Ana    25     Madrid  Ingeniera            1998
# 1   Juan    30  Barcelona     Médico            1993
# 2  María    22    Sevilla  Profesora            2001
# 3  Pedro    40   Valencia Arquitecto            1983
# 4  Carlos    35     Bilbao    Abogado            1988

# Concatenar DataFrames
nueva_persona = pd.DataFrame({
    'Nombre': ['Laura'],
    'Edad': [28],
    'Ciudad': ['Zaragoza'],
    'Profesión': ['Diseñadora'],
    'Año_Nacimiento': [1995]
})
df = pd.concat([df, nueva_persona], ignore_index=True)
print(df)
#   Nombre  Edad     Ciudad   Profesión  Año_Nacimiento
# 0    Ana    25     Madrid   Ingeniera            1998
# 1   Juan    30  Barcelona      Médico            1993
# 2  María    22    Sevilla   Profesora            2001
# 3  Pedro    40   Valencia  Arquitecto            1983
# 4  Carlos    35     Bilbao     Abogado            1988
# 5  Laura    28   Zaragoza  Diseñadora            1995

# Eliminar filas
df_sin_carlos = df.drop(4)
print(df_sin_carlos)
#   Nombre  Edad     Ciudad   Profesión  Año_Nacimiento
# 0    Ana    25     Madrid   Ingeniera            1998
# 1   Juan    30  Barcelona      Médico            1993
# 2  María    22    Sevilla   Profesora            2001
# 3  Pedro    40   Valencia  Arquitecto            1983
# 5  Laura    28   Zaragoza  Diseñadora            1995

# Reiniciar índices
df_reset = df_sin_carlos.reset_index(drop=True)
print(df_reset)
#   Nombre  Edad     Ciudad   Profesión  Año_Nacimiento
# 0    Ana    25     Madrid   Ingeniera            1998
# 1   Juan    30  Barcelona      Médico            1993
# 2  María    22    Sevilla   Profesora            2001
# 3  Pedro    40   Valencia  Arquitecto            1983
# 4  Laura    28   Zaragoza  Diseñadora            1995

Manejo de datos faltantes

En el análisis de datos reales, es común encontrar valores faltantes. Pandas proporciona herramientas para detectarlos y tratarlos:

# Crear un DataFrame con valores nulos
datos_incompletos = {
    'A': [1, 2, np.nan, 4],
    'B': [5, np.nan, np.nan, 8],
    'C': [9, 10, 11, 12]
}
df_nulos = pd.DataFrame(datos_incompletos)
print(df_nulos)
#      A    B   C
# 0  1.0  5.0   9
# 1  2.0  NaN  10
# 2  NaN  NaN  11
# 3  4.0  8.0  12

# Detectar valores nulos
print(df_nulos.isnull())
#        A      B      C
# 0  False  False  False
# 1  False   True  False
# 2   True   True  False
# 3  False  False  False

# Contar valores nulos por columna
print(df_nulos.isnull().sum())
# A    1
# B    2
# C    0
# dtype: int64

# Eliminar filas con valores nulos
print(df_nulos.dropna())
#      A    B   C
# 0  1.0  5.0   9
# 3  4.0  8.0  12

# Eliminar columnas con valores nulos
print(df_nulos.dropna(axis=1))
#     C
# 0   9
# 1  10
# 2  11
# 3  12

# Rellenar valores nulos
print(df_nulos.fillna(0))  # Reemplazar por cero
#      A    B   C
# 0  1.0  5.0   9
# 1  2.0  0.0  10
# 2  0.0  0.0  11
# 3  4.0  8.0  12

# Rellenar con el valor anterior/siguiente
print(df_nulos.fillna(method='ffill'))  # forward fill
#      A    B   C
# 0  1.0  5.0   9
# 1  2.0  5.0  10
# 2  2.0  5.0  11
# 3  4.0  8.0  12

print(df_nulos.fillna(method='bfill'))  # backward fill
#      A    B   C
# 0  1.0  5.0   9
# 1  2.0  8.0  10
# 2  4.0  8.0  11
# 3  4.0  8.0  12

Operaciones estadísticas y agrupación

Estadísticas descriptivas

# Volvamos a nuestro DataFrame de personas
print(df_reset)
#   Nombre  Edad     Ciudad   Profesión  Año_Nacimiento
# 0    Ana    25     Madrid   Ingeniera            1998
# 1   Juan    30  Barcelona      Médico            1993
# 2  María    22    Sevilla   Profesora            2001
# 3  Pedro    40   Valencia  Arquitecto            1983
# 4  Laura    28   Zaragoza  Diseñadora            1995

# Estadísticas de columnas numéricas
print(df_reset.describe())
#             Edad  Año_Nacimiento
# count   5.000000        5.000000
# mean   29.000000     1994.000000
# std     6.782330        7.106335
# min    22.000000     1983.000000
# 25%    25.000000     1988.000000
# 50%    28.000000     1995.000000
# 75%    30.000000     1998.000000
# max    40.000000     2001.000000

# Estadísticas individuales
print(f"Media de edad: {df_reset['Edad'].mean()}")
print(f"Edad mínima: {df_reset['Edad'].min()}")
print(f"Edad máxima: {df_reset['Edad'].max()}")

Agrupación de datos

La función groupby() permite agrupar datos según criterios específicos:

# Crear un DataFrame más grande para el ejemplo
datos_ventas = {
    'Fecha': pd.date_range('2023-01-01', periods=10),
    'Vendedor': ['Ana', 'Juan', 'María', 'Pedro', 'Ana', 'Juan', 'María', 'Pedro', 'Ana', 'Juan'],
    'Producto': ['Laptop', 'Móvil', 'Tablet', 'Laptop', 'Móvil', 'Tablet', 'Laptop', 'Móvil', 'Tablet', 'Laptop'],
    'Unidades': [5, 10, 8, 12, 6, 9, 7, 11, 4, 10],
    'Precio': [800, 500, 300, 800, 550, 320, 780, 520, 310, 790]
}
df_ventas = pd.DataFrame(datos_ventas)
df_ventas['Total'] = df_ventas['Unidades'] * df_ventas['Precio']
print(df_ventas)
#         Fecha Vendedor Producto  Unidades  Precio   Total
# 0 2023-01-01      Ana   Laptop         5     800    4000
# 1 2023-01-02     Juan    Móvil        10     500    5000
# 2 2023-01-03    María   Tablet         8     300    2400
# 3 2023-01-04    Pedro   Laptop        12     800    9600
# 4 2023-01-05      Ana    Móvil         6     550    3300
# 5 2023-01-06     Juan   Tablet         9     320    2880
# 6 2023-01-07    María   Laptop         7     780    5460
# 7 2023-01-08    Pedro    Móvil        11     520    5720
# 8 2023-01-09      Ana   Tablet         4     310    1240
# 9 2023-01-10     Juan   Laptop        10     790    7900

# Agrupar por vendedor y calcular el total de ventas
ventas_por_vendedor = df_ventas.groupby('Vendedor')['Total'].sum()
print(ventas_por_vendedor)
# Vendedor
# Ana       8540
# Juan     15780
# María     7860
# Pedro    15320
# Name: Total, dtype: int64

# Agrupar por producto y calcular unidades vendidas
unidades_por_producto = df_ventas.groupby('Producto')['Unidades'].sum()
print(unidades_por_producto)
# Producto
# Laptop    34
# Móvil     27
# Tablet    21
# Name: Unidades, dtype: int64

# Múltiples estadísticas por grupo
resumen_por_vendedor = df_ventas.groupby('Vendedor').agg({
    'Total': ['sum', 'mean'],
    'Unidades': ['sum', 'mean', 'max']
})
print(resumen_por_vendedor)
#          Total           Unidades          
#           sum      mean      sum mean  max
# Vendedor                                  
# Ana      8540  2846.667       15  5.0    6
# Juan    15780  5260.000       29  9.7   10
# María    7860  3930.000       15  7.5    8
# Pedro   15320  7660.000       23 11.5   12

# Agrupar por múltiples columnas
resumen_detallado = df_ventas.groupby(['Vendedor', 'Producto'])['Total'].sum()
print(resumen_detallado)
# Vendedor  Producto
# Ana       Laptop      4000
#           Móvil       3300
#           Tablet      1240
# Juan      Laptop      7900
#           Móvil       5000
#           Tablet      2880
# María     Laptop      5460
#           Tablet      2400
# Pedro     Laptop      9600
#           Móvil       5720
# Name: Total, dtype: int64

Fusión y combinación de datos

Pandas proporciona diferentes formas de combinar DataFrames:

Concatenación

# Dividir nuestro DataFrame en dos
df_parte1 = df_ventas.iloc[0:5]
df_parte2 = df_ventas.iloc[5:10]

# Concatenar verticalmente (unir filas)
df_concat_v = pd.concat([df_parte1, df_parte2])
print(df_concat_v)  # Resultado igual a df_ventas original

# Concatenar horizontalmente (unir columnas)
df_a = df_ventas[['Fecha', 'Vendedor', 'Producto']]
df_b = df_ventas[['Unidades', 'Precio', 'Total']]
df_concat_h = pd.concat([df_a, df_b], axis=1)
print(df_concat_h)  # Resultado igual a df_ventas original

Merge (Uniones tipo SQL)

# Crear DataFrames para el ejemplo
clientes = pd.DataFrame({
    'ID': [1, 2, 3, 4, 5],
    'Nombre': ['Ana', 'Juan', 'María', 'Pedro', 'Laura'],
    'Ciudad': ['Madrid', 'Barcelona', 'Sevilla', 'Valencia', 'Zaragoza']
})

pedidos = pd.DataFrame({
    'Pedido_ID': [101, 102, 103, 104, 105, 106],
    'Cliente_ID': [1, 2, 3, 1, 4, 2],
    'Producto': ['Laptop', 'Móvil', 'Tablet', 'Monitor', 'Impresora', 'Altavoces'],
    'Monto': [800, 500, 300, 200, 150, 80]
})

# Inner join (solo registros que coinciden en ambos DataFrames)
df_inner = pd.merge(clientes, pedidos, left_on='ID', right_on='Cliente_ID')
print(df_inner)
#    ID Nombre     Ciudad  Pedido_ID  Cliente_ID   Producto  Monto
# 0   1    Ana     Madrid        101          1     Laptop    800
# 1   1    Ana     Madrid        104          1    Monitor    200
# 2   2   Juan  Barcelona        102          2      Móvil    500
# 3   2   Juan  Barcelona        106          2  Altavoces     80
# 4   3  María    Sevilla        103          3     Tablet    300
# 5   4  Pedro   Valencia        105          4  Impresora    150

# Left join (todos los registros del DataFrame izquierdo)
df_left = pd.merge(clientes, pedidos, left_on='ID', right_on='Cliente_ID', how='left')
print(df_left)
#    ID Nombre     Ciudad  Pedido_ID  Cliente_ID    Producto  Monto
# 0   1    Ana     Madrid      101.0        1.0      Laptop  800.0
# 1   1    Ana     Madrid      104.0        1.0     Monitor  200.0
# 2   2   Juan  Barcelona      102.0        2.0       Móvil  500.0
# 3   2   Juan  Barcelona      106.0        2.0   Altavoces   80.0
# 4   3  María    Sevilla      103.0        3.0      Tablet  300.0
# 5   4  Pedro   Valencia      105.0        4.0   Impresora  150.0
# 6   5  Laura   Zaragoza        NaN        NaN         NaN    NaN

# Right join (todos los registros del DataFrame derecho)
df_right = pd.merge(clientes, pedidos, left_on='ID', right_on='Cliente_ID', how='right')
print(df_right)  # En este caso, igual que inner join porque todos los pedidos tienen cliente

# Outer join (todos los registros de ambos DataFrames)
df_outer = pd.merge(clientes, pedidos, left_on='ID', right_on='Cliente_ID', how='outer')
print(df_outer)
#    ID Nombre     Ciudad  Pedido_ID  Cliente_ID    Producto  Monto
# 0   1    Ana     Madrid      101.0        1.0      Laptop  800.0
# 1   1    Ana     Madrid      104.0        1.0     Monitor  200.0
# 2   2   Juan  Barcelona      102.0        2.0       Móvil  500.0
# 3   2   Juan  Barcelona      106.0        2.0   Altavoces   80.0
# 4   3  María    Sevilla      103.0        3.0      Tablet  300.0
# 5   4  Pedro   Valencia      105.0        4.0   Impresora  150.0
# 6   5  Laura   Zaragoza        NaN        NaN         NaN    NaN

Operaciones con series temporales

Pandas tiene excelente soporte para trabajar con datos de series temporales:

# Crear una Series con fechas como índice
fechas = pd.date_range('2023-01-01', periods=6)
valores = [100, 105, 110, 115, 120, 125]
serie_temporal = pd.Series(valores, index=fechas)
print(serie_temporal)
# 2023-01-01    100
# 2023-01-02    105
# 2023-01-03    110
# 2023-01-04    115
# 2023-01-05    120
# 2023-01-06    125
# Freq: D, dtype: int64

# Acceder por fecha
print(serie_temporal['2023-01-03'])  # 110

# Rebanado de fechas
print(serie_temporal['2023-01-02':'2023-01-04'])
# 2023-01-02    105
# 2023-01-03    110
# 2023-01-04    115
# Freq: D, dtype: int64

# Remuestreo a frecuencia menor (agrupación temporal)
print(serie_temporal.resample('2D').mean())
# 2023-01-01    102.5
# 2023-01-03    112.5
# 2023-01-05    122.5
# Freq: 2D, dtype: float64

# Operaciones con desplazamiento temporal
print(serie_temporal.shift(1))  # Desplazar un día hacia adelante
# 2023-01-01      NaN
# 2023-01-02    100.0
# 2023-01-03    105.0
# 2023-01-04    110.0
# 2023-01-05    115.0
# 2023-01-06    120.0
# Freq: D, dtype: float64

# Cambio porcentual
print(serie_temporal.pct_change())
# 2023-01-01         NaN
# 2023-01-02    0.050000
# 2023-01-03    0.047619
# 2023-01-04    0.045455
# 2023-01-05    0.043478
# 2023-01-06    0.041667
# Freq: D, dtype: float64

Entrada y salida de datos

Pandas puede leer y escribir datos en varios formatos:

CSV

# Guardar DataFrame a CSV
df_ventas.to_csv('ventas.csv', index=False)

# Leer CSV
df_leido = pd.read_csv('ventas.csv')
print(df_leido.head())

Excel

# Requiere openpyxl o xlrd
# pip install openpyxl

# Guardar DataFrame a Excel
df_ventas.to_excel('ventas.xlsx', sheet_name='Datos', index=False)

# Leer Excel
df_excel = pd.read_excel('ventas.xlsx', sheet_name='Datos')
print(df_excel.head())

SQL

# Requiere SQLAlchemy
# pip install sqlalchemy

from sqlalchemy import create_engine

# Conexión a una base de datos SQLite
engine = create_engine('sqlite:///mi_base_datos.db')

# Guardar DataFrame a una tabla SQL
df_ventas.to_sql('ventas', engine, if_exists='replace', index=False)

# Leer tabla SQL
df_sql = pd.read_sql('SELECT * FROM ventas', engine)
print(df_sql.head())

JSON

# Guardar DataFrame a JSON
df_ventas.to_json('ventas.json')

# Leer JSON
df_json = pd.read_json('ventas.json')
print(df_json.head())

Visualización de datos con Pandas

Pandas integra Matplotlib para crear visualizaciones rápidamente:

# Importar matplotlib (requerido para mostrar gráficos)
import matplotlib.pyplot as plt

# Gráfico de barras
ventas_por_vendedor.plot(kind='bar')
plt.title('Ventas totales por vendedor')
plt.ylabel('Ventas (€)')
plt.tight_layout()
plt.show()

# Gráfico de líneas para serie temporal
serie_temporal.plot()
plt.title('Evolución temporal')
plt.ylabel('Valor')
plt.tight_layout()
plt.show()

# Histograma
df_ventas['Unidades'].plot(kind='hist', bins=5)
plt.title('Distribución de unidades vendidas')
plt.xlabel('Unidades')
plt.tight_layout()
plt.show()

# Gráfico de dispersión
df_ventas.plot.scatter(x='Precio', y='Unidades')
plt.title('Relación entre precio y unidades vendidas')
plt.tight_layout()
plt.show()

Caso práctico: Análisis de ventas

Veamos un ejemplo completo de análisis con Pandas:

# Supongamos que tenemos nuestro DataFrame de ventas
print(df_ventas.head())

# 1. Análisis exploratorio
print("Estadísticas descriptivas:")
print(df_ventas.describe())

# 2. Ventas por día de la semana
df_ventas['DiaSemana'] = df_ventas['Fecha'].dt.day_name()
ventas_dia = df_ventas.groupby('DiaSemana')['Total'].sum()
print("\nVentas por día de la semana:")
print(ventas_dia)

# 3. Producto más vendido por vendedor
top_producto = df_ventas.groupby(['Vendedor', 'Producto'])['Unidades'].sum().reset_index()
idx = top_producto.groupby('Vendedor')['Unidades'].idxmax()
mejor_producto = top_producto.loc[idx]
print("\nProducto más vendido por cada vendedor:")
print(mejor_producto)

# 4. Evolución diaria de ventas
ventas_diarias = df_ventas.groupby('Fecha')['Total'].sum()
print("\nEvolución diaria de ventas:")
print(ventas_diarias)

# 5. Análisis de correlación
print("\nCorrelación entre variables:")
print(df_ventas[['Unidades', 'Precio', 'Total']].corr())

# 6. Visualización de resultados
plt.figure(figsize=(12, 10))

# Gráfico 1: Ventas por vendedor
plt.subplot(2, 2, 1)
ventas_por_vendedor.plot(kind='bar', ax=plt.gca())
plt.title('Ventas por vendedor')
plt.ylabel('Ventas (€)')

# Gráfico 2: Unidades por producto
plt.subplot(2, 2, 2)
unidades_por_producto.plot(kind='pie', autopct='%1.1f%%', ax=plt.gca())
plt.title('Distribución de unidades por producto')

# Gráfico 3: Evolución diaria de ventas
plt.subplot(2, 2, 3)
ventas_diarias.plot(ax=plt.gca())
plt.title('Evolución diaria de ventas')
plt.ylabel('Ventas (€)')

# Gráfico 4: Relación precio-unidades
plt.subplot(2, 2, 4)
df_ventas.plot.scatter(x='Precio', y='Unidades', ax=plt.gca())
plt.title('Relación entre precio y unidades')

plt.tight_layout()
plt.show()

Resumen

Pandas es una herramienta fundamental para el análisis de datos en Python. Proporciona estructuras de datos versátiles como Series y DataFrames, que facilitan la manipulación, limpieza y análisis de datos. Hemos explorado operaciones básicas como selección, filtrado, agrupación, fusión de datos y trabajo con series temporales. También hemos visto cómo importar y exportar datos en diferentes formatos y crear visualizaciones sencillas. Pandas es extremadamente útil tanto para análisis exploratorios rápidos como para preparar datos para análisis más complejos. En los siguientes temas, exploraremos herramientas más específicas para visualización de datos, como Matplotlib, que complementan perfectamente a Pandas.