← Volver al Blog

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 Team15 min de lecturaCiencia de Datos
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

15 min lectura

# 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

Interoperabilidad:
  • Formato estándar para APIs REST
  • Compatible con todas las plataformas
  • Amplio soporte en librerías

Casos de Uso:
  • 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!

Share:

Artículos Relacionados

Read in English