Este tutorial adapta pedagógicamente el Día 79. Las secciones 📝 Contenido original del curso provienen de las lecciones 583 a 590; el cuaderno de inicio y el archivo
nobel_prize_data.csvestán en los recursos del curso (Nobel Prize Analysis Start.zip). En varias lecciones parte del código aparece solo en imágenes; aquí se reconstruye y se verifica. Los retos 🟢🟡🟠🔴, la sección una base de datos, varias historias, el proyecto extra sobre América Latina en el Nobel y la etapa 4 del Laboratorio de Datos Abiertos son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Nota sobre las verificaciones: el 27 de septiembre de 2026, con Python 3.14, pandas 3.0.6, plotly 7.1.0, seaborn 0.13.2, Matplotlib 3.11.2 y statsmodels 0.15.0, y con una copia pública de
nobel_prize_data.csv(publicada en GitHub por otro estudiante del mismo curso), se ejecutó todo el código. Los resultados coinciden con el curso: 962 filas y 16 columnas, de 1901 a 2020; 6,2 % de mujeres; 6 laureados repetidos; Economía desde 1969; Estados Unidos, Reino Unido y Alemania a la cabeza; John Goodenough, de 97 años, el mayor. Hay tres observaciones importantes: cada fila es un laureado, no un premio (hay 962 filas pero 602 premios distintos), así que los gráficos cuentan laureados; la línea central de un diagrama de caja es la mediana, no la media; ylowess=Truenecesita el paquetestatsmodels(sin él:RuntimeError: lowess=True requires statsmodels).
Tabla de contenidos
- Antes de empezar: el testamento de Alfred Nobel
- Explorar y limpiar el conjunto de datos
- Hacer preguntas: categorías, mujeres y repetidores
- Tendencias en el tiempo con Matplotlib
- Países: ranking, mapa coroplético y acumulado
- Instituciones y ciudades: gráfico sunburst
- La edad de los laureados
- 📖 Una base de datos, varias historias
- 🚀 Proyecto del día: la historia del Nobel en 8 gráficos
- 🌟 Proyecto extra: América Latina en el Nobel
- 🏗️ Laboratorio de Datos Abiertos — Etapa 4
- 🧩 Comprueba lo aprendido
- 🤖 Programar con apoyo de IA
- 🛠️ Correcciones técnicas al material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 79
0. Antes de empezar: el testamento de Alfred Nobel
(Fuente: 583-day-79-goals-what-you-will-make-by-the-end-of-the-day.md)
📝 Contenido original del curso
El 27 de noviembre de 1895, Alfred Nobel firmó su testamento en París. Al abrirse tras su muerte causó controversia: Nobel dejaba casi toda su fortuna para crear premios "a quienes, durante el año anterior, hayan conferido el mayor beneficio a la humanidad". Cada año se premia a científicos y escritores en química, literatura, física, fisiología o medicina, economía y paz.
Este proyecto integra muchas herramientas de los días anteriores y agrega otras nuevas:
- un mapa coroplético para mostrar datos sobre un mapa;
- barras de plotly con segmentos de los datos;
- gráficos sunburst;
.lmplot()de seaborn con líneas de ajuste por categoría (row,hue,lowess);- cómo la misma información cuenta historias distintas según cómo se mire (cajas contra series de tiempo);
- histogramas de seaborn para ver la distribución.
Preparación: descarga el ZIP, sube el cuaderno a Google Drive, ábrelo con Colab y agrega nobel_prize_data.csv.
Prerequisitos: plotly (Día 76), dos ejes y media móvil (Días 74 y 75),
mergeygroupby(Día 74),regplot(Día 78),np.arange(Día 77). En tu computador:pip install plotly seaborn statsmodels.
1. Explorar y limpiar el conjunto de datos
(Fuente: 584-update-packages-in-google-colab-y-explore-and-clean-the-dataset.md)
🎯 Objetivo de aprendizaje
Explicar por qué faltan datos (no solo cuántos) y convertir un texto como "1/3" en un número.
📝 Contenido original del curso
En Colab, actualizar plotly: el plotly preinstalado estaba desactualizado y causaba problemas con el sunburst. Se descomenta la celda con pip install, se ejecuta y se vuelve a comentar.
Reto 1: ¿forma?, ¿columnas y qué contienen?, ¿primer y último año? Reto 2: ¿duplicados?, ¿NaN?, ¿en qué columnas y cuántos?, ¿por qué? Reto 3: convierte birth_date a fecha y agrega share_pct con la parte del premio como decimal.
Solución: 962 filas y 16 columnas, de 1901 a 2020. Columnas destacadas: birth_date (texto), motivation, prize_share (fracción), laureate_type (individuo u organización), birth_country (incluye países que ya no existen), birth_country_current (nombre actual), ISO (código de 3 letras), organization_name, organization_city.
print(f'Any duplicates? {df_data.duplicated().values.any()}') # False
print(f'Any NaN values among the data? {df_data.isna().values.any()}') # True
df_data.isna().sum()
col_subset = ['year', 'category', 'laureate_type',
'birth_date', 'full_name', 'organization_name']
df_data.loc[df_data.birth_date.isna()][col_subset]Sin fecha de nacimiento aparecen organizaciones (la ONU, la Cruz Roja): tiene sentido. Y como su nombre está en full_name, organization_name queda vacío. Además, muchos premios de Literatura y Paz fueron para personas sin afiliación a una universidad o instituto.
df_data.birth_date = pd.to_datetime(df_data.birth_date)
separated_values = df_data.prize_share.str.split('/', expand=True)
numerator = pd.to_numeric(separated_values[0])
denomenator = pd.to_numeric(separated_values[1])
df_data['share_pct'] = numerator / denomenator📖 Explicación conceptual (verificada)
| Columna | NaN | ¿Por qué? |
|---|---|---|
birth_date, birth_country, birth_country_current, sex, ISO |
28 | Son organizaciones: no nacen ni tienen sexo |
birth_city |
31 | Las 28 organizaciones y 3 personas sin ciudad registrada |
organization_name, organization_city |
255 | Organizaciones y personas sin afiliación (sobre todo Literatura y Paz) |
motivation |
88 | Premios sin motivación registrada en la fuente |
Faltante no es lo mismo que error. Un NaN puede significar "no aplica" (una organización no tiene fecha de nacimiento) o "no se sabe". No se deben eliminar esas filas a ciegas: borrar las 255 filas sin organización quitaría a casi todos los ganadores de Literatura y Paz.
share_pct: los valores posibles son 1, 1/2, 1/3 y 1/4 (verificado: 352, 321, 219 y 70 laureados).
🛠️ Nota técnica (verificado): un error en los datos.
laureate_typemarca 32 filas comoOrganization, pero solo 28 no tienen fecha de nacimiento. Las otras 4 son personas mal clasificadas: Le Duc Tho (1973), la Madre Teresa (1979), el 14.º Dalái Lama (1989) y Aung San Suu Kyi (1991), todas del premio de Paz. Así se detecta:df_data[(df_data.laureate_type == 'Organization') & df_data.sex.notna()]. Lección: contrasta columnas entre sí; una sola columna puede tener errores que otra delata.
🛠️ Nota técnica: hoy Colab trae versiones recientes de plotly; en general no hace falta actualizarlo. Si alguna vez lo necesitas,
%pip install --upgrade plotlyy luego reinicia la sesión (Entorno de ejecución → Reiniciar), porque un paquete ya importado no se recarga solo.
🛠️ Nota técnica: el curso escribe
denomenator; la palabra correcta en inglés es denominator. Funciona igual (es solo un nombre de variable), pero conviene escribir bien los nombres.
⚠️ Errores frecuentes
dropna()sin pensar: pasarías de 962 a menos de 700 filas y perderías categorías enteras.pd.to_numeric('1/3'):ValueError. Hay que separar numerador y denominador primero.- Tratar
sexcomo si incluyera a las organizaciones: los porcentajes cambian según el denominador (sección 2).
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: ¿cuántas organizaciones han ganado realmente? ¿En qué categoría? Corrige
laureate_typede las 4 personas mal clasificadas y comprueba que ahora coincide con las 28 filas sin fecha de nacimiento. - 🟡 Reto 2: calcula
share_pcten una sola línea con.map({'1/1': 1, '1/2': 0.5, ...}). ¿Qué ventaja y qué riesgo tiene frente asplit?
2. Hacer preguntas: categorías, mujeres y repetidores
(Fuente: 585-plotly-bar-y-donut-charts-analyse-prize-categories-y-women-winning-prizes.md)
🎯 Objetivo de aprendizaje
Formular preguntas propias sobre unos datos y responderlas con conteos, filtros y gráficos segmentados.
📝 Contenido original del curso
Reto 1: formula 3 preguntas. Buena parte de la ciencia de datos es hacerse preguntas; es lo más difícil de enseñar porque requiere creatividad. A veces los datos no pueden responderlas, "y está bien: es parte del descubrimiento". Ejemplos: "¿Qué porcentaje de laureados fueron mujeres?", "¿Cuántos premios hubo en cada categoría?".
Reto 2: dona de hombres contra mujeres. Solo un 6,2 % fueron mujeres.
biology = df_data.sex.value_counts()
fig = px.pie(labels=biology.index, values=biology.values,
title="Percentage of Male vs. Female Winners",
names=biology.index, hole=0.4)
fig.update_traces(textposition='inside', textfont_size=15, textinfo='percent')
fig.show()Reto 3: las 3 primeras mujeres laureadas (una es, claro, Marie Curie):
df_data[df_data.sex == 'Female'].sort_values('year', ascending=True)[:3]Reto 4: ¿alguien ganó más de una vez? Buscando duplicados en full_name:
is_winner = df_data.duplicated(subset=['full_name'], keep=False)
multiple_winners = df_data[is_winner]
print(f'There are {multiple_winners.full_name.nunique()}'
' winners who were awarded the prize more than once.') # 6Solo 4 son personas. Marie Curie ganó en Física y en Química; Linus Pauling, en Química y luego en Paz por promover el desarme nuclear; la Cruz Roja Internacional ganó el de Paz 3 veces, las dos primeras durante las guerras mundiales.
Reto 5: ¿cuántas categorías? (6). Barras con la escala Aggrnyl, sin eje de color:
prizes_per_category = df_data.category.value_counts()
v_bar = px.bar(x=prizes_per_category.index, y=prizes_per_category.values,
color=prizes_per_category.values, color_continuous_scale='Aggrnyl',
title='Number of Prizes Awarded per Category')
v_bar.update_layout(xaxis_title='Nobel Prize Category', coloraxis_showscale=False,
yaxis_title='Number of Prizes')
v_bar.show()Reto 6: ¿por qué tan pocos de Economía? Es mucho más nuevo: desde 1969 (Física, desde 1901).
Reto 7: hombres y mujeres por categoría:
cat_men_women = df_data.groupby(['category', 'sex'],
as_index=False).agg({'prize': pd.Series.count})
cat_men_women.sort_values('prize', ascending=False, inplace=True)
v_bar_split = px.bar(x=cat_men_women.category, y=cat_men_women.prize,
color=cat_men_women.sex,
title='Number of Prizes Awarded per Category split by Men and Women')
v_bar_split.update_layout(xaxis_title='Nobel Prize Category', yaxis_title='Number of Prizes')
v_bar_split.show()El desequilibrio es muy grande en Física, Economía y Química; las mujeres están algo más representadas en Medicina, Literatura y Paz. Dividir las barras así da una imagen mucho más detallada.
📖 Resultados verificados
| Categoría | Mujeres | Hombres |
|---|---|---|
| Chemistry | 7 | 179 |
| Economics | 2 | 84 |
| Literature | 16 | 101 |
| Medicine | 12 | 210 |
| Peace | 17 | 90 |
| Physics | 4 | 212 |
Primeras mujeres: Marie Curie (Física, 1903), Bertha von Suttner (Paz, 1905) y Selma Lagerlöf (Literatura, 1909). Repetidores: Marie Curie, Linus Pauling, John Bardeen, Frederick Sanger, el Comité Internacional de la Cruz Roja (3 veces) y el ACNUR (Alto Comisionado de las Naciones Unidas para los Refugiados, 2 veces).
🛠️ Nota técnica (verificado): ¿premios o laureados? Cada fila es un laureado. Un premio compartido por tres personas aparece 3 veces. Hay 962 filas pero solo 602 premios distintos (combinaciones de año y categoría). Por eso los gráficos del curso titulados "Number of Prizes" cuentan en realidad laureados. Para contar premios:
df_data.groupby('category').prize.nunique()(Física: 114 premios, 216 laureados).
🛠️ Nota técnica (verificado): el denominador. El 6,2 % es 58 mujeres de 934 personas (se excluyen las 28 organizaciones, que no tienen sexo). Sobre las 962 filas sería 6,0 %. Ninguna cifra es "la correcta": hay que decir cuál es el denominador.
⚠️ Errores frecuentes
- Llamar a una variable
biologypara contar sexos: funciona, pero un nombre comoconteo_sexocomunica mejor. - Buscar repetidores con
duplicated()sinkeep=False: solo verías la segunda aparición de cada uno. - Comparar Economía con Física por el total sin notar que Economía empezó 68 años después.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: calcula el porcentaje de mujeres por década. ¿Está aumentando?
- 🟡 Reto 2: grafica el número de premios (no laureados) por categoría y compáralo con el gráfico del curso.
- 🔴 Reto 3 — Pensamiento computacional: para comparar Economía con las demás categorías de forma justa, calcula laureados por año desde que existe cada categoría. Diseña el cálculo y explica tu decisión.
3. Tendencias en el tiempo con Matplotlib
(Fuente: 586-using-matplotlib-to-visualise-trends-over-time.md)
🎯 Objetivo de aprendizaje
Combinar dispersión, media móvil y un segundo eje invertido para mostrar la relación entre dos tendencias.
📝 Contenido original del curso
Reto 1: ¿se otorgan más premios ahora? Cuenta los premios por año, calcula la media móvil de 5 años, superponla a un gráfico de dispersión, pon una marca cada 5 años de 1900 a 2020 (con NumPy) y usa los colores dodgerblue y crimson. ¿Influyeron las guerras mundiales?
prize_per_year = df_data.groupby(by='year').count().prize
moving_average = prize_per_year.rolling(window=5).mean()
plt.figure(figsize=(16, 8), dpi=200)
plt.title('Number of Nobel Prizes Awarded per Year', fontsize=18)
plt.yticks(fontsize=14)
plt.xticks(ticks=np.arange(1900, 2021, step=5), fontsize=14, rotation=45)
ax = plt.gca()
ax.set_xlim(1900, 2020)
ax.scatter(x=prize_per_year.index, y=prize_per_year.values,
c='dodgerblue', alpha=0.7, s=100)
ax.plot(prize_per_year.index, moving_average.values, c='crimson', linewidth=3)
plt.show()Reto 2: ¿se comparten más los premios? Promedio anual de share_pct y su media móvil de 5 años, en un segundo eje, invertido:
yearly_avg_share = df_data.groupby(by='year').agg({'share_pct': pd.Series.mean})
share_moving_average = yearly_avg_share.rolling(window=5).mean()
ax1 = plt.gca()
ax2 = ax1.twinx() # segundo eje y
ax2.invert_yaxis() # se puede invertir
# ... scatter y plot en ax1 como antes ...
ax2.plot(prize_per_year.index, share_moving_average.values, c='grey', linewidth=3)Hay una clara tendencia al alza en el número de premios, porque se comparten cada vez más. Desde 1969 hay más por la llegada de Economía. Durante las guerras mundiales se otorgaron muy pocos: en lugar de ceros, se ven puntos azules que faltan.
📖 Explicación conceptual (verificada)
- Años faltantes (verificado): 1940, 1941 y 1942 no tienen ninguna fila; durante la Primera Guerra Mundial hubo pocos laureados (1914: 3; 1916: 1; 1918: 2).
groupbysolo crea filas para los años que existen en los datos: un año sin premios no aparece como 0, sino que no aparece. - La media móvil de 5 años llega a 12,4 laureados por año en 2020, frente a 6 en 1901. La parte promedio del premio baja de 0,82 (1905) a 0,49 (2020).
- ¿Por qué invertir el segundo eje? Porque las dos tendencias van en direcciones opuestas: más laureados ↔ partes más pequeñas. Al invertirlo, ambas líneas suben juntas y la relación "salta a la vista". Es un recurso legítimo solo si se indica claramente (etiqueta del eje): si no, el lector creería que la parte del premio aumenta.
🛠️ Nota técnica: el reto escribe
dogerblue; el nombre del color esdodgerblue(la solución lo usa bien). Con el nombre mal escrito, Matplotlib lanzaValueErrorindicando que no es un color válido. Además, los gráficos con dos ejes conservan el título "Number of Nobel Prizes Awarded per Year": conviene cambiarlo y etiquetar ambos ejes.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: agrega etiquetas a los dos ejes, una leyenda y una anotación en 1969 ("Primer premio de Economía").
- 🟡 Reto 2: reindexa la serie con todos los años (
prize_per_year.reindex(range(1901, 2021), fill_value=0)) y compara el gráfico. ¿Qué versión es más honesta para mostrar las guerras?
4. Países: ranking, mapa coroplético y acumulado
(Fuente: 587-a-choropleth-map-and-the-countries-with-the-most-prizes.md)
🎯 Objetivo de aprendizaje
Elegir la columna adecuada para un análisis geográfico, crear un mapa coroplético y un gráfico de líneas acumulado.
📝 Contenido original del curso
Reto 1: top20_countries con el total de premios. ¿birth_country, birth_country_current u organization_country? ¿Qué problemas tiene cada una?
birth_country incluye países que ya no existen (la Unión Soviética, Checoslovaquia): es mejor birth_country_current, el país que hoy controla la ciudad de nacimiento. Pero eso no es la nacionalidad: hay quienes nacieron en el extranjero, emigraron o cambiaron de ciudadanía. Hay que ser claros con los supuestos.
top_countries = df_data.groupby(['birth_country_current'],
as_index=False).agg({'prize': pd.Series.count})
top_countries.sort_values(by='prize', inplace=True)
top20_countries = top_countries[-20:]
h_bar = px.bar(x=top20_countries.prize, y=top20_countries.birth_country_current,
orientation='h', color=top20_countries.prize,
color_continuous_scale='Viridis', title='Top 20 Countries by Number of Prizes')
h_bar.update_layout(xaxis_title='Number of Prizes', yaxis_title='Country',
coloraxis_showscale=False)
h_bar.show()Reto 2: un mapa coroplético (se abre en otra pestaña) con los códigos ISO de 3 letras (escala matter):
df_countries = df_data.groupby(['birth_country_current', 'ISO'],
as_index=False).agg({'prize': pd.Series.count})
world_map = px.choropleth(df_countries, locations='ISO', color='prize',
hover_name='birth_country_current',
color_continuous_scale=px.colors.sequential.matter)
world_map.update_layout(coloraxis_showscale=True)
world_map.show()Reto 3: divide las barras por categoría. Primero se cuenta por país y categoría; luego se une con top20_countries para tener el total y controlar el orden:
cat_country = df_data.groupby(['birth_country_current', 'category'],
as_index=False).agg({'prize': pd.Series.count})
merged_df = pd.merge(cat_country, top20_countries, on='birth_country_current')
merged_df.columns = ['birth_country_current', 'category', 'cat_prize', 'total_prize']
merged_df.sort_values(by='total_prize', inplace=True)
cat_cntry_bar = px.bar(x=merged_df.cat_prize, y=merged_df.birth_country_current,
color=merged_df.category, orientation='h',
title='Top 20 Countries by Number of Prizes and Category')
cat_cntry_bar.show()Estados Unidos tiene una proporción increíble de los premios de Economía; Japón y Alemania, muy pocos o ninguno. Estados Unidos tiene más premios solo en Física o solo en Medicina que Francia en total. Alemania ganó más en Física que el Reino Unido, y Francia más en Paz y Literatura que Alemania.
Reto 4: premios acumulados por país en el tiempo:
prize_by_year = df_data.groupby(by=['birth_country_current', 'year'], as_index=False).count()
prize_by_year = prize_by_year.sort_values('year')[['year', 'birth_country_current', 'prize']]
cumulative_prizes = prize_by_year.groupby(by=['birth_country_current',
'year']).sum().groupby(level=[0]).cumsum()
cumulative_prizes.reset_index(inplace=True)
l_chart = px.line(cumulative_prizes, x='year', y='prize',
color='birth_country_current', hover_name='birth_country_current')
l_chart.show()Estados Unidos despegó tras la Segunda Guerra Mundial, que devastó Europa; antes, el Nobel era "un asunto europeo". En los últimos 40 años hay muchos más países representados. El Reino Unido y Alemania intercambiaron posiciones en los años 70 y 90, y Suecia se mantuvo quinta durante décadas: ¿un poco de "sesgo local"?
📖 Resultados verificados
País (birth_country_current) |
Laureados | Química | Economía | Literatura | Medicina | Paz | Física |
|---|---|---|---|---|---|---|---|
| Estados Unidos | 281 | 55 | 49 | 10 | 78 | 19 | 70 |
| Reino Unido | 105 | 27 | 8 | 7 | 28 | 11 | 24 |
| Alemania | 84 | 26 | 1 | 8 | 18 | 5 | 26 |
| Francia | 57 | 10 | 4 | 11 | 12 | 10 | 10 |
| Japón | 27 | 7 | 0 | 3 | 5 | 1 | 11 |
Respuestas a las preguntas del reto 3: Alemania y Japón son más débiles que Estados Unidos en Economía; Alemania supera al Reino Unido en Física (26 contra 24); Francia supera a Alemania en Paz, Literatura y también en Economía (4 contra 1); Australia tiene la mayoría en Medicina (7 de 10); la mitad de los premios de los Países Bajos es de Física (9 de 18); Estados Unidos no supera en Economía a toda Francia (49 contra 57), pero sí en Física (70) y en Medicina (78).
¿Cuándo tomó la delantera Estados Unidos? Según el acumulado verificado, el país con más laureados fue Francia o Alemania hasta 1951, año en que Estados Unidos pasó al primer lugar y ya no lo dejó.
Cómo funciona el acumulado: groupby(level=[0]).cumsum() suma, dentro de cada país, los valores año tras año. Como solo hay filas en los años en que un país ganó, la línea salta de un año con premio al siguiente.
⚠️ Errores frecuentes
- Mapa vacío o con países grises: el coroplético necesita códigos ISO alfa-3 correctos (
COL,USA). Un nombre de país enlocationsno funciona si no indicaslocationmode='country names'. mergeque pierde países: conhow='inner'(por defecto), un país que no está en el top 20 desaparece; aquí es lo que se busca.- Cambiar
columnssin revisar el orden:merged_df.columns = [...]renombra por posición; si el orden cambia, los nombres quedan cruzados. Es más segurorename(columns={'prize_x': 'cat_prize', 'prize_y': 'total_prize'}).
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: repite el ranking con
organization_country(dónde se hizo la investigación). ¿Qué países suben? ¿Qué te dice eso sobre la "fuga de cerebros"? - 🟡 Reto 2: haz el mapa por millón de habitantes con un archivo de población. ¿Qué país lidera ahora?
- 🟠 Reto 3: anima el mapa con
animation_frame='decade'usando los datos acumulados por década.
5. Instituciones y ciudades: gráfico sunburst
(Fuente: 588-create-sunburst-charts-for-a-detailed-regional-breakdown-of-research-locations.md)
📝 Contenido original del curso
Reto 1: las 20 instituciones con más laureados. ¿Cuántos tienen la Universidad de Chicago y Harvard? Reto 2: las 20 ciudades de investigación. ¿Cuál es el mayor centro de descubrimientos? ¿Y en Europa? Reto 3: las 20 ciudades de nacimiento (escala Plasma). ¿Qué porcentaje de los premios de Estados Unidos corresponde a nacidos en Nueva York? ¿Cuántos nacieron en Londres, París y Viena? ¿Cuántas de las 5 primeras están en Estados Unidos? Reto 4: un sunburst país → ciudad → organización. ¿Qué notas en Alemania y Francia?
top20_orgs = df_data.organization_name.value_counts()[:20]
top20_orgs.sort_values(ascending=True, inplace=True)
org_bar = px.bar(x=top20_orgs.values, y=top20_orgs.index, orientation='h',
color=top20_orgs.values, color_continuous_scale=px.colors.sequential.haline,
title='Top 20 Research Institutions by Number of Prizes')
org_bar.update_layout(xaxis_title='Number of Prizes', yaxis_title='Institution',
coloraxis_showscale=False)
org_bar.show()
country_city_org = df_data.groupby(by=['organization_country', 'organization_city',
'organization_name'],
as_index=False).agg({'prize': pd.Series.count})
burst = px.sunburst(country_city_org,
path=['organization_country', 'organization_city', 'organization_name'],
values='prize', title='Where do Discoveries Take Place?')
burst.show()Cambridge (Massachusetts) y Nueva York lideran la investigación. Una ciudad muy poblada tiene más probabilidad de ser cuna de un laureado (Nueva York, París, Londres), aunque Viena y Budapest, menos pobladas, produjeron muchos. Las ciudades donde se investiga (Cambridge, Stanford, Berkeley) no son las de nacimiento. El sunburst muestra la concentración: en Francia casi todo está en París; en Alemania los descubrimientos están mucho más repartidos; el Reino Unido está dominado por Cambridge y Londres.
📖 Resultados verificados
- Instituciones: University of California (40), Harvard (29), Stanford (23), MIT (21), University of Chicago (20).
- Ciudades de investigación: Cambridge, MA (50), New York, NY (45), Cambridge del Reino Unido (31), Londres (27), París (25). En Europa gana Cambridge.
- Ciudades de nacimiento: Nueva York (53), París (26), Londres (19), Viena (14), Chicago (12). Entre las 5 primeras, 2 están en Estados Unidos. Nacidos en Nueva York: 18,9 % de los 281 laureados nacidos en Estados Unidos.
- Francia: 25 de 38 laureados afiliados a instituciones francesas trabajaban en París; Alemania: 23 ciudades distintas.
🛠️ Nota técnica: la solución del sunburst llama a
update_layout(xaxis_title=..., yaxis_title=..., coloraxis_showscale=False), que no tiene efecto: un sunburst no tiene ejes. Sobra, aunque no produce error. Y ojo: "Brooklyn, NY" aparece aparte de "New York, NY"; si los sumas, Nueva York crece aún más. Decidir cómo agrupar lugares es parte del análisis.
🔎 ¿Cómo se lee un sunburst?
Es un gráfico circular por niveles: el anillo interior son los países; el siguiente, sus ciudades; el exterior, las organizaciones. El ángulo de cada porción es proporcional a values. Al hacer clic en un país, el gráfico "entra" en él. Es ideal para jerarquías; con más de 3 niveles se vuelve ilegible.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: crea un sunburst categoría → sexo → país de nacimiento.
- 🟡 Reto 2: unifica "Brooklyn, NY" y "New York, NY" y recalcula el ranking.
6. La edad de los laureados
(Fuente: 589-unearthing-patterns-in-the-laureate-age-at-the-time-of-the-award.md y 590-learning-points-y-summary.md)
🎯 Objetivo de aprendizaje
Describir una distribución con un histograma y estadísticas, y comparar la visión "de conjunto" (cajas) con la visión "en el tiempo" (lmplot con lowess).
📝 Contenido original del curso
Reto 1: la edad en el año del premio, en winning_age:
birth_years = df_data.birth_date.dt.year
df_data['winning_age'] = df_data.year - birth_yearsReto 2: el mayor y el menor laureado:
display(df_data.nlargest(n=1, columns='winning_age'))
display(df_data.nsmallest(n=1, columns='winning_age'))John Goodenough tenía 97 años. Nació de padres estadounidenses en Alemania: nuestro análisis por país cuenta un premio "alemán" extra, aunque es estadounidense. "Nunca es tarde para ganar un Nobel".
Reto 3: estadísticas descriptivas e histograma (prueba 10, 20, 30 y 50 bins):
plt.figure(figsize=(8, 4), dpi=200)
sns.histplot(data=df_data, x=df_data.winning_age, bins=30)
plt.xlabel('Age')
plt.title('Distribution of Age on Receipt of Prize')
plt.show()Reto 4: ¿los laureados son cada vez mayores? regplot con lowess=True:
plt.figure(figsize=(8, 4), dpi=200)
with sns.axes_style("whitegrid"):
sns.regplot(data=df_data, x='year', y='winning_age', lowess=True,
scatter_kws={'alpha': 0.4}, line_kws={'color': 'black'})
plt.show()lowess traza una regresión local: como una media móvil, da una forma no lineal. De 1900 a 1950 los laureados tenían unos 55 años; hoy, cerca de 70. En los últimos 10 años la dispersión aumentó: más laureados muy jóvenes y muy viejos.
Reto 5: edades por categoría con sns.boxplot (muestra "la media, los cuartiles, el máximo y el mínimo"). ¿De verdad los ganadores de Paz son mayores que los de Física?
Reto 6: lmplot con una fila por categoría (row) y luego todas juntas (hue):
with sns.axes_style('whitegrid'):
sns.lmplot(data=df_data, x='year', y='winning_age', row='category',
lowess=True, aspect=2,
scatter_kws={'alpha': 0.6}, line_kws={'color': 'black'})
plt.show()
with sns.axes_style("whitegrid"):
sns.lmplot(data=df_data, x='year', y='winning_age', hue='category',
lowess=True, aspect=2,
scatter_kws={'alpha': 0.5}, line_kws={'linewidth': 5})
plt.show()Física, Química y Medicina envejecen con el tiempo; el efecto más fuerte está en Física (de menos de 50 a más de 70). Economía es más estable. Paz muestra la tendencia opuesta: sus ganadores son más jóvenes. Las cajas del conjunto y las líneas en el tiempo cuentan historias muy distintas.
Resumen del día: repaso de NaN, conversiones, dona y barras de plotly, media móvil, value_counts, groupby, merge, sort_values y agg; nuevo: mapa coroplético, barras segmentadas, sunburst, lmplot con row, hue y lowess, histogramas y la lección de que los mismos datos pueden mostrar historias distintas.
📖 Resultados verificados
Estadística de winning_age |
Valor |
|---|---|
| Laureados con edad (personas) | 934 |
| Promedio | 59,9 años |
| Mediana | 60 |
| 75 % tiene menos de… | 69 años |
| Mínimo / máximo | 17 (Malala Yousafzai, Paz, 2014) / 97 (John Goodenough, Química, 2019) |
| Categoría | Edad mediana | Tendencia lowess (primer dato → último) |
|---|---|---|
| Physics | 55 | 46 → 73 |
| Chemistry | 58 | 48 → 71 |
| Medicine | 57 | 54 → 69 |
| Literature | 67 | 61 → 70 |
| Economics | 67 | 68 → 69 (estable) |
| Peace | 62 | 66 → 57 (baja) |
🛠️ Nota técnica (verificado):
lowess=Truenecesita el paquete statsmodels. En Colab ya está; en tu computador, sin él:RuntimeError: lowess=True requires statsmodels, an optional dependency, to be installed.Solución:pip install statsmodels.
🛠️ Nota técnica: la línea central de un diagrama de caja es la mediana, no la media (Día 76, sección 8). En
sns.boxplotpuedes mostrar también la media conshowmeans=True. Con Matplotlib 3.11, seaborn 0.13.2 muestra una advertencia (MatplotlibDeprecationWarning: vert: bool was deprecated): viene de seaborn, no de tu código, y el gráfico funciona.
🛠️ Nota técnica (verificado): año del premio − año de nacimiento no es la edad exacta: quien cumple años después de la ceremonia (10 de diciembre) queda con 1 año de más. Pasa con 55 de los 934 laureados. Para un análisis general la aproximación es razonable; si necesitaras la edad exacta, restarías fechas completas.
⚠️ Errores frecuentes
- Histograma con pocos o demasiados
bins: con 5 no ves la forma; con 200 ves ruido. Prueba varios y elige el que muestre la forma sin exagerar. lmplotdentro deplt.figure(...):lmplotcrea su propia figura (es una FacetGrid); el tamaño se controla conheightyaspect.- Calcular la edad sin convertir la fecha:
df_data.birth_date.dt.yearfalla sibirth_datesigue siendo texto (AttributeError: Can only use .dt accessor with datetimelike values).
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: ¿quiénes ganaron antes de los 30 años? ¿En qué categorías?
- 🟡 Reto 2: compara la edad mediana de hombres y mujeres por categoría.
- 🟠 Reto 3: agrega la media al diagrama de caja con
showmeans=True. ¿En qué categoría se separan más media y mediana? ¿Por qué?
7. 📖 Una base de datos, varias historias
(Sección creada para esta adaptación.)
El curso muestra que la caja dice "los de Paz son mayores" y el lmplot dice "los de Paz son cada vez más jóvenes". Las dos cosas son ciertas: la caja resume 120 años a la vez; la línea muestra el cambio. Antes de concluir, pregúntate siempre:
| Pregunta | En el Nobel |
|---|---|
| ¿Qué representa cada fila? | Un laureado, no un premio |
| ¿Qué falta y por qué? | Organizaciones sin edad; años de guerra sin premios |
| ¿Qué columna mide lo que quiero? | País de nacimiento ≠ nacionalidad ≠ país donde investigó |
| ¿Estoy resumiendo o viendo el cambio? | Cajas contra lmplot |
| ¿Quién eligió los datos? | Un comité sueco y noruego: los premios reflejan sus criterios y los de su época |
Representación: que solo el 6,2 % de los laureados sean mujeres o que haya muy pocos laureados de África y América Latina no mide el talento de esas poblaciones: refleja quién tuvo acceso a la educación, a los laboratorios y a las redes científicas, y quién fue nominado. Los datos describen el pasado; no dicen "quién puede" ganar.
8. 🚀 Proyecto del día: la historia del Nobel en 8 gráficos
(Integra las lecciones 584 a 590.)
Problema
La biblioteca del colegio prepara una exposición sobre ciencia y quiere una infografía interactiva sobre el Premio Nobel.
Contexto
Una exposición la verán estudiantes de todos los grados: los gráficos deben ser claros y las conclusiones, cuidadosas.
Objetivo
Un cuaderno con el análisis completo del curso y una selección de 8 gráficos guardados en HTML con títulos en español.
Requisitos funcionales
- Limpieza explicada (tabla de NaN y sus causas),
birth_dateconvertida,share_pctywinning_age. - Dona por sexo y barras por categoría segmentadas por sexo.
- Laureados por año con media móvil y parte promedio del premio en un segundo eje.
- Top 20 de países, mapa coroplético y acumulado por país.
- Sunburst de lugares de investigación.
- Histograma de edades,
lmplotpor categoría y cajas por categoría. - Una conclusión por gráfico, indicando si cuenta laureados o premios.
Restricciones técnicas
- Cada gráfico guardado con
write_html(plotly) osavefig(Matplotlib y seaborn). - Ninguna conclusión sobre "talento" o "capacidad" de un grupo (sección 7).
Planificación
- Comprender los datos. 2. Entradas: el CSV. 3. Procesos: limpiar → preguntar → agrupar → graficar → interpretar. 4. Salidas: 8 gráficos y textos. 5. Dividir por lección. 6. Elegir los 8 gráficos más claros. 7. Implementar. 8. Probar. 9. Corregir. 10. Montar la exposición.
Construcción paso a paso
- Versión 1: exploración, NaN y conversiones.
- Versión 2: categorías y sexo.
- Versión 3: tendencias en el tiempo.
- Versión 4: países y mapa.
- Versión 5: instituciones y sunburst.
- Versión final: edades y selección de los 8 gráficos.
Pruebas
| Comprobación | Valor esperado (verificado) |
|---|---|
| Forma y años | (962, 16); 1901–2020 |
| Porcentaje de mujeres (sobre personas) | 6,2 % |
| Repetidores | 6 |
| Años sin laureados | 1940, 1941, 1942 |
| Premios distintos | 602 |
| País con más laureados | Estados Unidos (281) |
| Edad mínima / máxima | 17 / 97 |
🧪 Prueba y depuración
df_data['share_pct'] = pd.to_numeric(df_data.prize_share)
df_data['winning_age'] = df_data.year - df_data.birth_date.dt.year
top20 = df_data.birth_country.value_counts()[:20]
world_map = px.choropleth(df_data, locations='birth_country_current', color='prize')
sns.regplot(data=df_data, x='year', y='winning_age', lowess=True)Encuentra cinco problemas: to_numeric no entiende "1/2" (ValueError); birth_date no se ha convertido a fecha (AttributeError con .dt); birth_country incluye países que ya no existen; el mapa usa nombres en locations (sin locationmode) y colorea por la columna de texto prize en vez de un conteo; y lowess=True falla si no está instalado statsmodels.
⭐ Extensión del proyecto
- Reto 1: una línea de tiempo interactiva con
px.scatter(año contra categoría) donde cada punto sea un laureado y el color sea el sexo. - Reto 2: analiza las palabras más frecuentes en
motivationpor categoría (pista:str.split+explode+value_counts).
9. 🌟 Proyecto extra: América Latina en el Nobel
(Proyecto creado para esta adaptación; no existe en el curso original.)
Situación
En los datos hay 19 laureados nacidos en países de América Latina y el Caribe (verificado), entre ellos dos colombianos: Gabriel García Márquez (Literatura, 1982) y Juan Manuel Santos (Paz, 2016).
Requisitos
- Define qué países cuentan como "América Latina y el Caribe" y justifica tu lista.
- Filtra los laureados con
isin. ¿Cuántos son? ¿En qué categorías? - Crea un mapa coroplético limitado al continente (
scope='south america'o ajustando la geografía config.update_geos). - Crea una línea de tiempo de los premios de la región.
- Compara
birth_country_currentconorganization_countrypara los premios científicos. ¿Dónde investigaron? Escribe un párrafo sobre la migración de científicos. - Investiga (fuentes confiables) a una o un laureado de la región y agrega una ficha con su aporte.
Decisiones que debes tomar (y justificar)
- ¿Incluyes a quien nació en la región pero desarrolló su carrera en otro país (por ejemplo, Peter Medawar, nacido en Brasil)?
- ¿Qué conclusión no se puede sacar de que la región tenga pocos premios científicos?
Casos de prueba
- Tu filtro encuentra a García Márquez y a Santos.
- El mapa usa los códigos ISO de la columna
ISO.
10. 🏗️ Laboratorio de Datos Abiertos — Etapa 4
(Proyecto integrador creado para esta adaptación; etapas anteriores en los Días 76 a 78.)
Etapa 4 (hoy):
- Describe la distribución de tu variable principal:
describe(), histograma con variosbinsy una frase sobre su forma (¿simétrica?, ¿sesgada?, ¿con valores extremos?). - Compárala entre categorías con cajas y con
lmplot(conhueorow) si tienes una variable de tiempo. ¿Cuentan la misma historia? - Si tus datos tienen municipios o departamentos, crea un mapa coroplético (plotly acepta un archivo GeoJSON de los departamentos de Colombia con
geojson=yfeatureidkey=); si no, un sunburst con una jerarquía de tus datos. - Completa en
laboratorio.ipynbla tabla de la sección 7: qué representa cada fila, qué falta, qué mide cada columna.
Producto de la etapa: sección 5 de laboratorio.ipynb.
11. 🧩 Comprueba lo aprendido
Conceptuales
- ¿Por qué
birth_country_currentes mejor quebirth_countrypara un mapa? ¿Qué problema sigue teniendo? - ¿Qué diferencia hay entre contar laureados y contar premios?
- ¿Qué es un mapa coroplético y qué dato necesita para ubicar cada país?
- ¿Qué hace
lowess=True? ¿Qué paquete necesita? - ¿Cómo es posible que la caja y el
lmplotde Paz digan cosas "opuestas"?
Análisis de código
df_data.groupby(['birth_country_current', 'year']).size().groupby(level=0).cumsum()¿Qué calcula? ¿Qué forma tiene el índice del resultado?
Predicción
Si un premio de Física de un año se reparte entre 3 personas, ¿cuántas filas aparecen y cuánto vale share_pct en cada una? ¿Cuánto suma share_pct para ese premio?
Depuración
"Mi coroplético aparece completamente gris". Da dos causas posibles.
Modificación
Cambia el histograma de edades para mostrar una curva de densidad (kde=True) y separa por sexo con hue='sex'.
Creación
Escribe ranking(df, columna, n) que devuelva un gráfico de barras horizontales de plotly con los n valores más frecuentes de cualquier columna, ordenados de mayor a menor (arriba el mayor).
12. 🤖 Programar con apoyo de IA
Ciclo de trabajo: formula el problema → inténtalo tú → consulta a la IA → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.
Actividad 1 — Comprobar datos. Pregunta a una IA cuántas mujeres han ganado el Nobel hasta 2020 y quién es la persona más joven en ganarlo. Compara con los datos (58 y Malala Yousafzai) y con la página oficial de la Fundación Nobel (nobelprize.org). Si hay diferencias, ¿de dónde vienen (fechas de corte, organizaciones, premios repetidos)?
Actividad 2 — Revisar un gráfico. Pide a una IA el código de un mapa coroplético de los premios por país. ¿Usa códigos ISO? ¿Aclara que cuenta laureados por país de nacimiento? Compara con la documentación de plotly.express.choropleth.
Actividad 3 — Sesgo en las conclusiones. Muestra a una IA la tabla de mujeres por categoría y pídele una conclusión. ¿Confunde representación con capacidad? Reescribe la conclusión siguiendo la sección 7.
13. 🛠️ Correcciones técnicas al material original
| Archivo | Afirmación o comportamiento del curso | Observación | Tratamiento |
|---|---|---|---|
585–587 |
"Number of Prizes" en los gráficos | Cuentan laureados: 962 filas, 602 premios (verificado) | Nota técnica de la sección 2 |
589 |
La caja muestra "la media" | Muestra la mediana; showmeans=True agrega la media |
Nota técnica de la sección 6 |
589 |
regplot / lmplot con lowess=True |
Requiere statsmodels (RuntimeError sin él, verificado) |
Nota técnica de la sección 6 |
589 |
winning_age = año − año de nacimiento |
Aproximación: 55 de 934 quedan con 1 año de más (verificado) | Nota técnica de la sección 6 |
584 |
Actualizar plotly en Colab | Hoy normalmente innecesario; si se actualiza, reiniciar la sesión | Nota técnica de la sección 1 |
586 |
Color dogerblue en el reto |
Es dodgerblue |
Nota técnica de la sección 3 |
587 |
Francia supera a Alemania en Paz y Literatura | Cierto, y también en Economía (4 contra 1, verificado) | Sección 4 |
588 |
update_layout con títulos de ejes en el sunburst |
No tiene efecto (no hay ejes) | Nota técnica de la sección 5 |
585 |
6,2 % de mujeres | Sobre 934 personas; sobre 962 filas sería 6,0 % | Nota técnica de la sección 2 |
584 |
laureate_type distingue personas de organizaciones |
4 personas del premio de Paz están marcadas como Organization (verificado) |
Nota técnica de la sección 1 |
584 |
denomenator; "starburst chart"; "wards" (por wars); "Massachusets" |
Erratas: denominator, sunburst, wars, Massachusetts | — |
14. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| Testamento de Nobel, categorías, qué se aprende, cuaderno y CSV | 583 |
Sección 0 | Preparar el cuaderno | — | Sección 8 |
Actualizar plotly en Colab; exploración; duplicados; NaN y sus causas; to_datetime; share_pct |
584 |
Sección 1 | Retos 1–3 | Organizaciones; map |
Secciones 8 y 10 |
Formular preguntas; dona por sexo; primeras mujeres; repetidores; categorías con Aggrnyl; Economía; barras por sexo |
585 |
Sección 2 | Retos 1–7 | Mujeres por década; premios contra laureados | Secciones 8 y 9 |
Premios por año, media móvil, np.arange para marcas, dos ejes, invert_yaxis, guerras |
586 |
Sección 3 | Retos 1 y 2 | Anotaciones; reindex |
Sección 8 |
Columna de país, top 20, coroplético con ISO, barras por país y categoría, merge, acumulado con cumsum |
587 |
Sección 4 | Retos 1–4 | País de la organización; per cápita; animación | Secciones 8, 9 y 10 |
| Top instituciones, ciudades de investigación y de nacimiento, sunburst | 588 |
Sección 5 | Retos 1–4 | Sunburst por categoría; unificar ciudades | Secciones 8 y 10 |
winning_age, nlargest/nsmallest, describe, histplot, regplot con lowess, boxplot, lmplot con row y hue |
589 |
Secciones 6 y 7 | Retos 1–6 | Menores de 30; sexo; showmeans |
Secciones 8 y 10 |
| Resumen del día | 590 |
Sección 6 | — | — | Sección 8 |
| (No existe en el curso original) | — | Sección 7 | — | Una base de datos, varias historias | Secciones 8 y 10 |
| (No existe en el curso original) | — | — | — | América Latina en el Nobel | Sección 9 |
| (No existe en el curso original) | — | — | — | Laboratorio de Datos Abiertos, etapa 4 | Sección 10 |
15. 📦 Evidencias de aprendizaje del Día 79
- Tus 3 preguntas iniciales y el cuaderno con el análisis completo.
- Los 8 gráficos de la exposición, con sus conclusiones.
- El análisis de América Latina en el Nobel (proyecto extra).
- La etapa 4 del Laboratorio de Datos Abiertos.
- Cuaderno de errores:
to_numericcon fracciones,.dtsobre texto,dropnaque borra categorías enteras, laureados contra premios, denominador de los porcentajes, columna de país equivocada, coroplético sin ISO,columnsrenombradas por posición,lowesssin statsmodels, media contra mediana.