División aleatoria
Las muestras se reparten al azar. El mismo paciente acaba a ambos lados y las métricas salen infladas.
Todo lo que usamos procede de TCGA (The Cancer Genome Atlas), el consorcio genómico del National Cancer Institute y el National Human Genome Research Institute estadounidenses, en su categoría de acceso abierto.
Matriz de expresión RNA-Seq. 1.344 muestras tumorales y 336 de tejido sano, de cinco órganos.
La etiqueta de cada muestra. 320 pacientes aportaron tumor y sano; tejido de 121 centros distintos.
Traduce los identificadores anónimos a genes reales. 20.502 con símbolo oficial HGNC.
Los tres ficheros fueron renombrados y reempaquetados por el equipo: los enlaces llevan a la fuente pública, no al archivo con ese nombre.
1.680 muestras de cinco tejidos distintos. De cada uno hay tejido tumoral y tejido sano del mismo paciente — y esa pareja es lo que permite entrenar el primer modelo.
Todos los tumores son primarios (código 01 del barcode TCGA) y las muestras sanas son tejido adyacente del mismo paciente (código 11). El modelo no ha visto metástasis. La proporción tumor/sano es exactamente 80/20 en los cinco tejidos, por diseño de la extracción.
320 pacientes aportaron dos muestras: una tumoral y una sana. Si caen en lados distintos de la partición, el modelo reconoce al paciente, no al cáncer. Saca buena nota sin haber aprendido nada.
Las muestras se reparten al azar. El mismo paciente acaba a ambos lados y las métricas salen infladas.
GroupShuffleSplit para el hold-out y StratifiedGroupKFold para la validación cruzada: todas las muestras de una persona van juntas.
1.680 muestras RNA-Seq · 20.531 genes · acceso público
Selección de genes por ANOVA · partición por paciente · modelos versionados en joblib
Dataset y predicciones almacenadas
Predicción y explicabilidad en directo. Desplegada en Render.
Publicada en GitHub Pages.
El primero explora qué hay en los datos. El segundo decide qué genes importan y qué modelo usar.
expresion y metadatos: tumor o sano, y de qué cohorte.→ dataset_clean · gráficos y rutas listos para el notebook 02
→ modelos entrenados y versionados en joblib
Todo el proyecto está en el repositorio. Estos dos fragmentos son los que sostienen la validez de los resultados.
La partición que evita la trampa
Ningún paciente puede estar a los dos lados. Y lo comprobamos con un assert: si falla, el cuaderno se para.
# Validación cruzada agrupada por paciente cv = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=RANDOM_STATE) # Conjunto apartado, también por paciente gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=RANDOM_STATE) train_idx, test_idx = next(gss.split(X, binary_target, groups=groups)) assert set(groups[train_idx]).isdisjoint( set(groups[test_idx])) print("OK: sin pacientes compartidos")
El assert no es decorativo: es una comprobación que se ejecuta cada vez. Si algún paciente apareciera en ambos conjuntos, el análisis se detiene.
Todo dentro del pipeline
Escalado y selección de genes van dentro, no antes. Así se recalculan en cada partición y no se filtra información del test.
pipe = Pipeline([ ("var", VarianceThreshold(threshold=0.0)), ("scaler", StandardScaler()), ("select", SelectKBest(f_classif)), ("clf", LogisticRegression(max_iter=5000, class_weight="balanced")), ]) param_dist = { "select__k": [500, 1000, 1500, 2000, 3000], "clf__C": [0.01, 0.05, 0.1, 0.5, 1.0, 2.0], }
El class_weight balanced compensa el desbalance 80/20 sin tocar los datos, y los hiperparámetros se buscan con la misma validación agrupada.
El código completo, los cuadernos y los modelos entrenados están en GitHub