import pandas as pd
import numpy as np
import math
import [Link] as plt
————————————————————————Regresión lineal
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from [Link] import mean_squared_error, r2_score, mean_absolute_error
————————————————————————. Árbol de decisión
from sklearn import tree
from [Link] import DecisionTreeClassifier
from [Link] import OrdinalEncoder
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from [Link] import accuracy_score, confusion_matrix
———————————————————————— kmeans
from [Link] import KMeans
import os
from [Link] import silhouette_score
from [Link] import StandardScaler
———————————————————————— corpus
import re
import nltk
import spacy
from [Link] import SnowballStemmer
from [Link] import FreqDist
from wordcloud import WordCloud
———————————————————————— extracción
import requests
from bs4 import BeautifulSoup
———————————————————————— mapas
import geopandas as gpd
from [Link] import Point
import mapclassify
• df.set_index("nomCol", inplace=True) Modifica el índice del DataFrame para usar la columna "nomCol".
inplace=True aplica el cambio sin crear copia.
• [Link] = listaConNomsCols [A,B,C,D] Asigna nuevos nombres a todas las columnas según la lista
listaConNomsCols.
• [Link] Devuelve el objeto con los nombres de las columnas.
• [Link] Devuelve una tupla (num_filas, num_columnas).
• [Link] Devuelve el tipo de dato de cada columna.
•[Link]() Muestra resumen: número de filas, nombres y tipos de columnas y conteo de valores no nulos/NaN.
• [Link] Devuelve los valores como arreglo (matriz) NumPy.
• [Link]() Mínimo por columna numérica (por defecto, axis=0).
• [Link]() Máximo por columna numérica. numeric_only=True
• [Link]() Promedio por columna numérica.
• [Link]() Mediana por columna numérica.
• [Link]() Desviación estándar por columna numérica.
• [Link]() Moda de los datos por columna (valor más frecuente).
Nota rápida: en las funciones estadísticas, si quieres operar por renglón usa axis=1 (por ejemplo, [Link](axis=1)).
• [Link]— llamar al index
• [Link]() Estadísticas de columnas numéricas: count, mean, std, min, Q1, median, Q3, max.
• [Link](n) Primeros n registros. Default n=5.
• [Link](n) Últimos n registros. Default n=5.
• [Link](n) Muestra aleatoria de n filas. Alternativa: [Link](frac=0.1).
• len(df) arroja número de renglones en el DF
• [Link]() Suma por columna numérica (o cuenta True en booleanas).
[Link]() Cuenta cuántos valores no nulos (no NaN) hay en cada columna, sin importar si son números, strings o
booleanos.
• [Link](axis=0) Índice/etiqueta del máximo por columna (axis=0) o por fila (axis=1).
• [Link](axis=0) Índice/etiqueta del mínimo por columna o por fila.
• [Link](columns={'viejoNom':'nuevoNom'}) Renombra columnas. Usa inplace=True si no quieres copiar.
• [Link](valorExistente, valorReemplazo) Reemplaza valores en todo el DataFrame.
Varios a la vez: [Link]({v1:n1, v2:n2}) o con patrones: [Link]({r'\s+':'_'}, regex=True).
• df['nomCol'] Selecciona la columna nomCol como Series.
• df['nomCol'][numRen] Elemento de nomCol en el renglón numRen. Recomendado: [Link][numRen, 'nomCol'].
• df[listaConNomsCol] Subconjunto de columnas. Ejemplo: df[['col1','col2']] crea un nuevo DataFrame.
• df.sort_index(ascending=False) Ordena por índice de filas. ascending=True es el default.
• df.sort_values(by='nom_columna', ascending=False) Ordena por valores de una columna.
• [Link][fila, columna] Selección por posición entera. Acepta slices y listas.
• [Link][fila, columna] Selección por etiqueta. Acepta listas y slicing por etiqueta.
• [Link][num_fila]—num_fila=index • [Link][condición, "columnas"]
• [Link][num_fila, "columna"] • [Link][df["editorial"] == "Planeta", "titulo"]
• [Link][[lista_filas], ["lista_columnas"]] • [Link][df[“paginas”]>300]
num_lib_ed = [Link](‘editorial’)[[‘titulo’]].count() [Link]("editorial").agg({"titulo":"count",
Para graficar = [Link](‘editorial’)[‘titulo’].count() "paginas":"mean"})
Caso 1 dataframe caso 2 serie
df[['PRECIO_U', 'CANT', 'TOTAL']].agg(['sum', 'mean'])
[Link]("editorial")[["paginas"]].agg(["sum","mean"])
• Cambiar a numérico- df['nomCol'] = pd.to_numeric(df['nomCol'], errors='coerce') → convierte a número; los
no convertibles quedan como NaN.
• df['nomCol'] = df['nomCol'].astype(int) → a enteros. No debe haber NaN en la columna.
• df['nomCol'] = df['nomCol'].astype(float) → a flotantes. No debe haber NaN en la columna.
• Cambiar a texto- df['nomCol'] = df['nomCol'].astype(str) → a string.
• Cambiar a categoría- df['nomCol'] = df['nomCol'].astype('category') → a category.
Notas rápidas
• Cambiar a booleano- df['nomCol'] = df['nomCol'].astype(bool) → a bool.
• Con errors='coerce', todo
• [Link] —i = int, f = float, b = bool, 0 = object, U = string Unicode, S = bytes, valor no convertible se
M = datetime64, m = timedelta64, c = complex. Para saber de la columna vuelve NaN.
Contenido de cada registro type(df['nomCol'] [0]) • Para columnas con NaN que
deban ser enteras, puedes
usar df['nomCol'] =
df['nomCol'].astype('Int64').
Gráficas en DataFrame. Uso de matplotlib
Nombres de colores: “red”, ”orange”, ”yellow”, ”green”, ”coral”, ”magenta”, ”
blue”,…
# Histograma- [Link](contenidoGrafica, bins=numBins, color='nombre_color')
# Gráfica de barras vertical- [Link](categorias, contenidoGrafica, color='nombre_color')
# Gráfica de barras horizontal- [Link](indiceEnY, contenidoGrafica, color='nombre_color')
# Boxplot- [Link](df['nomCol']). Boxplot- [Link]([serie1, serie 2])
# Gráfica de dispersión- [Link](df['nomColX'], df['nomColY'])
# Personalización
[Link]('Titulo de la gráfica')
[Link]('Etiqueta en el eje de las Ys')
[Link]('Etiqueta en el eje de las Xs')
# Mostrar gráfica
[Link]()
Varias en una
fig, ax = [Link](numRenDesplegado, numColsDesplegado, figsize=(ancho, largo))
fig, ax = [Link](nrows=1, ncols=2, figsize=(10, 4))
ax[ren,col].tipoGrafica(.....)
ax[ren,col].set_title
ax[ren,col].set_xlabel
ax[ren,col].set_ylabel
[Link]("Titulo al grupo de gráficas"
plt. tight_layout() - para que no se encimen
[Link]()
df = pd.read_csv( '[Link]',
sep=',', # Separador. Por omisión es ','
index_col='nomColQueSeraIndice', # Columna que será el índice
names=[listaConNombresDeColumnas], # Cambia los nombres de las columnas usando una lista
usecols=listaConNombresDeColumnas, # Especifica qué columnas cargar
nrows=numDeFilasALeer, # Número de filas a leer
skiprows=numDeFilasAOmitir, # Filas a omitir (número o lista)
encoding='latin-1' # Codificación del archivo
compression=“zip”
)
df=pd.read_excel('[Link]')
Funciones para datos categóricos
• [Link]() arroja los nombres de los valores categóricos únicos contenidos en una Series
• [Link]() cantidad de valores únicos por columna en un dataframe
• df.value_counts() cantidad de valores por categoría en una Series
Valores faltantes en un dataframe
[Link]() devuelve un DataFrame booleano donde los valores faltantes se marcan True
[Link]() indica las posiciones de los valores no faltantes. Lo contrario a .isna()
[Link](subset=‘columna’) Eliminar valores faltantes: axis=0 elimina por fila =1 columna - subset indica columnas
con ocurrencias de na
df[‘nomCol’].fillna(valor/función)
df[‘nomCol’].ffill() rellena la celda faltante con el elemento anterior (forward fill)
df[‘nomCol’].bfill() rellena la celda faltante con el elemento posterior (backward fill)
Empleo de pandas para resolver problemas de valores duplicados
[Link]() arroja una Series booleana indicando cuál fila es duplicada
df.drop_duplicates() elimina los renglones duplicados del dataframe
Identificación de valores atípicos por técnicas estadísticas: IQR limite_inferior = Q1 - 1.5 * IQR
Q1 = df['minutos_mes'].quantile(0.25) limite_superior = Q3 + 1.5 * IQR
Q3 = df['minutos_mes'].quantile(0.75) print(limite_inferior)
IQR= Q3-Q1 print(limite_superior)
outliers = df[(df['minutos_mes'] < limite_inferior) | (df['minutos_mes'] > limite_superior)]
outliers
[Link][df['minutos_mes'] > limite_superior, 'minutos_mes'] = limite_superior
df
scaler = MinMaxScaler() ó scaler = StandardScaler() from [Link] import MinMaxScaler
from [Link] import StandardScaler
df[‘nomCol’] = scaler.fit_transform(df[[‘nomCol’]])
df[['Cantidad', 'Precio']] = scaler.fit_transform(df[['Cantidad', 'Precio']]) &-and. |-or
df_est = df
num_cols = df_est.select_dtypes(include='number').columns
scaler = StandardScaler()
df_est[num_cols] = scaler.fit_transform(df_est[num_cols])
df_est.head()
Creación de un archivo de Excel con información de un DataFrame
arch= [Link]("NUEVO_PEDIDOS.xlsx")
df_pedidos.to_excel(arch)
[Link]()
.to_csv("[Link]") # Exporta el DataFrame a un archivo CSV
.to_excel("[Link]") # Exporta el DataFrame a un archivo Excel
.to_sql("nomArch") # Exporta el DataFrame a una base de datos SQL
.to_json("[Link]") # Exporta el DataFrame a un archivo JSON
Las correlaciones van de -1 a 1:
1 indica una correlación positiva perfecta y correlacion = df[[listaNomsCols]].corr()
-1 indica una correlación negativa perfecta.
correlacion = df[listaNomsCols].corr()
reg_may= df[(df['PRECIO_U']== df['PRECIO_U'].max()) & (df['CANT']== df['CANT'].max())]
df[['PRECIO_U', 'CANT', 'TOTAL']].agg(['sum', 'mean'])
df[["gender", "school_group", "minutes"]].describe()
[Link]().sum()
df=[Link]([Link]).first()
fut ["CONTINENTE"] = "Europa"
#Se aplican filtros para re-asignar valor a CONTINENTE
fut. loc[(fut["Pais"]=="Mexico") | (fut["Pais"]=="Argentina") | (fut ["Pais"]=="USA"), "CONTINENTE"] = "America"
fut. tail(10)
menor= (df['tip'] / df['total_bill'])*100 df2= (menor<18).mean()*100
#Datos faltantes mostrados #datos duplicados mostrados
df_na= df_planes.isna() mask_dup = [Link](keep=False)
na_por_fila = df_na.any(axis=1) # True para TODAS las filas que se repiten (incluye la primera)
df_planes[na_por_fila] df1[mask_dup]
#numero de columnas
len([Link])
index = ((df['Ventas Departamento de perfume'] > 20000) & (df['Ventas Departamento de dulce'] > 20000))
[Link]()
tiendas_ventas_prom = [Link][index2, ['Ventas Departamento de regalos']]
tiendas_ventas_prom
Pautas generales para remplazo o eliminación de valores faltantes
#Remplazar datos faltantes con mediana
*Si existe un número “considerable” de datos atípicos en la misma columna donde haya datos faltantes
*Si los datos faltantes son datos numéricos continuos y hay pocos datos faltantes
#Remplazar datos faltantes con valor previo ffill o posterior bfill
*Si los datos faltantes describen series temporales o datos que describen tendencias (p.e datos económicos
o temperaturas)
#Eliminar valores faltantes
*Cuando hay demasiados valores faltantes en la fila y el registro no aporta información significativa.
*Si la columna con datos faltantes no es relevante para el análisis.
*Cuando eliminar datos no introduce sesgo en el análisis
Análisis de datos categóricos
.mode() arroja el valor que aparece con mayor frecuencia
.value_counts(normalize = True) arroja frecuencia de cada ocurrencia
Creación de tablas de contingencia entre columnas con datos categóricos:
prom= [Link](df[‘nomCo1’], df[‘nomCol2’])
prom= [Link](titanic['sex'], titanic['survived'])
prom
pct_surv_women = [Link]['female', 1] / [Link]['female'].sum() * 100
pct_surv_men = [Link]['male', 1] / [Link]['male'].sum() * 100
print("Porcentaje de mujeres que sobrevivieron:", pct_surv_women,'%')
print("Porcentaje de hombres que sobrevivieron:", pct_surv_men,'%')
df["fecha_inscripcion"] = pd.to_datetime(df["fecha_inscripcion"], format="%m/%d/%y")
df['año']= df["fecha_inscripcion"].[Link]
df['dia']= df["fecha_inscripcion"].dt. day_name(locale="es_ES")
df
df['redaccion_letra'] = 'No aprobado'
[Link][df['redaccion'].between(6,8), 'redaccion_letra']= 'Aprobado'
[Link][df['redaccion'].between(9,10), 'redaccion_letra']= 'Execelente'
df[['redaccion', 'redaccion_letra']]
df=[Link]({"99": [Link], 99:[Link]})
freq: cuantas veces aparece top en la columna.
top: el valor que más aparece (moda) que "99" se usa para reemplazar datos
Precio_max = df_pedidos['PRECIO_U'].max()
df_maximos=df_pedidos[df_pedidos['PRECIO_U'] == Precio_max]
df_maximos['NOMBRE'].head()
df_filtro= (df_pedidos['CLASIFICACION'] == 'botana') & (df_pedidos['NOMBRE'] == 'alitas')
df_cant= df_filtro.sum()
Regresión lineal
x = df[['WinterRain', 'AGST', 'HarvestRain','Age']]
y= df['Price']
[Link](numeric_only=True)
x_train, x_test, y_train, y_test = train_test_split (x, y, test_size = 0.3, random_state = 42)
lr=LinearRegression()
r2 = r2_score(y_test, y_pred_test)
[Link](x_train, y_train)
r2
coeficiente = lr.coef_ R²: Porción de la variación explicada por el modelo. 1 es
coeficiente perfecto, 0 no ayuda, puede ser negativo. Más alto mejor.
intercepto = lr.intercept_ mae = mean_absolute_error(y_test, y_pred_test)
intercepto mae
y_pred_train= [Link](x_train) MAE: Promedio de errores absolutos. Menos sensible a
y_pred_test = [Link](x_test) outliers. Misma unidad que y. Más bajo mejor.
mse = mean_squared_error(y_test, y_pred_test)
mse
RMSE: Raíz del promedio de errores al
cuadrado. Penaliza errores grandes. rmse= [Link](mse)
Misma unidad que y. Más bajo mejor. rmse
MedHouseVal = −37.0233 + 4.48674910e-01⋅MedInc + 9.72425752e-03⋅HouseAge − 1.23323343e-01⋅AveRooms +
0.7831⋅AveBedrms − 0.0000020⋅Population − 0.0035⋅AveOccup − 0.4198⋅Latitude − 0.4337⋅Longitude
df_results=[Link](x_test, columns= [Link])
df_results['ValorReal']= y_test
df_results['Prediccion']= y_pred_test
Segunda opción:
nuevo = [Link]({'WinterRain':[600], 'AGST':[15], 'HarvestRain':[150], 'Age':[15]})
nuevo
pred_log = [Link](nuevo)
pred_log
Árbol de decisión
# convertir los valores categóricos a categóricos numéricos
encoder = OrdinalEncoder(categories=[
['rainy', 'overcast', 'sunny'], # Orden para 'outlook'
['cool', 'mild', 'hot'], # Orden para 'temp'
['normal', 'high'], # Orden para 'humidity'
[False, True], # Orden para 'windy'
['no', 'yes'] # Orden para 'play'
])
valores_codificados = encoder.fit_transform(df_tenis_original)
df_tenis = [Link](valores_codificados, columns=df_tenis_original.columns).astype(int)
df_tenis
y=df_tenis['play']
x=df_tenis[['outlook', 'temp', 'humidity', 'windy']]
[Link]()
[Link]()
[Link]()
[Link]()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y)
clf = [Link](criterion = “entropy”) #el criterio por default es gini
[Link](X_train, y_train)
profundidad = clf.get_depth()
tree.plot_tree(clf, feature_names = [Link]) hojas = clf.get_n_leaves()
y_pred = [Link](X_test) Usa el modelo entrenado para predecir las clases de los datos de prueba.
confusion_matrix(y_test, y_pred) Muestra una tabla de aciertos y errores (matriz de confusión).
Prueba= accuracy_score(y_test, y_pred) Calcula la exactitud del modelo en el conjunto de prueba.
Prueba
Calcula la exactitud del modelo en el
Entrenamiento= accuracy_score(y_train, [Link](X_train))
conjunto de entrenamiento (sirve para
Entrenamiento
comparar y detectar sobreajuste).
Cross validation:
cv_scores = cross_val_score (clf, X_train, y_train, cv=10)
cv_scores
cv_scores.std()
cv_scores.mean()
• cv_scores Parte los datos en 10 pedazos y prueba el modelo 10 veces. Guarda los resultados.
• cv_scores → Muestra las 10 puntuaciones (qué tan bien le fue en cada prueba).
• cv_scores.mean() → Promedio de esas 10 pruebas (qué tan bien le va en general al modelo).
• cv_scores.std() → Mide qué tanto cambian las 10 pruebas entre sí.
• Desviación estándar baja (< 0.30) → modelo estable.
• Desviación estándar alta (> 0.30) → modelo inestable, no generaliza bien.
Interpretación:
El modelo tiene un rendimiento promedio alto (95%) y una desviación estándar menor a 0.05, lo que indica que
el modelo es estable y generaliza bien
Cundo yo elijo la profundidad
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
clf = [Link](max_depth=1, random_state=42)
[Link](X_train, y_train)
profundidad = [1, 2, 3, 4, 5, 6]
acc_test = [Prueba1, Prueba2, Prueba3, Prueba4, Prueba5, Prueba6]
acc_train = [Entrena.1, Entrena.2, Entrena.3, Entrena.4, Entrena.5, Entrena.6]
[Link](profundidad, acc_test, label='Exactitud prueba')
[Link](profundidad, acc_train, label='Exactitud entrenamiento')
[Link]('Profundidad del árbol')
[Link]('Exactitud')
[Link]('Exactitud vs Profundidad')
plt.tight_layout()
[Link]()
[Link]()
[Link](df.select_dtypes(include='number'))
K-means [Link]('boxplot')
[Link]()
scaler = StandardScaler()
X = [Link](scaler.fit_transform(X), columns= [Link])
[Link]()
inertias = []
silhouette_scores = []
for i in range(1, 11):
kmeans = KMeans(n_clusters=i, n_init='auto')
[Link](X)
[Link](kmeans.inertia_)
if (i>=2):
silhouette = silhouette_score(X, kmeans.labels_)
silhouette_scores.append(silhouette)
[Link](range(1, 11), inertias, marker='o')
[Link]('Método del codo')
[Link]('Número de clusters')
[Link]('Inercias')
[Link]()
[Link](range(2, 11), silhouette_scores, marker='o')
[Link]('Coeficiente de Silhouette')
[Link]('Número de clusters')
[Link]('Coeficiente')
[Link]()
Al analizar las gráficas del método del codo y del índice de Silhouette, vi que la inercia disminuye mucho
entre k = 2 y k = 3, pero después ya casi no mejora. Además, el valor más alto del índice de Silhouette se
obtiene en k = 3 (aproximadamente 0.339). Por eso decidí quedarme con k = 3, porque es donde los grupos
quedan mejor separados y con una buena cohesión interna.
kmeans = KMeans(n_clusters =3, n_init='auto')
[Link](X)
grupo=kmeans.labels_
df_etiq=[Link](grupo)
df_etiq.value_counts()
X['Grupo']= grupo
df['Grupo']= grupo
[Link]()
[Link]( X['Score 2019'], X['Life Expectancy 2019'], c=kmeans.labels_)
[Link](kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 3],c='red', marker='x', s=200, label='Centroides')
plt. title('Dispersión entre rango de felicidad obtenido y Expectativa de vida')
[Link]('Rank 2019')
[Link]('Life Expectancy 2019')
[Link]()
silhouette = silhouette_score(X, kmeans.labels_)
[Link]('Grupo').mean() silhouette
kmeans.cluster_centers_
kmeans.inertia_
CORPUS
stop_words = [Link]("spanish")
tokenizer = [Link]()
stemmer = SnowballStemmer("spanish")
nlp = spacy. load("es_core_news_sm")
corpus = [ ]
#Funcion para normalizar
def normaliza (frase):
frase = [Link]()
frase = [Link](r"[^a-záéíóúüñ\s]", " ", frase, re.I | re.A)
tokens = [Link](frase)
filtered_tokens = [tok for tok in tokens if tok not in stop_words]
frase = " ".join(filtered_tokens)
return frase
normaliza_corpus = [Link](normaliza)
corpus_normalizado = normaliza_corpus(corpus)
corpus_normalizado
Conservar números:r"[^a-záéíóúüñ0-9\s]"
Aceptar también mayúsculas sin depender de .lower():r"[^A-Za-zÁÉÍÓÚÜÑáéíóúüñ\s]"
def lematiza (docto):
tokens = nlp(str (docto))
lematizadas = [token. lemma_ for token in tokens]
docto_lem = " ".join(lematizadas)
return docto_lem
lematizar = np. vectorize (lematiza)
corpus_lematizado = lematizar(corpus_normalizado)
corpus_lematizado
def enraizamiento(docto):
palabras_con_raiz = [ ]
palabras = [Link]()
for palabra in palabras:
palabras_con_raiz.append([Link](palabra))
docto_raiz = " ".join(palabras_con_raiz)
return docto_raiz
enraizar = np. vectorize (enraizamiento)
corpus_enraizado = enraizar(corpus_normalizado)
corpus_enraizado
palabras= [ ]
for documento in corpus_normalizado:
for palabra in [Link]():
[Link](palabra)
palabras
freq = [Link](palabras)
frecuencia_palabras = [Link](freq.most_common(10))
frecuencia_palabras.columns = ["palabra", "frecuencia"]
frecuencia_palabras
[Link](frecuencia_palabras["palabra"], frecuencia_palabras["frecuencia"])
[Link](rotation=90)
[Link]()
nube_palabras = WordCloud().generate(" ".join(palabras))
[Link](nube_palabras, interpolation="nearest")
[Link]("off")
[Link]()
POS tagging
texto = " ".join(corpus)
documento = nlp(texto)
for palabra in documento:
print([Link], palabra.pos_)
print("\nSustantivos:\n")
for palabra in documento:
if palabra.pos_ in ["NOUN", "PROPN"]:
print([Link], palabra.pos_)
print("\nAdjetivos:\n")
for palabra in documento:
if palabra.pos_ == "ADJ":
print([Link], palabra.pos_)
print("\nVerbos:\n")
for palabra in documento:
if palabra.pos_ == "VERB":
print([Link], palabra.pos_)
Sin acentos
_mapa = [Link]("áéíóúü", "aeiouu")
def quitar_acentos(s):
return [Link](_mapa)
def normaliza(frase):
frase = [Link]()
frase = quitar_acentos(frase) # ñ se queda como ñ
frase = [Link](r"[^a-zñ\s]", " ", frase, re.I | re.A)
tokens = [Link](frase)
filtered_tokens = [t for t in tokens if t not in stop_words_sin_acentos]
frase = " ".join(filtered_tokens)
return frase
stop_words_sin_acentos = set(quitar_acentos([Link]()) for w in stop_words)
normaliza_corpus = [Link](normaliza)
corpus_normalizado = normaliza_corpus(corpus)
corpus_normalizado
Extracción / Web Scraping
url = '[Link]
pag_html = [Link](url)
print(pag_html.text[:1000])
sopa = BeautifulSoup(pag_html.text, "html5lib")
print("Título de la página web:\n\n", [Link])
print(“Subtítulo de la página web:\n\n", [Link])
print("Cuerpo de la página web\n\n", [Link])
Lo mismo para h1
print("\nImpresión de todos los títulos H2:\n")
titulos_h2 = [ ]
# aquí vamos guardando los H2
for elemento in [Link]("h2"):
texto = elemento.get_text(strip=True)
print(texto)
titulos_h2.append(texto)
print("\nImpresión de todos los títulos H4 (data-cta):\n")
titulos_h4 = [ ]
# aquí vamos guardando los H4
for elemento in [Link]("h4"):
if elemento.has_attr("data-cta"):
texto = elemento["data-cta"]
print(texto)
titulos_h4.append(texto)
print("\nImpresión de todos los párrafos:\n")
parrafos = [ ]
# aquí vamos guardando los párrafos
for elemento in [Link]("p"):
texto = elemento.get_text(strip=True)
print(texto)
[Link](texto)
Extraer títulos de noticias
url = '[Link]
response = [Link](url)
if response.status_code == 200:
# Paso 4: Analizar el contenido HTML con BeautifulSoup
soup = BeautifulSoup([Link], '[Link]')
# Buscar los elementos que contienen los títulos de las
noticias- en Hacker News, los títulos están en la clase 'titleline'
titles = soup.find_all('span', class_='titleline')
# Mostrar los títulos en consola
print("Títulos de noticias en Hacker News:\n")
for i, title in enumerate(titles, start=1):
text = title.get_text() # obtenemos el texto
print(f"{i}. {text}")
else:
print("Error al conectar con el sitio web.")
Geopandas
#Leer un GeoJSON -> GeoDataFrame (32 estados)
mapa_mx_gj = gpd.read_file("[Link]")
mapa_mx_gj.columns
mapa_mx_gj.shape
mapa_mx_gj.plot(edgecolor="gray", color="coral")
mapa_mx_gj.plot(column="ENTIDAD", edgecolor="black", figsize=(15, 10))
[Link]()
#Filtrar un estado con .loc y graficar
slp = mapa_mx_gj.loc[mapa_mx_gj["ENTIDAD"] == "SAN LUIS POTOSI"]
[Link](edgecolor="black", color="blue")
[Link]()
# 0.6 Operaciones geométricas: CRS, conversión, áreas
Parámetros de .plot() en GeoDataFrame:
mapa_mx_gj.crs • edgecolor: color de bordes (líneas).
• color: color de relleno.
# Conversion • column: colorea según una columna
mapa_mx = mapa_mx_gj.to_crs(epsg=3857) (categorías con tonos limitados por default).
• figsize: tamaño de la figura (ancho, alto).
# Observamos nuevamente el crs del nuevo geo df
mapa_mx.crs
mapa_mx.area
mapa_mx["AREA"] = mapa_mx.area / 1_000_000
mapa_mx[["ENTIDAD", "AREA"]].head()
mapa_mx.plot(column="AREA", edgecolor="gray", cmap="Blues", legend=True)
[Link]()
# 0.7 Centroides
centroide = mapa_mx.centroid
centroide
mapa_mx["CENTROIDE"] = centroide
mapa_mx[["CENTROIDE"]].head()
# 0.7.2 Graficar dos capas: mapa + centroides
# --------------------------------------------
axis = mapa_mx.plot(column="ENTIDAD", edgecolor="gray", alpha=0.5)
mapa_mx["CENTROIDE"].plot(ax=axis, marker="o", color="black", markersize=3)
[Link]()
# 0.7.6 Distancia del Estadio Azteca a cada centroide (km)
from [Link] import Point
estadio_azteca = Point(-11042932.94161607, 2195615.334524989) (X,Y)
estadio_azteca = [Link](estadio_azteca, crs=mapa_mx.crs)
mapa_mx["distEstAzteca"]=[float(estadio_azteca.distance(centroid))/1000 for centroid in mapa_mx["CENTROIDE"]]
mapa_mx.head(15)
EJERCICIO 21 — MAPAS COROPLÉTICOS
"scheme" clasifica los valores en CLASES (rangos) y colorea por clase.
- scheme="Quantiles": mismos elementos por clase (ej. 5 clases -> ~20% estados c/u).
- scheme="EqualInterval": divide min->max en intervalos del mismo tamaño.
- scheme="NaturalBreaks": cortes "naturales" (agrupa valores parecidos y separa grupos).
- scheme="UserDefined": tú defines los cortes con bins=[...].
MERGE (PEGAR DATOS AL MAPA)
mapa_mx = [Link](mapa_mx_gj, ventas, left_on="ENTIDAD" right_on="Estado")
mapa_mx = mapa_mx.drop(columns=["Estado"])
CONVERTIR "Utilidad" A NÚMERO (SI TRAE "$")
mapa_mx["UtilidadNumerica"] = (mapa_mx["Utilidad"].[Link]("$", "").astype(float))
mapa_mx[["ENTIDAD", "Utilidad", "UtilidadNumerica"]].head()
COROPLETA: scheme="Quantiles"
mapa_mx.plot(column="UtilidadNumerica", cmap="RdYlGn", legend=True, edgecolor="black", scheme="Quantiles",
figsize=(10,6), legend_kwds={"loc": "upper right", "title": "Utilidad"})
[Link]("Utilidad por Estado (Quantiles)")
[Link](
COROPLETA: scheme="EqualInterval"
mapa_mx.plot(column="UtilidadNumerica", cmap="OrRd", legend=True, edgecolor="black", scheme="EqualInterval",
figsize=(10,6), legend_kwds={"title": "Utilidad"})
[Link]("Utilidad por Estado (EqualInterval)")
[Link]()
10) COROPLETA: scheme="UserDefined" (tú pones los bins)
mapa_mx.plot(column="UtilidadNumerica", cmap="YlGnBu", legend=True, edgecolor="black",
scheme="UserDefined", classification_kwds={"bins": [-500, 0, 50, 100, 200, 500]}, figsize=(10,6),
legend_kwds={"title": "Utilidad (bins)"})
[Link]("Utilidad por Estado (UserDefined)")
[Link]()
cmap= viridis, Blues, YlOrRd, RdYlGn, Greens
10) COROPLETA: scheme="UserDefined" (tú pones los bins)
# -------------------------------
mapa_mx.plot(
column="UtilidadNumerica",
cmap="YlGnBu",
legend=True,
edgecolor="black",
scheme="UserDefined",
classification_kwds={"bins": [-500, 0, 50, 100, 200, 500]},
figsize=(10,6),
legend_kwds={"title": "Utilidad (bins)"}
)
[Link]("Utilidad por Estado (UserDefined)")
[Link]()
cmap= viridis, Blues, YlOrRd, RdYlGn, Greens