JSON en Ciencia de Datos: Pandas, NumPy y Análisis de Datos
Aprende a usar JSON en ciencia de datos con Python. Incluye Pandas, NumPy, visualización y casos de uso prácticos.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# JSON en Ciencia de Datos: Pandas, NumPy y Análisis de Datos
JSON es un formato fundamental en ciencia de datos para almacenar y intercambiar datos. Esta guía completa te enseñará cómo trabajar con JSON usando las herramientas más populares de Python.
¿Por Qué JSON en Ciencia de Datos?
Ventajas
Flexibilidad:- Estructura anidada para datos complejos
- No requiere esquema fijo
- Fácil de leer para humanos
- Formato estándar para APIs REST
- Compatible con todas las plataformas
- Amplio soporte en librerías
- Datos de APIs web
- Logs y eventos
- Configuraciones
- Datasets con estructura variable
- Respuestas de servicios cloud
Pandas y JSON
Instalación
pip install pandas numpy matplotlib seaborn
Leer JSON con Pandas
import pandas as pd
# Desde archivo
df = pd.read_json('datos.json')
# Desde string
json_str = '{"nombre": "Ana", "edad": 28}'
df = pd.read_json(json_str)
# Desde URL
url = 'https://api.ejemplo.com/datos.json'
df = pd.read_json(url)
# Con orientación específica
df = pd.read_json('datos.json', orient='records')
Orientaciones de JSON en Pandas
Orient='records'
# JSON: Array de objetos
[
{"nombre": "Ana", "edad": 28, "ciudad": "Madrid"},
{"nombre": "Carlos", "edad": 35, "ciudad": "Barcelona"}
]
df = pd.read_json('usuarios.json', orient='records')
print(df)
# nombre edad ciudad
# 0 Ana 28 Madrid
# 1 Carlos 35 Barcelona
Orient='index'
# JSON: Objeto con índices como claves
{
"0": {"nombre": "Ana", "edad": 28},
"1": {"nombre": "Carlos", "edad": 35}
}
df = pd.read_json('datos.json', orient='index')
Orient='columns'
# JSON: Columnas como claves principales
{
"nombre": {"0": "Ana", "1": "Carlos"},
"edad": {"0": 28, "1": 35}
}
df = pd.read_json('datos.json', orient='columns')
Orient='values'
# JSON: Array 2D
[
["Ana", 28, "Madrid"],
["Carlos", 35, "Barcelona"]
]
df = pd.read_json('datos.json', orient='values')
df.columns = ['nombre', 'edad', 'ciudad']
JSON Anidado a DataFrame
import pandas as pd
from pandas import json_normalize
# JSON anidado
datos = {
"usuarios": [
{
"id": 1,
"nombre": "Ana",
"contacto": {
"email": "ana@ejemplo.com",
"telefono": "+34600111222"
},
"habilidades": ["Python", "SQL", "R"]
},
{
"id": 2,
"nombre": "Carlos",
"contacto": {
"email": "carlos@ejemplo.com",
"telefono": "+34600333444"
},
"habilidades": ["JavaScript", "Python"]
}
]
}
# Normalizar JSON anidado
df = json_normalize(datos['usuarios'])
print(df)
# id nombre contacto.email contacto.telefono habilidades
# 0 1 Ana ana@ejemplo.com +34600111222 [Python, SQL, R]
# 1 2 Carlos carlos@ejemplo.com +34600333444 [JavaScript, Python]
# Especificar nivel de anidación
df = json_normalize(
datos['usuarios'],
sep='_' # Usar _ en vez de . para columnas anidadas
)
JSON con Arrays Anidados
import pandas as pd
from pandas import json_normalize
datos = {
"nombre": "TechCorp",
"empleados": [
{
"nombre": "Ana",
"proyectos": [
{"nombre": "Proyecto A", "horas": 120},
{"nombre": "Proyecto B", "horas": 80}
]
},
{
"nombre": "Carlos",
"proyectos": [
{"nombre": "Proyecto C", "horas": 150}
]
}
]
}
# Expandir arrays anidados
df = json_normalize(
datos,
record_path=['empleados', 'proyectos'],
meta=[
['nombre'], # nombre de la empresa
['empleados', 'nombre'] # nombre del empleado
],
meta_prefix='empresa_',
record_prefix='proyecto_'
)
print(df)
# proyecto_nombre proyecto_horas empresa_nombre empresa_empleados.nombre
# 0 Proyecto A 120 TechCorp Ana
# 1 Proyecto B 80 TechCorp Ana
# 2 Proyecto C 150 TechCorp Carlos
Escribir DataFrame a JSON
import pandas as pd
df = pd.DataFrame({
'nombre': ['Ana', 'Carlos', 'María'],
'edad': [28, 35, 31],
'ciudad': ['Madrid', 'Barcelona', 'Valencia']
})
# Escribir a archivo
df.to_json('salida.json', orient='records', indent=2)
# Como string
json_str = df.to_json(orient='records', force_ascii=False)
# Con compresión
df.to_json('datos.json.gz', orient='records', compression='gzip')
# Líneas (JSONLines)
df.to_json('datos.jsonl', orient='records', lines=True)
JSONLines para Big Data
import pandas as pd
# Escribir JSONLines (un JSON por línea)
df.to_json('datos.jsonl', orient='records', lines=True)
# Leer JSONLines
df = pd.read_json('datos.jsonl', orient='records', lines=True)
# Leer en chunks para archivos grandes
chunks = []
for chunk in pd.read_json('datos_grandes.jsonl', lines=True, chunksize=10000):
# Procesar cada chunk
chunks.append(chunk[chunk['edad'] > 30])
df_filtrado = pd.concat(chunks, ignore_index=True)
NumPy y JSON
Convertir Arrays NumPy a JSON
import numpy as np
import json
# Array NumPy
arr = np.array([[1, 2, 3], [4, 5, 6]])
# Convertir a lista y luego a JSON
json_str = json.dumps(arr.tolist())
print(json_str)
# [[1, 2, 3], [4, 5, 6]]
# Con custom encoder para tipos NumPy
class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
return super().default(obj)
datos = {
'valores': np.array([1, 2, 3]),
'matriz': np.array([[1, 2], [3, 4]]),
'numero': np.int64(42)
}
json_str = json.dumps(datos, cls=NumpyEncoder, indent=2)
Cargar JSON a NumPy
import numpy as np
import json
# Leer JSON
with open('datos.json') as f:
datos = json.load(f)
# Convertir a array NumPy
arr = np.array(datos['valores'])
# Para datos numéricos homogéneos
matriz = np.array(datos['matriz'], dtype=np.float64)
Análisis de Datos con JSON
Ejemplo: Análisis de Ventas
import pandas as pd
import numpy as np
from datetime import datetime
# Cargar datos de ventas desde JSON
ventas = pd.read_json('ventas.json', orient='records')
# Convertir fecha a datetime
ventas['fecha'] = pd.to_datetime(ventas['fecha'])
# Análisis básico
print(f"Total ventas: {ventas['monto'].sum():.2f}€")
print(f"Venta promedio: {ventas['monto'].mean():.2f}€")
print(f"Número de transacciones: {len(ventas)}")
# Agrupar por producto
por_producto = ventas.groupby('producto').agg({
'monto': ['sum', 'mean', 'count'],
'cantidad': 'sum'
})
print(por_producto)
# Ventas por mes
ventas['mes'] = ventas['fecha'].dt.to_period('M')
por_mes = ventas.groupby('mes')['monto'].sum()
print(por_mes)
# Top 10 productos
top_productos = ventas.groupby('producto')['monto'].sum() .sort_values(ascending=False) .head(10)
print(top_productos)
Ejemplo: Análisis de APIs
import pandas as pd
import requests
from pandas import json_normalize
# Obtener datos de API
respuesta = requests.get('https://api.github.com/users/python/repos')
repos = respuesta.json()
# Normalizar a DataFrame
df = json_normalize(repos)
# Seleccionar columnas relevantes
df_repos = df[[
'name',
'stargazers_count',
'forks_count',
'open_issues_count',
'created_at',
'language'
]]
# Análisis
print("Repositorios por lenguaje:")
print(df_repos['language'].value_counts())
print("\nEstadísticas de stars:")
print(df_repos['stargazers_count'].describe())
# Repos más populares
top_repos = df_repos.nlargest(5, 'stargazers_count')
print("\nTop 5 repositorios:")
print(top_repos[['name', 'stargazers_count']])
Limpieza de Datos JSON
import pandas as pd
import numpy as np
# Cargar datos
df = pd.read_json('datos_sucios.json', orient='records')
# Manejar valores nulos
print(f"Valores nulos por columna:\n{df.isnull().sum()}")
# Rellenar nulos
df['edad'].fillna(df['edad'].median(), inplace=True)
df['ciudad'].fillna('Desconocida', inplace=True)
# Eliminar duplicados
df.drop_duplicates(subset=['email'], inplace=True)
# Normalizar strings
df['nombre'] = df['nombre'].str.strip().str.title()
df['email'] = df['email'].str.lower()
# Convertir tipos
df['edad'] = df['edad'].astype(int)
df['fecha'] = pd.to_datetime(df['fecha'])
# Validar rangos
df = df[df['edad'].between(0, 120)]
df = df[df['email'].str.contains('@')]
# Guardar datos limpios
df.to_json('datos_limpios.json', orient='records', indent=2)
Visualización de Datos JSON
Matplotlib
import pandas as pd
import matplotlib.pyplot as plt
# Cargar datos
df = pd.read_json('ventas.json', orient='records')
df['fecha'] = pd.to_datetime(df['fecha'])
# Gráfico de línea: Ventas por mes
ventas_mes = df.groupby(df['fecha'].dt.to_period('M'))['monto'].sum()
plt.figure(figsize=(12, 6))
ventas_mes.plot(kind='line', marker='o')
plt.title('Ventas Mensuales')
plt.xlabel('Mes')
plt.ylabel('Monto (€)')
plt.grid(True)
plt.tight_layout()
plt.savefig('ventas_mensuales.png')
plt.show()
# Gráfico de barras: Top productos
top_productos = df.groupby('producto')['monto'].sum() .sort_values(ascending=False).head(10)
plt.figure(figsize=(12, 6))
top_productos.plot(kind='barh')
plt.title('Top 10 Productos por Ventas')
plt.xlabel('Monto (€)')
plt.ylabel('Producto')
plt.tight_layout()
plt.savefig('top_productos.png')
plt.show()
Seaborn
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Cargar datos
df = pd.read_json('empleados.json', orient='records')
# Configurar estilo
sns.set_theme(style="whitegrid")
# Distribución de salarios
plt.figure(figsize=(10, 6))
sns.histplot(data=df, x='salario', bins=30, kde=True)
plt.title('Distribución de Salarios')
plt.xlabel('Salario (€)')
plt.ylabel('Frecuencia')
plt.tight_layout()
plt.savefig('distribucion_salarios.png')
# Box plot por departamento
plt.figure(figsize=(12, 6))
sns.boxplot(data=df, x='departamento', y='salario')
plt.title('Salarios por Departamento')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('salarios_departamento.png')
# Scatter plot: Edad vs Salario
plt.figure(figsize=(10, 6))
sns.scatterplot(data=df, x='edad', y='salario', hue='departamento', size='experiencia')
plt.title('Relación Edad-Salario')
plt.tight_layout()
plt.savefig('edad_salario.png')
Plotly (Interactivo)
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
# Cargar datos
df = pd.read_json('ventas.json', orient='records')
df['fecha'] = pd.to_datetime(df['fecha'])
# Gráfico interactivo de línea
fig = px.line(
df.groupby('fecha')['monto'].sum().reset_index(),
x='fecha',
y='monto',
title='Evolución de Ventas'
)
fig.write_html('ventas_interactivo.html')
# Treemap de ventas por categoría
ventas_cat = df.groupby(['categoria', 'producto'])['monto'].sum().reset_index()
fig = px.treemap(
ventas_cat,
path=['categoria', 'producto'],
values='monto',
title='Ventas por Categoría y Producto'
)
fig.write_html('treemap_ventas.html')
# Sunburst chart
fig = px.sunburst(
ventas_cat,
path=['categoria', 'producto'],
values='monto'
)
fig.write_html('sunburst_ventas.html')
Machine Learning con Datos JSON
Preparar Datos para ML
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
# Cargar datos
df = pd.read_json('clientes.json', orient='records')
# Codificar variables categóricas
le = LabelEncoder()
df['genero_encoded'] = le.fit_transform(df['genero'])
df['ciudad_encoded'] = le.fit_transform(df['ciudad'])
# One-hot encoding
df_encoded = pd.get_dummies(df, columns=['categoria'], prefix='cat')
# Normalizar features numéricas
scaler = StandardScaler()
columnas_num = ['edad', 'ingreso', 'gasto_mensual']
df[columnas_num] = scaler.fit_transform(df[columnas_num])
# Dividir en train/test
X = df.drop(['compra_realizada'], axis=1)
y = df['compra_realizada']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
Ejemplo: Predicción con Random Forest
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import json
# Cargar y preparar datos
df = pd.read_json('datos_clientes.json', orient='records')
# Features y target
X = df[['edad', 'ingreso', 'visitas', 'tiempo_cliente']]
y = df['churn']
# Dividir datos
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Entrenar modelo
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# Evaluar
y_pred = rf.predict(X_test)
print(classification_report(y_test, y_pred))
# Feature importance
importancia = pd.DataFrame({
'feature': X.columns,
'importancia': rf.feature_importances_
}).sort_values('importancia', ascending=False)
print("\nImportancia de features:")
print(importancia)
# Guardar resultados en JSON
resultados = {
'precision': float(rf.score(X_test, y_test)),
'feature_importance': importancia.to_dict('records'),
'matriz_confusion': confusion_matrix(y_test, y_pred).tolist()
}
with open('resultados_modelo.json', 'w') as f:
json.dump(resultados, f, indent=2)
Integración con Bases de Datos
MongoDB (JSON nativo)
from pymongo import MongoClient
import pandas as pd
import json
# Conectar a MongoDB
client = MongoClient('mongodb://localhost:27017/')
db = client['mi_base_datos']
coleccion = db['usuarios']
# Insertar desde JSON
with open('usuarios.json') as f:
datos = json.load(f)
coleccion.insert_many(datos)
# Query y convertir a DataFrame
cursor = coleccion.find({'edad': {'$gt': 25}})
df = pd.DataFrame(list(cursor))
# Aggregation pipeline
pipeline = [
{'$match': {'activo': True}},
{'$group': {
'_id': '$ciudad',
'count': {'$sum': 1},
'edad_promedio': {'$avg': '$edad'}
}},
{'$sort': {'count': -1}}
]
resultados = list(coleccion.aggregate(pipeline))
df_agg = pd.DataFrame(resultados)
PostgreSQL con JSON
import pandas as pd
from sqlalchemy import create_engine
import json
# Conectar a PostgreSQL
engine = create_engine('postgresql://user:pass@localhost/dbname')
# Cargar JSON a DataFrame
df = pd.read_json('datos.json', orient='records')
# Guardar en PostgreSQL
df.to_sql('mi_tabla', engine, if_exists='replace', index=False)
# Consultar y obtener JSON
query = """
SELECT
json_agg(row_to_json(t)) as datos
FROM mi_tabla t
WHERE edad > 25
"""
resultado = pd.read_sql(query, engine)
datos_json = resultado['datos'][0]
# Guardar resultado como JSON
with open('resultado.json', 'w') as f:
json.dump(datos_json, f, indent=2)
Mejores Prácticas
1. Manejar Archivos Grandes
import pandas as pd
import json
# Leer en chunks
def procesar_json_grande(archivo, chunksize=10000):
resultados = []
for chunk in pd.read_json(archivo, lines=True, chunksize=chunksize):
# Procesar cada chunk
procesado = chunk[chunk['activo'] == True]
resultados.append(procesado)
return pd.concat(resultados, ignore_index=True)
# Streaming con ijson para JSON muy grandes
import ijson
def contar_usuarios(archivo):
count = 0
with open(archivo, 'rb') as f:
for usuario in ijson.items(f, 'usuarios.item'):
if usuario['edad'] > 25:
count += 1
return count
2. Validación de Datos
import pandas as pd
from cerberus import Validator
# Definir schema
schema = {
'nombre': {'type': 'string', 'required': True},
'edad': {'type': 'integer', 'min': 0, 'max': 150},
'email': {'type': 'string', 'regex': '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'}
}
validator = Validator(schema)
# Validar datos
datos = pd.read_json('usuarios.json', orient='records')
errores = []
for idx, row in datos.iterrows():
if not validator.validate(row.to_dict()):
errores.append({'fila': idx, 'errores': validator.errors})
if errores:
print(f"Se encontraron {len(errores)} errores de validación")
pd.DataFrame(errores).to_json('errores_validacion.json', orient='records')
3. Optimización de Memoria
import pandas as pd
# Especificar tipos de datos al leer
dtypes = {
'id': 'int32',
'nombre': 'string',
'edad': 'int8',
'activo': 'bool'
}
df = pd.read_json('datos.json', orient='records', dtype=dtypes)
# Convertir a tipos eficientes
df['categoria'] = df['categoria'].astype('category')
df['fecha'] = pd.to_datetime(df['fecha'])
print(f"Uso de memoria: {df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
Conclusión
JSON es un formato versátil para ciencia de datos, especialmente al trabajar con APIs y datos semi-estructurados. Pandas y NumPy proporcionan herramientas poderosas para procesar JSON eficientemente.
Puntos Clave
- Pandas facilita conversión entre JSON y DataFrames
- json_normalize es esencial para JSON anidado
- JSONLines es ideal para big data
- Visualiza datos con Matplotlib, Seaborn o Plotly
- Valida siempre datos de fuentes externas
¡Domina JSON para análisis de datos más eficientes!
Artículos Relacionados
Python y JSON: Guía Completa del Módulo json
Aprende a trabajar con JSON en Python usando el módulo json. Incluye parsing, serialización, archivos JSON y mejores prácticas.
Convertir JSON a Excel: Guía Completa con Python, JavaScript y Herramientas
Aprende a convertir JSON a Excel usando Python (pandas), JavaScript (xlsx), herramientas online y más. Incluye ejemplos prácticos y mejores prácticas.
Trabajar con Archivos JSON Grandes: Técnicas de Streaming y Optimización
Aprende a manejar archivos JSON de varios GB con streaming, procesamiento incremental y optimización de memoria.