EstevezAlvarez
Python Data analysis Pandas

Python for data analysis: from CSV to insight

Data analysis in Python follows a well-defined workflow: load, explore, clean, transform, analyze and visualize. Mastering this cycle with pandas and matplotlib solves 80% of real-world problems.

Load CSV / DB / API Explore shape, dtypes, nulls Clean nulls, types, outliers Transform groupby, merge, pivot Analyze statistics, KPIs Visualize charts, reports
The standard analysis workflow: data loading → exploration → cleaning → transformation → statistical analysis → visualization.

The Python data stack

Three libraries cover almost every case:

pip install pandas numpy matplotlib seaborn

Load and explore the data

The first step is always to understand the dataset’s shape and quality before transforming anything.

import pandas as pd
import numpy as np

# Cargar desde CSV
df = pd.read_csv("ventas.csv", parse_dates=["fecha"])

# Primeras filas
print(df.head())

# Forma y tipos
print(df.shape)        # (filas, columnas)
print(df.dtypes)       # tipo de cada columna
print(df.info())       # nulos + tipos en una línea

# Estadísticas descriptivas
print(df.describe())

# Valores nulos por columna
print(df.isnull().sum())
fecha producto cantidad precio_unit total index 0 2026-01-03 Manzana 50 1.20 60.00 1 2026-01-03 Naranja 30 0.90 27.00 2 2026-01-04 Manzana NaN 1.20 NaN ← null (NaN) datetime64 object (str) float64 float64 float64 int64 dtype → df.shape = (3, 5) · 3 rows, 5 columns · 1 null value in 'cantidad'
Anatomy of a DataFrame: index (row), typed columns (dtype), and NaN values in empty cells that need to be handled before analysis.

Clean and transform

Cleaning is the most time-consuming phase in real projects. The most common problems are nulls, incorrect types and duplicates.

# Eliminar filas con nulos en columnas críticas
df = df.dropna(subset=["cantidad", "precio_unit"])

# Rellenar nulos opcionales con la mediana
df["descuento"] = df["descuento"].fillna(df["descuento"].median())

# Convertir tipos
df["fecha"] = pd.to_datetime(df["fecha"])
df["cantidad"] = df["cantidad"].astype(int)

# Eliminar duplicados
df = df.drop_duplicates()

# Crear columna calculada
df["total"] = df["cantidad"] * df["precio_unit"]

# Extraer componentes de fecha
df["mes"]  = df["fecha"].dt.month
df["anio"] = df["fecha"].dt.year

Analyze: groupby and aggregations

groupby is the most powerful pandas operation. It answers questions such as “how much did we sell of each product each month?” in a single line.

# Ventas totales por producto
ventas_producto = (
    df.groupby("producto")["total"]
    .agg(["sum", "mean", "count"])
    .rename(columns={"sum": "total_ventas", "mean": "ticket_medio", "count": "n_transacciones"})
    .sort_values("total_ventas", ascending=False)
)
print(ventas_producto)

# Evolución mensual
evolucion = df.groupby(["anio", "mes"])["total"].sum().reset_index()
print(evolucion)

# Pivot table: producto vs mes
pivot = df.pivot_table(
    values="total",
    index="producto",
    columns="mes",
    aggfunc="sum",
    fill_value=0
)
print(pivot)

Visualize results

import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# Gráfica de barras — top productos
ventas_producto["total_ventas"].head(10).plot(
    kind="bar", ax=axes[0], color="#4f8cff", edgecolor="white"
)
axes[0].set_title("Top 10 productos por ventas")
axes[0].set_xlabel("")
axes[0].set_ylabel("Total €")
axes[0].tick_params(axis="x", rotation=45)

# Evolución temporal
evolucion.plot(
    x="mes", y="total", kind="line",
    ax=axes[1], marker="o", color="#4f8cff"
)
axes[1].set_title("Evolución mensual de ventas")
axes[1].set_xlabel("Mes")
axes[1].set_ylabel("Total €")

plt.tight_layout()
plt.savefig("informe_ventas.png", dpi=150)
plt.show()

Export results

# Exportar a Excel con múltiples hojas
with pd.ExcelWriter("informe.xlsx", engine="openpyxl") as writer:
    ventas_producto.to_excel(writer, sheet_name="Por producto")
    evolucion.to_excel(writer, sheet_name="Evolución mensual", index=False)
    pivot.to_excel(writer, sheet_name="Pivot producto-mes")

# Exportar a CSV limpio
df.to_csv("ventas_limpias.csv", index=False, encoding="utf-8")

# Cargar en PostgreSQL
from sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@localhost/ventas_db")
df.to_sql("ventas", engine, if_exists="replace", index=False)

Next steps

  1. Polars — an alternative to pandas, significantly faster on large datasets (>1M rows) thanks to lazy execution and native multicore support.
  2. DuckDB — SQL directly over DataFrames or Parquet files, ideal for serverless ad hoc analysis.
  3. scikit-learn — when exploratory analysis reveals patterns worth modeling with machine learning.
  4. Jupyter + nbconvert — for documented, reproducible analysis workflows that can be exported to HTML or PDF.